ドメインのWHOISやサイトの情報を調べることのできるサービスDomainWatchですが、7月半ばからシステムに問題が発生し、新規にドメインのWHOISを照会する機能を停止していました。
—
具体的に言うと、DomainWatchのデータベースはMySQL(MariaDB)を、全文検索にはMySQL用のストレージエンジンMroongaを採用していたのですが、件数が多すぎたせいでMroongaはキーのサイズが4GBまでという制限に引っかかってしまいました。
MySQLの上限に達してしまった
もう再構築するしかない pic.twitter.com/ZufuMpMo1v— Cheena (ちーな) (@cheenanet) 2019年7月17日
(MySQLの上限と書いていますが、Mroongaの制限が正しいですね)
そこでMroongaではもうあかんということになり、長らく検討していたElasticsearchへの移行を決めました。Elasticsearch自体は別のプロジェクト(非公開)で使用しており、ある程度ノウハウはありました。
Elasticsearchのアナライザー(データ格納時に指定した処理をなんかかんやしてくれるやつ)はこんな感じにしています。
{ "analysis": { "analyzer": { "whois_analyzer": { "type": "custom", "tokenizer": "icu_tokenizer", "filter": "ngram" } } } }
ICU TokenizerとN-gramを合わせるとハイブリッドでいいらしいです。
(8/20):検索精度が悪いため、結局N-gramはやめました
KuromojiなどではなくICUを選んだ理由としては、WHOIS情報は日本語だけでなく全言語の文字をサポートする必要があるためです。
MySQLのデータをElasticsearchに移行するにあたっては、Logstashを利用しました。
sudo yum install logstash
(Elasticsearchのリポジトリを追加する必要あり)
適当な .conf を作ります。
input { jdbc { jdbc_driver_library => "/usr/share/java/mysql-connector-java.jar" jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://localhost:3306/{database}" jdbc_user => "{username}" jdbc_password => "{password}" jdbc_paging_enabled => true jdbc_page_size => 100000 statement => "SELECT * FROM whois" } } output { elasticsearch { hosts => ["localhost:9200"] index => "whois" pipeline => "date_pipeline" } }
こんな感じで実行
/usr/share/logstash/bin/logstash -f mysql2elasticsearch.conf
データが400万件以上あるため、 jdbc_page_size を指定して10万行ごとに処理するようにしたところ、うまくいきました。 statement ではインポートするレコードを指定しています(テーブル whois の全レコード)。
また、MySQLでは日付文字列をDATETIMEの Y-m-d H:i:s 形式で格納していたため、これをElasticsearchの型 date_time_no_millis の yyyy-MM-dd’T’HH:mm:ssZZ 形式に直す必要がありました。これにはIngest機能を使い、Pipelineを作成しました。
{ "description" : "date pipeline", "processors" : [ { "gsub" : { "field": "created_at", "pattern": " ", "replacement": "T", "ignore_missing": true } }, { "gsub" : { "field": "updated_at", "pattern": " ", "replacement": "T", "ignore_missing": true } }, { "gsub" : { "field": "expires_at", "pattern": " ", "replacement": "T", "ignore_missing": true } }, { "gsub" : { "field": "added_at", "pattern": " ", "replacement": "T", "ignore_missing": true } } ] }
Elasticsearchへの格納時に日付フィールドの文字列に含まれる半角スペースをTに変換しているだけですね。
—
Elasticsearchに移行したことで、複雑なクエリも検索できるようになりました。
例: domain:*tokyo* AND domain:*2020*
新しくなったDomainWatchを今後もご活用ください。
お疲れ様
他のと違ってCAPTCHAがないのでサクッと調べられてありがたい。
デザインがすこ
2点、要望と質問があります
1. DomainWatchで、CIDR内に属するドメインを表示するよう、「検索機能」を改善してほしい。
例→ cidr:1.2.3.4/24 (この範囲内の全ドメイン)
2. 検索結果に「APIあります」という表示がありますが、domainwat.chはCloudflareをつかっており、TorやAPIを使うプログラム(curl/py)をブロックするのではないでしょうか?
「https://domainwat.ch/api/search?」がブロックされるとAPIの意味がない(使えない)のでは。
1のCIDR検索ができるようになれば、APIを使ってみようと思ってます。
1. 検索はドメインのWHOISしか有効になっていないので、別で作ることを検討します。
2. Tor経由のcURLだとブロックされる可能性はあります。
いつも使わせていただいてます。
一つ気になったのですが
https://domainwat.ch/whois/fmovies.to
のようにtoドメインを検索するとlast editedとexpiresがnoneになるのですが仕様でしょうか?
そのうち対応します。
Domainwatchのログ保存期間はどの程度でしょうか?