MySQLユーザーのためのMySQLプロトコル入門 #4

なんとなく気分で始めたMySQLプロトコル入門ですが今回は少し趣向をかえてbinlog formatについて書いてみたいと思います。

MySQLでのレプリケーションのメッセージ単位として使われているbinlogですが、そもそもbinlog(バイナリーログ)とはどういったものなのでしょうか?実際問題よくわからなくてもちょちょっと設定すれば素敵に動いてくれるのでわからなくても大丈夫っちゃー、大丈夫なんですがせっかく興味が湧いてしまった事ですし調べていきましょう。

http://dev.mysql.com/doc/internals/en/replication-protocol.html より引用してみます。

Replication uses binlogs to ship changes done on the master to the slave and can be written to Binlog File and sent over the network as Binlog Network Stream.

ええっと、要するにレプリケーションという仕組みはbinlogというものを使ってmasterでの変更をslaveに伝えられるもので、Binlog Network Streamというものでnetwork上を流れるモノのようです。

ううん、なんだか分かるような、わからないような。ちょっとややこしいですね。
今日のところはひとまずBinlog Fileというものがどういったものなのかについて見て行きましょう。

Binlog File

http://dev.mysql.com/doc/internals/en/binlog-file.html
BinlogファイルはBinlog File Headerで始まり、Binlog Eventが連続したものである。と書かれています。

そのまんますぎますが、図で書いてみるとこんな感じでしょうか。
Screen Shot 2014-11-17 at 1.28.48 PM

Binlog File Headerとはどういうものか、というと
http://dev.mysql.com/doc/internals/en/binlog-file-header.html

0xfe, 0x62, 0x69, 0x6e (0xfe bin)の4byteから始まるファイルとかいてありますが単なるMagicですね。あまり重要ではないので次に進みましょう

Binlog Event Header

Binlog Eventが続いたもの……と書いてあるぐらいなのでここが一番重要なポイントっぽいですね。Binlog EventはMySQL Packetと同じようにHeader + Payload形式となっています。

http://dev.mysql.com/doc/internals/en/binlog-event-header.html から定義を引用します。

binlogのversionによって定義が分岐しますが、現状のMySQLではlog pos, flagsは必ずつくようになっています。今までのMySQLプロトコルをParseしていれば簡単にParse出来そうですね。

それでは早速Binlog Event Headerをparseするプログラムを書いてみましょう。

毎度の通り、PlayGroundで試せます。実行結果は下記の通りです。
http://play.golang.org/p/2QL3ZD7b29

Parse出来てそうですね!これで中身はともかく、Binlogが読み進められるようになりました。

Binlog Event Type

ひとまずBinlogのメッセージをParseできるようになりましたが、先ほどParseした0x0f(15)のEvent Typeとはなんだったのでしょうか?

全部のEventを解説していく結構な量になってしまうので
http://dev.mysql.com/doc/internals/en/binlog-event-type.html から私が興味有る部分だけ抜粋してみます。

と、これぐらいですかね。せっかくBinlogをparseするのですし自力でクエリが見れるようになりたいですよね(mysqlbinlogでqueryみれますが、まーそれはおいといて)。あとはFORMAT DESCRIPTION EVENTとROTATE EVENTぐらいがわかればとりあえず肝は分かりそうです。

それではFormat Description Eventを見ていきます

Format Description Event

http://dev.mysql.com/doc/internals/en/format-description-event.html Format Description Eventはbinlog version 4において最初のイベントで、binlog formatのバージョンや, binlogを作成したMySQL Serverのバージョン情報などが入っています。

細かい話は置いといて、まずはParseしてみましょう。

event type header lengthsの項目だけが解釈がしづらい上に解説が少ないですね。

こういった説明が少ないのはMySQLに限らずよくあるパターンなんですが、いくつか実際のバイナリを眺めていればなんとなく理解しやすいものです。

ざっくりと説明するとこの項目はuint8の配列で各種Event Headerの大きさを明記だけのものです(配列のOffsetはEventType - 1という仮定になっています)
例えば先ほどの0x0f format descriptionの大きさがどれくらいか、という場合はEvent Type - 1のOffsetを見れば大きさが書いてある、ということになります。

Binlog HeaderをParseするプログラムにFormat Description EventをParseする機能を追加してみましょう。

Format Description EventをParseすることで各イベントのサイズがわかるようになりました。
http://play.golang.org/p/m8cFKfsLIG

そいでは次すすみます。

Rotate Event

Replicationをしているとbinlogがrotationしていることに気がつくと思います。このRotate Eventでは主にbinlogのrotationを行う時にどうしたらよいか、ということが記されています。
http://dev.mysql.com/doc/internals/en/rotate-event.html から抜粋すると

binlog version 1は現状のversionではないので省いておきました。

uint64のpositionと次のbinlog fileの名前が入っているだけなのでparse簡単ですね。適当に書くとこんな感じでしょうか

実際Rotate EventはRotation以外の用途にも使われたりするのですが、現状はとりあえずParseしてみる事が目的なのでまた後日にでも解説しようと思います

Query Event

さぁ、ようやくおまちかねのQuery Eventです。
http://dev.mysql.com/doc/internals/en/query-event.html

ここらへんまでやってきた皆さんであればもうサクサクとParseできるはずです。決して解説が面倒になってきたわけではありませんヨ!?

一箇所status-varsの部分だけ分かりづらいので補足しておきます。
status-varsは連続したbyteで表したkey valueでkeyが1byte, value sizeはkeyによって事前に定義された長さを使います。

例えばstatus-varsのoffset 0が0x00の場合はKeyがQ_FLAGS2_CODEとなり、Valueの長さは4byteとなります。

まー、ぶっちゃけこれらのstatus-varsの情報は自前でReplicationをしようとかいった場合以外には不要な情報ですし実装するのが結構面倒だったりするのでスルーしておきましょう。

終わりに

Binlog FileのParseを通してEventについて学ぶことが出来ました。

実際はmysqlbinlogコマンドを使うだけで十分なんですが、ファイルフォーマットまで詳しくなっているとbinlogが壊れた時もバイナリを眺めればどこが悪いのか想像がつくようになるので覚えておいて損はないですね。

今日説明した内容のサンプルを ここ においておきますので興味がある人は書いてみて答え合わせしてみたりしてください。

そうそう、こういった新しい事とか知らない事についてやらない理由とかわからない理由こねくり回すのはそれはそれで楽しいんですが、ぼくたち創造的な開発者ですし、ごたごたいってねーでコード書こうって姿勢って大事だったりします。最初は難しいかもしれないけどちょっとトライしたら絶対できるから。
こういった事は「やるかやったか」(やるかやらないか、じゃないよ)なのでどんどん書いて引き出し増やしていきましょ。

そんなことはさておき、次回はBinlog Eventの中でもRow Based Replication部分に焦点を当てて解説して行きたいと思います。年末進行&私がAdvent Calendarに参加しすぎてしまい次の記事まで期間があいてしまうかもしれませんが、いましばらくお待ちいただければと思います。

Treasure Data Advent Calendarへのお誘い

今年はhttp://qiita.com/advent-calendar/2014/td というのを主催しておりますので、みなさんも是非是非ご参加いただければと思います。私もGREEで実際の現場で使われている中からちょろちょろと事例をご紹介できるように調整すすめています。

TD使い始めの方へのtipsや実際の事例などの共有ができれば幸いです。

それでは