AsakusaとOLTP(RDB)とバッチ処理 

Asakusa Advend Calnderの最終として

現状

 

2018/12月の現在の自分のタスクは、DBのMVCCでのTX制御の理論・アルゴリズムの設計になっている。要するにDBを作りましょうということで、そのコア部分をどうにかしなさい、ということになっている。それで、その前提として、今回のDB-Prjでの最大の眼目の一つを「Writeの強いRDB(OLTP)」ということにしている。

 

現在のRDBはそもそも原理的かつそのツールとしての特性上WriteというよりもReadにパフォーマンスが振られている。結果として、一般に、書き込みヘビーの業務系大型バッチ処理RDBでまぁほぼ全敗になる。これは常識のまま、そろそろ30年くらいになるし、この辺が改善する見込みはほぼない。ということで、大規模(といってもさすがに最近のトレンドの規模感からはそう簡単には大規模とは言いがたいが)で複雑な一貫性を担保する書き込み、という意味では、まぁあまりよいアイデアはない。

 

一方、自分らの飯のタネの一つは、複雑な業務系のバッチ処理の分散高速化で、これは基本的にデータはRDBにあるのが普通だ。それをクラスター/またはメニーコア+大容量メモリーサーバに展開しつつ、分散処理で高速に処理して戻します、というのが基本戦術だ。現状のAsakusaはこういう用途で使う。

 

当たり前だが、RDBから抜く時間・戻す時間は無駄だし、バッチ処理は可能であればDB上で実行し、かつオンライン処理を止めずにバッチも動かしたい、というのが普通の発想だ。要するにDB上で複雑な結合処理をしながらドカドカ書き込めて、かつ普通にクエリーもストレスなく動いてほしいは、これはまぁ、別に特別でもなんでもない要請だ。普通に見れば「今時そんなこともできないのか?」ということになる。いいわけとしては「すべての用途に秀でた技術はありません」というのが、ありがちな言い訳になる。

 

で、そうも言ってられないので、いろいろやってみるか、という話になっていて、それで上記の通り、まずは「Writeの強いRDB(OLTP)」を、いくら待っても出てくるどころか、最近ではむしろDBの選択の余地がどんどん減っている状況なので、まぁ作ってみましょうか。とこういう風になっている。

 

ということで以下、仮にAsakusaをOLTPで動かす、ということを考えるのであれば、考慮しなくてはいけない点を、順にいろいろ書いておく。

 

えっと以下一応、Isolationレベルはすべてserializableを前提に書く。(なお、個人的にはRCレベルの話であれば特段DBを使う必要はなく、その辺のFSをちょっと工夫すれば実現できるので、それはDBとは思っていません。悪しからず。)

 

前提としてのSILO

SILOの登場以降、DBの世界はほぼ劇的に変わった。SILO以前・以降ではdatabaseというものはほぼ別物だと考えてよい。one-shot request / group commit / OCC(read lock free) / validation-phase / epoch basedはどのDBでも、その在り方・解釈はさまざまであるが、どれも踏襲している。今のところ、自分の観測範囲では、ただの一つも例外はない。この構成要素を持ったうえで、メニーコア・大容量メモリーで動かすというのが現在のDBのスタンダードだ。

 よって、今後のWriteの強いDB(+バッチ処理)を考える場合には、まずもってSILOを前提にする必要がある。

 

SILOベースでの課題

ということで、SILOでWriteの強化+バッチ、ということになるのだが、これはまともに行くと絶望的にきつい。実装云々以前に、まずもって基本的な枠組みが、風向き的にアゲインスト。秒速40mクラス。雪山稜線であればシカどころか寝ぼけた熊まで飛ばされるクラス。普通に敗退。

 

Write lock

まず通常のOCC実装は1Vになる。よって普通にwrite lockをとる。このため、いろいろ書き込みが競合しだすとまず基本的にスローダウンか、abort祭りになる。in-place前提で、write-heavyであれば、これは実装とか理論以前の話として、普通に誰でも想像できる通りで、そして想像通りの結果になる。たしかにSILO/OCCは新しいアーキテクチャを存分に生かしたものではあるが、write特性については1Vである限りlockを取らざるを得ず、その意味では既存DB路線を踏襲している。ベースアルゴリズムCSRという点もある。んで、んじゃーそのabort祭りをどうするか?ってので、可能な限り超効率的に物理で殴るという方針をとったのが、SILO-OCC-1Vだったりする。そんな感じだ。

 

SILO-OCC-1Vは、abort&retry勝負はショートレンジの処理であれば、まだ勝ち目はあるが、ロングバッチでは話にならない。まずはserializable云々の前に、とにもかくにも「書き込めます」という状態を確保しないと、そもそも土俵に上がれない。 なので、まずもって「最低限の前提」としてMV化していく必要がある。

 

MVであれば、とにもかくにもinstallはできる。よって、この場合、大事なのは「MV」である、ということではなくて、「write lockを取らない」ということが肝要になる。installそれ自体はロックされては手も足も出ないからだ。

 

なお、この目線で見た場合、SILO前提での昨今の“MVCC”-RDBでは、実は役に立たない。基本的にwrite lockをとる手法を採用している。結局は1Vチックな仕組みが主流であり、一応MVを称しているが、形だけmulti-versionといったところが否めない。・・・write lockをとる段階で、本当の意味でのMVCCではなく、単にversionがmultiなだけのDBに過ぎない。単純なw-wをconflictとしないところがMVの最大のメリットだ。その意味ではMVCCと称しながらwrite lockをとる実装は文字通り羊頭狗肉だと思っている。

 

ということで、MVを前提にして、かつ、可能な限りwrite-lockをとらない原理・実装を選択する必要がある。要するに「read lock free / write lock free」の実現だ。なんかちょっとSFチックな話にすら聞こえかねないが、ただ、これは「ちゃんとした」理論の枠組みと実装方針があれば、多少は勝算はあるとは思っている。

 

以上は、まずはSILOの枠組みの中の問題になる。すなわちepochな時空間での考え方が基本になっている。

 

epochベースでのserialization orderの「延長」

次のハードルがこれ。これもかなりキツイ。大体20msecがepochだとして、5minバッチだと、15000epoch。まぁこんなdurationで処理が継続するとはSILOは想定しない。物理GCクラスでの単位になる。epoch跨ぎをどうするか、それも複数跨ぎになるが、というのはちょっと問題としては大きい。これは既存のSILOの枠組みを超えるものになる。

 端的に言えば、epochをまたぐバッチ処理中のread/writeとepochの中に閉じているtxとの整合性をどうするか?という問題にある。普通に考えれば問題は山積。

 

-read

上書きの処理。普通にロングバッチ処理中に読んだ値が、どんどんconcurrentに更新される。しかもこっちはepoch跨ぎなので、バッチ処理より先にcommitされる。同一epoch内であれば、deferred commitの手法を利用することでいくらでも処理可能だが、epochを越えるとなると、over-writeのtxのserialization orderを後ろに持ってくることはできないので、簡単に詰む。よって違う枠組みを導入しないと無理。

 

-write

バッチの処理中でのwriteを読んだconcurentなtxが先コミットになる。read-fromの要請、すなわちHerbrand semanticsの維持が面倒。定義の”occurs before”をどう解釈するか、という話もあるが、commit orderで逆順であれば、さすがに打つ手がない。これもepoch内部であれば、普通にdeferred commitで処理できる話ではあるが、読んだtxの方がserialization orderが前にくることが強制になるので、これも詰む。

 

read/writeの両者で手が詰む。

 現在のところのアイデアとしては、readについては従来と違う枠組みを考える必要がある、一応ベースになるアイデアはあるので検討中。writeについては要はcommit orderが整合できないtxには読ませない、というプロトコルで対応する。ということでいろいろ検討中というのが目下の状況。まぁ普通に苦戦してる。

 

いずれにしてもSILO-OCCのようなシンプルに物理で殴るという方法ではなく、ある程度テクニカルな仕組みを理論的な枠組みから構築していくという方向になる。

 

必要な枠組みとしての検討事項

 

要するにAsakusa以前に、そもそもバッチ的処理をRDB(OLTP)で行う、ということのハードルが高く、そのための準備がかなり前人未到系になっているという感じだ。けだし、これは従来のRDBでも同じ問題はあって、MVCCよりも制約が強い既存の1VベースRDBではほぼ絶望的だと思う。(SQLをちゃんと書けばパフォーマンスが上がるので十分だ、それほど既存のSQLバッチは中身が悪いので遅い、という話もよく聞くが、consistent / concurrent / write heavyなバッチ処理は実装以前の話として、理論的な枠組みからして無理だろうな、というのが今の実感。)

 

今後の検討課題は以下

-serialzation空間としてはMVSRを前提にする。

個人的にはMVSRを目標とする。まともに行くとNP-完全なので、どういう制約をうまく利用するか?になると思う。時代の流れもこちらを向いている。真っ向勝負。

 

-read protocol / write protocol / commit protocol

基本3層protocolの構成をベースに検討。

特にread protocolは現在のところほぼ、read most recently程度の理論・実装しかない。これを整備して行く。もっともwrite protocolですらおそらくappend onlyが関の山なので、こちらも普通にいろいろ検討する必要がある。大抵の枠組みはcommit protocolだけなので、それではもうダメです。

 

-commit protocolの拡張

基本方針としては、deferred commitを利用する方針で、その拡張を行う。install-based orderとcommit-based orderは明確に分ける。epoch跨ぎを考えるので、concurrentな中にalready committedなものが発生するということになる。従来のコンセプトでは commit / to be committedのみだと思う。

 

-実装物理レイヤー

これは弊社および某Prjの超絶優秀なエンジニア諸氏にまずはお任せするしかないので、初手から「一番いいやつを頼む」としか言えない。てか、線形リストはもうダメな気がする。すんません、実装とか全部入りで最初から考えてたら、とても精神がもたないので、まじで勘弁してください。

 

その上で

以上が揃った上で初めて、AsakusaをOLTP上で動かす、ということを検討する、という段になる。

いやー、なかなか遠大な道のりだが、そんなもんだ。見ようによっては「たかだか、RDBでちゃんとバッチ動かします」ぐらいの話でしかないのだが。その上でのAskausaの話だ。

 

Asakusaは現在のところ、できてほぼ10年近くになるが、いまだに「業務系の複雑な処理を、SIを前提にして、分散処理環境で効率的に設計・実装・実行するフレーワーク」はAsakusa以外に存在しない。その意味では存在意義はあると思っている。実績・完成度もある上にOSSなので、これから別の商用プロダクトができるとは思えない。今後10年もその意義は続くだろう。なので、検討すべき価値が十分にあると個人的には思っている。その意味ではかなり迂遠は道のりであるが、そのOLTPの上でのバッチ処理→Asakusaの検討はありうると思っている。

 

仮に検討するので、あれば、上記のOLTPを前提として・・・

 

-I/O周りの再整理

このレベルになったら Wind gate / Thunder gateとかいうより なんかもっといろいろ別物になるくらいの勢いになると思う。Tx制御はもちろん、なんやらいろいろ。あとは、特にtest周りとかどーすんか?とか思うけど。どうすんだろ。初手から「一番いいやつを頼む」としか言えない。いろいろありすぎてちょっとなんとも。

 

-DSLの拡張

既存の枠組みではできなかったことも低コストでできるようになる「はず」なので、その辺の検討か。型・DAGあたりはまぁ基本だとして、それ以外で、という感じか。やり残りもあるので、その辺り含めてか。

 

-SQLとの「いろんな意味での再整理」

当然SQL処理との兼ね合いはどうするか?という話はいくらでも出てくる。そもそもストプロとはなんなのか?というところの議論からスタートか。

 

とかいろいろあるとは思う。ま、そんな感じ。いずれにしても 汎用機のバッチ無理→オープン化→RDBのバッチ遅い→Hadoop/Spark/M3BPの分散処理、というところからきてとうとう「やっぱ既存のDBだと無理から、一からつくるわ」ということになるとは、まさか思わなかった。

 

そんな感じ