MySQL binlog API は row based mode でこそ、その真価を発揮する!!
空前の MySQL binlog API ブームですが、みなさん libreplication の examples/basic-[12] を実行するだけで満足してしまっているようです。しかし、libreplication のおもしろいのは examples/mysql2lucene の方なんです。
3つのロギングモード
普段はあまり意識しないかもしれないですが mysql の binlog には statement based, row based, mixed の3種類があります。
statement based は、実際に実行された SQL が記録されます。一部の関数でちょっと危険です。
row based では、実際に変更された行のデータが記録されます。
mixed では、危険な関数をつかった場合などには row based で記録し、そうでなければ statement based で記録します。最近はこれがデフォルトです。
詳細は http://thinkit.co.jp/article/95/1?page=0,2 このへんなどをご欄ください。
ロギングモードを row based にしよう
SET GLOBAL binlog_format = 'ROW';
とかやると、binlog_format が row based に変更されます。
この状態で binlog API をたたくと、TABLE_MAP_EVENT, WRITE_ROWS_EVENT, UPDATE_ROWS_EVENT, DELETE_ROWS_EVENT の4種類のイベントがおくられてくるようになります。
行データが一緒におくられてくるので、それをつかって手元のデータをアップデートすればいいのです。SQL statement を解析したりする必要はありません。
実際に MySQL::BinLog でためしてみる
以下のようなプログラムで簡単に行のデータをとれます。
use 5.016000; use MySQL::BinLog; my %table_map; my $url = shift or pod2usage; my $binlog = MySQL::BinLog->new(MySQL::BinLog::create_transport($url)); $binlog->connect(); $binlog->set_position(4); say("connected: $binlog"); while (my $event = $binlog->wait_for_next_event()) { my $type = $event->get_event_type(); if ($type eq TABLE_MAP_EVENT) { $table_map{$event->table_id} = $event; } elsif ($type ~~ [WRITE_ROWS_EVENT, UPDATE_ROWS_EVENT, DELETE_ROWS_EVENT]) { my $table_event = $table_map{$event->table_id} or die "Unknown table: " . $event->table_id; my $rows = MySQL::BinLog::Row_event_set->new($event, $table_event); my $iter = $rows->begin(); while (my $row = $iter->next()) { if ($type eq WRITE_ROWS_EVENT) { say("INSERT"); show_row($row); } elsif ($type eq UPDATE_ROWS_EVENT) { say("UPDATE BEFORE"); show_row($row); say("UPDATE AFTER"); show_row($iter->next()); } elsif ($type eq DELETE_ROWS_EVENT) { say("DELETE"); show_row($row); } } } } sub show_row { my $row = shift; my $fields_iter = $row->begin; while (my $field = $fields_iter->next) { printf(" TYPE: %-10s STR: %s\n", $field->type_str, $field->as_string); } }
この状態で以下のような SQL を発行します。
INSERT INTO hoi (id, name) values (1, "HOGEHOGE"); UPDATE hoi SET name="FUGAFUGA" WHERE id=1; DELETE FROM hoi WHERE id=1;
すると、以下のような結果がえられます。
INSERT TYPE: LONG STR: 1 TYPE: VARCHAR STR: HOGEHOGE TYPE: TIMESTAMP STR: 1341954455 UPDATE BEFORE TYPE: LONG STR: 1 TYPE: VARCHAR STR: HOGEHOGE TYPE: TIMESTAMP STR: 1341954455 UPDATE AFTER TYPE: LONG STR: 1 TYPE: VARCHAR STR: FUGAFUGA TYPE: TIMESTAMP STR: 1341954455 DELETE TYPE: LONG STR: 1 TYPE: VARCHAR STR: FUGAFUGA TYPE: TIMESTAMP STR: 1341954455
まとめ
row based で binlog を記録することにより、行のデータを簡単に取得できます。
binlog API をつかうことで lucene, solr, groonga, rast などの全文検索エンジンにデータをうつすことが容易にできます。通常 solr を運用する場合は minutely で SELECT かけてデータをうつしたりすることが多いとおもいますが、binlog API をつかえばリアルタイムにデータをコピーできます。
mroonga のようなアプローチもありますが、こういうアプローチも面白いのではないでしょうか。mysql storage engine にくらべ制約がすくなく、開発期間も格段に短縮できそうですね。
このような、任意のストレージに replication できるというのが binlog API の主目的だとおもいますが、その他にもデータのモニタリングやらなんやら、アイディアはいろいろ考えられるのではないでしょうか。
エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド
- 作者: 奥野幹也
- 出版社/メーカー: 技術評論社
- 発売日: 2010/06/12
- メディア: 大型本
- 購入: 12人 クリック: 181回
- この商品を含むブログ (24件) を見る