ロングトランザクションとレプリケーションとPostgreSQL,MySQL

PostgreSQLMySQL(MariaDB)のレプリケーションはいろいろ違うが、ロングトランザクションでの挙動の差は興味深いわりにあまり言及されないので、さくっと書く。


MySQLレプリケーションはバイナリログベースである。動作は以下のとおり。

  1. トランザクションがcommitした時にバイナリログが書き込まれる
  2. それがマスターからスレーブに送信される
  3. 受信したバイナリログをスレーブがredoする


バイナリログはデータ更新をシリアライズして送信するようなものだから、どうしてもコミット完了後に送信せざるをえない*1

マスターがトランザクションを完了してからバイナリログが送信され、それをスレーブがredoするので、ロングトランザクションの場合はこんな処理シーケンスになる。

一方、PostgreSQLはWALデータを送信するわけだが、WALデータ送信タイミングは以下の通り:

  • トランザクションがcommitかabortしたとき
  • WAL writerが周期的(デフォルト200msec)に書き込んだ後
  • WAL bufferが溢れたとき

トランザクションがcommitする前であっても、WAL writerプロセスに書き込まれたWALデータが逐次送信されているし、大量に書き込まれてWALbufferが溢れれば200msec以内に送信される。

よって、ロングトランザクションの場合はこんな処理シーケンスになる。


ロングトランザクションの場合はMySQL/MariaDBでスレーブの遅れが顕著に現れるというお話。

*1:複数のトランザクションが並行して実行される場合を考えればよい。

pg_bman : Yet another backup tool for PostgreSQL

リモートサーバにデータをバックアップできるpg_rmanみたいなツールを作ってみた。

動機

pg_rmanはとてもよいツールだったのだが、PostgreSQLを置いたサーバにしかバックアップデータを保存できない*1。通常は別サーバにバックアップデータを置くので、実は今までpg_rmanの使いどころがなかった。

他にもPostgreSQLのバックアップツールはあるが、どれもデータの読み書きにssh+rsyncを使う。例えばpgbarmanなど。
問題はsshでパスワード入力しなくても済むように設定しなければならないことで、この為だけにPostgreSQLが稼働するサーバに無条件でloginできる状態を作らなければならないのは如何なものかと、常々思っていた。

アプローチと実装

PostgreSQL通信プロトコルだけでオンラインバックアップをするにはどうすればよいか、ネタフリに対して、花田さんはじめ皆様から有益な情報を頂き、特急で作ってみたのがpg_bman

Extensionはpg_read_binary_file()とpg_ls_dir()の制約を緩めただけ、SQLを発行する側のソフトはほぼテンプレの使い回し、操作ツールはbash。手抜きの極地。

結果

ネタフリ7月7日でGitHub公開7月9日。
大した作業もせずにpg_rmanとほぼ同様のバックアップ機能は実装できた(その後、2時間くらいでリストアも実装)。
少なくとも、個人的に使う分には充分な機能。


フィジビリティスタディなので、実装で気になった点を2つ。

byteaデータの送受信

pg_read_binary_read()は、内部で拾ってくるデータサイズ+VARHDRSZのメモリ領域をpallocで確保する。今回はWALセグメントを拾ってくるので16[Mbyte]を確保することになる。これ、640kの壁なんてものを意識しながらプログラミングを覚えた身としては、とても気になる。

	buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);


そもそも、byteaのデータを拾ってくる時には全部こうやってるのか?これから時間があるときに確認してみるつもりだけれども、通信ライブラリまわりって、まだ改良の余地が残ってそう。

リストア

どこでリストアするのかにも依存するけども、他のサーバ上でリストアするには結局sshftpなどが必要になるわけで、ことリストアに関してはlibpqに拘るのは無意味だということに、作り終わってから気づいた。ま、こんなモンですよね。

*1:pg_rmanは直でファイルシステムを読み書きするため。改造も容易でない。別サーバにバックアップを保存するには、NFSを使うくらいしか手がない。

再掲 並列アルゴリズム

5年くらい前に作ったマルチスレッドの分散アルゴリズム群を64bit対応にして再リリース。


ソースコードや使い方はこちらを参照

プログラムリスト:

  1. Queue
    1. "Bringing Practical LockFree Synchronization to 64Bit Applications" by Simon Doherty, Maurice Herlihy, Victor Luchangco, Mark Moir
    2. "Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms" by M. Michael and M. Scott
  2. List
    1. Coarse-Grained Synchronization Singly-linked List
    2. Fine-Grained Synchronization Singly-linked List
    3. Lazy Synchronization Singly-linked List
    4. "A Pragmatic Implementation of Non-Blocking Linked-Lists" by Timothy L. Harris
    5. "Lock-Free Linked Lists and Skip Lists" by Mikhail Fomitchev, Eric Ruppert
  3. SkipList
    1. A Simple Optimistic skip-list Algorithm" by Maurice Herlihy, Yossi Lev, Victor Luchangco, Nir Shavit
    2. "A Lock-Free concurrent skiplist with wait-free search" by Maurice Herlihy & Nir Shavit
  4. Hash
    1. (Chain) Hash Table
    2. Open-Addressed Hash Table
    3. Striped Hash Table
    4. Refinable Hash Table
    5. "Cuckoo Hashing" by R.Pagh, F.F.Rodler
    6. ConcurrentCuckooHash


すべてLinuxOSX上で動く。

クラッシュセーフなスレーブ

MySQLでslaveをクラッシュセーフ*1にするには、

  • MySQL 5.6以上
  • relay_log_recovery=ON
  • relay_log_info_repository=TABLE

というセッティングが必要。詳細は"こちら"、翻訳版は"こちら"


ざっくり言えば、リレーログのreplayと同じトランザクションで、InnoDBテーブルにリレーログの情報を書き込みcommitするので、大丈夫だよというお話。


MariaDBがこの機能に追従しないので、どうしたんだろうと思っていたら、MariaDBはGTIDのreplay状態などをgtid_slave_posというInnoDBテーブルに書き込むという技術的選択をしていた。もちろん、書き込むタイミングはreplayとおなじトランザクション
よって、MariaDB10.0以降は、GTIDを設定すればslaveがクラッシュセーフになる。MariaDBのGTIDはそこそこ完成しているので、こっちのほうが合理的な気がする*2

*1:スレーブがダウンしても、リレーログなどの情報が狂わないで再起動できる。

*2:MySQLのGTIDがまともになったら、同様の選択をするように思う。いつマトモになるかは知らないが。

PostgreSQLのリカバリ超入門

"JPUG勉強会の最終回"で「PostgreSQLリカバリ超入門」という話をした。


"SlideShare:PostgreSQLのリカバリ超入門"


WALとかCHECKPOINTとか、オンラインバックアップの原理について、可能な限り簡単に説明したつもり。


ネタ元の「内部構造:WAL」が分かりにくかった人は、上のPDFを眺めてからもう一度読んでいただくと、少しは分かりやすくなるかも*1


実運用について

PostgreSQLバックアップ運用の決定版はPostgreSQLバックアップ・リカバリ入門とか、そのうちアップされるであろう最新版の資料を見てください。

他の項目について

MVCCやVACUUMのパラパラ漫画のご要望が多ければ、作るかも・・・・

*1:ギリギリで書いたので、日本語として成立していない部分も多いので、理解が難しい部分は文章が悪いと思ってください。