IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

MySQLのXmasはXprotocolで決まり

昨日(12/24)は、協会のミサに行ってきました。牧師の説教はSNS批判でした。その話を私なりに解釈すると、「SNSで批判するときは、相手がリアルに目の前にいてもその発言ができるか、その覚悟を持った上でSNSを使え」と伝えているように感じました*1。あと、かなり蛇足ですが、聖餐を牧師が落としたのですが、すかさず拾って自分で食べて、何事もなかったようにしていたのを目撃しました*2

X

MySQL Casual Advent Calendar 2017は、開始されてから早い時期に24枠がすぐにうまってしまいました。1,2週間ほど最後の1枠が埋まっていませんでした。様子見していたのですが、Xに引っ掛けたネタを持っていたことを思い出し、誠悦ながら参加させていただくことにしました。

さて、「Xmasですね。MySQLのXと言えば、、、」と勿体ぶったタイトルにしていますが、MySQLXと言えばXProtocolです。

XProtocol

MySQLにはXProtocolと呼ばれるクライアントサーバ間の通信規約があります。

MySQL :: MySQL Internals Manual :: 15 X Protocol

そしてXProtocolを実装したXDevAPIが用意されています。ユーザはXDevAPIを使ってデータベースアクセスのプログラミングを行います。XProtocol / XDevAPIの特徴として、ドキュメントストアに対応していることが強調されることが多いです。例えば、次の資料があります。

https://www.db-tech-showcase.com/wp-content/dbts_museum/MySQL/MySQLDocStore_jp.pdf

検索すれば他にもたくさん情報が出てきます。しかし、XProtocolの仕様をよくよく読み込んでみると、ドキュメントストア処理以外にも、面白い仕様があるので紹介させてください。

Pipelining

Pipelineという機能です。

ざっくり言えば、クライアントの要求を、サーバからの応答を待たずに、どんどん送って処理をするという機能です。下の資料のPipeliningの節にシーケンスがあります。

MySQL :: MySQL Internals Manual :: 15.8 Implementation Notes

仕様上は、Expectationsという機構を使ってクライアントの要求を作ります。

MySQL :: MySQL Internals Manual :: 15.4 Expectations

例(エラーなし)

次のような5つのinsertを実行することを考えます。*3

insert into test_users values (1, 'mike'  , 'mike@example.com'  ,  45) --sql1
insert into test_users values (2, 'nancy' , 'nancy@example.com' , 115) --sql2
insert into test_users values (3, 'steve' , 'steve@example.com' , 298) --sql3
insert into test_users values (4, 'james' , 'steve@example.com' , 444) --sql4
insert into test_users values (5, 'jhon'  , 'steve@example.com' , 555) --sql5

通常は、

クライアントがsqlNをサーバに送信し、クライアントはサーバからの結果を待ち、サーバから結果を受信し、クライアントは結果が正常であることを確認、を5回繰り返(N=1..5)します。

Pipelineを使うと

クライアントがsql1からsql5をサーバに送信し、クライアントはサーバからの結果を待ち、サーバからsql1からsql5の結果を受信し、クライアントは結果に基づいて後続処理を行う

となります。

待ち時間を考慮するとPipelineのほうが全体の実行時間が短くなることが期待できます*4

例(エラーあり)

では、クライアントからまとめて送信したデータの中にエラーがある場合はどうでしょうか。

insert into test_users  values (1, 'mike'  , 'mike@example.com'  ,  45) --sql1
insert into test_users  values (2, 'nancy' , 'nancy@example.com' , 115) --sql2
insert into test_users_ values (3, 'steve' , 'steve@example.com' , 298) --sql3 テーブル名が不正
insert into test_users  values (4, 'james' , 'steve@example.com' , 444) --sql4
insert into test_users  values (5, 'jhon'  , 'steve@example.com' , 555) --sql5

サーバ側の挙動は、クライアントでの指定により異なります。sql3で失敗した場合

  • no_error指定があれば、sql4,sql5は実行されない
  • なにも指定がなければ(または上記no_errorを打ち消す指定をすれば)、sql4,sql5は実行

となります。

no_errorの指定は、対象となるsql実行範囲の前後に、opencloseのメッセージをつけ、openメッセージのcondition属性にno_errorをもつConditinoメッセージを指定します((設定が面倒ですが、openのメッセージ構造はpipeline以外の機能も指定できる仕組みになっています))。

要求メッセージのイメージは下記になります。

open{condition = Condition {condition_key = no_error}}
insert1
insert2
insert3 (不正なクエリ)
insert4
insert5
close{}

実行例

さて、実行結果を確認しましょう。Wiresharkでパケットを確認します*5

なにも指定しない場合

f:id:naotoogawa:20171223162452p:plain

  • No.1からNo.6はコネクション確立のメッセージのやりとりです。
  • No.7からNo.11はクライアントが要求するクエリのメッセージです。
  • No.12からNo.16はサーバの応答です。
    • No.14のみエラーとなり、後続のSQLは実行されています。

Pipelineのno_error指定をした場合

f:id:naotoogawa:20171223162510p:plain

  • No.1からNo.6はコネクション確立のメッセージのやりとりです。
  • No.7からNo.14は基本的にクライアントが要求するクエリのメッセージです。
    • No.7がPipelineの開始指定で、No.14がPipelineの終了指定になります。
    • 途中No.10のOKメッセージがあります。これは、Pipeline開始に対応するサーバの応答になります。
  • No.15からNo.20はサーバの応答です。
    • No.17の不正なクエリのエラーが応答されています。
    • No.18からNo.20のエラーはPipelineとしてのエラーになります。
    • 特に、4番目、5番目のクエリに対応するNo.19、No.20はクエリ自体はサーバでは実行されません。

以下にPipeline処理にて特有のメッセージ内容を個別に確認しましょう。

no_errorメッセージ(上記のNo.7)

f:id:naotoogawa:20171223162527p:plain

クエリエラーのメッセージ(上記のNo.17)

f:id:naotoogawa:20171223162545p:plain

Piplineエラーのメッセージ(上記のNo.20、(No.18,No.19も同様です。))

f:id:naotoogawa:20171223162557p:plain

まとめ

メッセージの内容を確認しながらPipelineの基本的な挙動を見てきました。考え方自体はシンプルで、応答を待たずに要求を送り応答を受け取る仕組みです。失敗時の挙動を制御できます。例えば、失敗したら後続は実行しない。

最後に2点追加コメントになります。

ちょっとどのようなユースケースがあるかわかりませんが、仕様を読むとPipelineの単位はネストできるようです。

Pipeline自体は、トランザクションとは独立しています。トランザクションを開始した上で、Pipeline処理を行い、rollbackすれば、ロールバックされます。(当たり前のことを言っていますね。)

*1:あくまで私の解釈です。牧師は丁寧に説教してくださいました。ちゃんとメモっとけばよかったなと少し後悔。

*2:人間ができていないので、つい余計なことを言ってしまいます。

*3:実際には1つのinsertで間に合いますが、説明のために5つのinsertがあるとします。

*4:環境によるので必ず短縮されるわけではないです

*5:12/25現在XProtocolのWiresharkプラグインを作成しており、現在テスト中です。2018年初には公開をしたいと考えております。