naoki86star

このインターネットの片隅で、バルスと唱えてみる

maxminddbのIPデータベースのカスタム作成

maxminddb ?

maxminddbはkeyをIPアドレスに特化しているデータベースといえばそうであり、だからまずはGeoLite2のような中身を詰め込んで*1あるdistributionにフォーカスがあたります。前から関連で見つかるこれを見て、IPに関連づいたlookupファイルを自作できそうと期待してました。tupleのcolumnを自分で定義して、つまり好きな項目をレコードにいれることができるのが心惹かれるところです。reference実装ってことで作成用のツールは今時点perlしかないようだってことで、perlでmmdbファイル作成を試してみます。
これは当初インストールにつまづいていたのを突破して自作DBファイルできたのでそれの覚書。

INSTALLファイルとかないなぁと思っていたら、ここにあったのを見つけた。

cpanm MaxMind::DB::Writer

これでさっくり入ってくれた。cpanmというのを入れるには

$ cpan App::cpanminus

でいいみたい。cpanmなんてあるのを知らなかった。*2

作成

exampleそのまま素直に付け足していって
最初のトライでの自分の先頭部は以下の感じ

use MaxMind::DB::Writer::Tree;

my %types = (
    desc => 'utf8_string',
    service => 'utf8_string',
);

my $tree = MaxMind::DB::Writer::Tree->new(
    ip_version            => 6,
    record_size           => 32,
    database_type         => 'My First Trial',
    languages             => ['jp'],
    description           => {jp => '最初のトライ' },
    map_key_type_callback => sub { $types{ $_[0] } },
);

ip_version : 6 でIPv4/IPv6同じファイルに入ってくれてる。元々は利便性のためのメタデータなんだろうけど本家?!GeoLite2は今IPv4/IPv6は一緒のファイルになってる。データの種類で分けてますよね(ASN,Country,City)
record_size : 最初40とか入れたら24/28/32のいずれしか許さないと返ってきた、ドキュメントには unsigned 16-bit integer.てあるが。
languages, descriptionを省略したら、newの時点でエラーになった。ドキュメントにはoptionalって表現があるけども。

$tree->insert_network()を呼び出すIPの順番とか特別気にする必要もない、と思いました。それでもファイル全体が大きくなる場合はツリーで近いものがまとまっている方がいいかもです。同一NWの場合サブネットマスク長の短いものから先に呼ばないと使うときの具合よくなかった。(6/18)

出来栄え

読む側は、いつものpythonのスクリプトにて。
サブネットを含めた総計16000件くらいのIPでファイルを作り、そのIPでシーケンシャル・逆シーケンシャル・ランダムアクセスで時間計ってみましたが、同じくらいの速さでアクセスできてるようです。以前、GeoLite2ファイルでアクセス速度計ったことあったのですが、それと遜色ない感じです。
ちなみにopen_database(..., mode=MODE_MMAP_EXT)で試しました。*3

import maxminddb
reader = maxminddb.open_database('output.mmdb', mode=maxminddb.MODE_MMAP_EXT)
obj = reader.get('59.10x.y.z')
print obj['desc'], obj['desc1']
補足

いわゆるプライベートアドレス(192.168.0.1とか172.31.250.0とか)を入れたらそれは入らなかったのでそういう仕様みたいです。

*1:それを定期的に更新してくれる!

*2:perlには20年前はさんざんお世話になりずいぶんと助けてもらいました。cpanコマンドまではよく使いましたが。

*3:mode=MODE_MMAP_EXTはmode=MODE_MMAPと比べると少なくとも10倍以上の実行時間の差が得られてます。MODE_MMAP_EXTというのはcのextension(*.soファイル)をpythonからロードしていて、ほとんどコード追ってないですがmapped-memoryを使っているだと思います。この手のパターンのお決まりで、ライブラリ使用中に*.mmdbファイル上書きするとアウトなのでロングタームで動かすプログラムではリロード機能つけてます。