2024.10.01
自社の社内情報を未来の“ゴミ”にしないための備え 「情報量が多すぎる」時代がもたらす課題とは?
リンクをコピー
記事をブックマーク
水戸部章生氏:(スライドを指して)こちらのバッチクライアント側からTiKVに、Raft側に処理を流して、Raftは受け取ったデータをそれぞれしっかりとコピーして整合性を保つとされていますが、本日はこのトランザクションについて紹介しようと思っています。
TiDBのトランザクションはもちろん、MVCC(MultiVersion Concurrency Control)で実現している分散型のデータベースです。このMVCCを実現するための技術キーポイント5つを紹介します。
先ほど名前が出ていましたが、1つ目がGoogle Percolatorと呼ばれる技術、2つ目がTimestamp Oracleです。3つ目はかなり前から提唱されているTwo Phase Commit、4つ目と5つ目はCompare And SwapとTime To Liveです。TiDBのトランザクションは、この5つで支えられています。
簡単なトランザクションの流れです。(スライドを指して)こちらは、私のPCで実際にやったものです。1つ目にMySQLと書いてありますが、TiDBです。先ほどMySQLのインターフェイスを持っていると紹介しましたが、このようなかたちで普通のBEGIN、select、updateと、同じコマンドが叩けます。
今回は、BEGINの後ろに楽観を意味するoptimisticをつけていますが、selectをしたあとupdateをして、commitする簡単なトランザクションの流れを実施しています。このトランザクションを実施すると、フィジカルの部分では実際にどのようなやり取りになっているかを、次のスライドに書いています。
(スライドを指して)左から右がトランザクションの流れです。まず、TiDBからstart_tsというかたちでBEGINを発行すると、Placement DriverからStart TSOと呼ばれるタイムスタンプを取得します。この取得が終わると、selectをする時にRaftを使っているので、どこにデータがあるかをPlacement Driverから取得します。
この取得が終わると、タイムスタンプを使ってスナップショットされたデータ、自分の位置がどこにあるかを確認した上でデータの読み込みが始まります。
本当はselectなどがありますが、updateしてデータを書き込むと、TiDBのメモリバッファ内にすべて書き込んだあと、バッチ処理するために必要なキーをまとめあげるなどして、次のcommitの処理に備えます。
次はcommitの処理です。先ほど1文でcommitと書きましたが、commitとしてはTwo Phase Commitを採用しています。分散型だと必須かと思いますが、最初にprewriteが発行されます。このprewrite時に、まずCAS(Compare And Swap)と呼ばれるメモリにスナップショットしたデータを配置します。そのあと、PercolatorによるSnapshot isolationとTTLを設定します。TTLを設定することによって、トランザクションが生きている間にTTLを延長します。トランザクションが消失した際にはTTLが無効になり、ほかのトランザクションが読み込みにいけるような設定になっています。
(スライドを指して)prewriteですが、すべてのキーに対してprewriteでロックを取得できると、次のcommitのフェーズに移れます。ただし、ロックを取得できないと、この時点でデータのロールバックが始まります。
無事にそれぞれのロックが取得できた際には、commitフェーズに移ります。commitフェーズは、さらにTSOタイムスタンプをPlacement Driverから取得し、取得したTSOを使って、それぞれのデータを書き込んでいきます。(スライドを指して)ここにCASによるデータのチェックと書いていますが、こちらは特に楽観処理の時に使います。のちほどスライドで詳しく紹介するので、ここでは割愛します。
最後にPrimaryKeyのロックの解除が終わるとcommitが完了し、クライアントに処理が戻るのが、一般的なTiDBのトランザクションの流れです。
本日は、詳細というより、全体の流れの中でどのような技術が使われてるかを紹介しようと思っています。(スライドを指して)少しわかりづらいと思うので、右上にトランザクション処理の中の、どの部分に位置するか書いています。この数字は最初にあったキー技術のどの番号かを意味しています。
1つ目はGoogle Percolatorによるスナップショット作成です。Google検索インデックスの更新に使用されるようなアーキテクチャーですが、TiDBの場合はこちらを使用しています。使用しているColumn Familyと呼ばれるそれぞれのcolumnを用意し、役割を持たせてスナップショットを取得するようなアーキテクチャーですが、TiKVではData、Lock、Writeの3つを使用しています。
(スライドを指して)こちらが、特定のキーのデータの持ち方です。まず、Keyと呼ばれる主となるキーがあります。Keyの次にDataとあります。のちほど紹介しますが、こちらのTSOというタイムスタンプで、それぞれData、Lock、Writeというかたちで1つのレコードを作っていきます。
今は$10というデータが存在していますが、この2つ目がcommitした際に出てくるデータです。commitすると5番目が今確定しているようなデータになっています。ほかのトランザクションがデータを読みにくる時には5番が確定しているので、10番を読み込みにいくような流れになります。
一番上がprewriteしている状態です。先ほどprewriteの際にはロックを取得する必要があると紹介しましたが、このロックの部分にprimary、もしくはほかのセカンダリであればprimaryのキー名を書いてロックを取得します。ロックがある時はまだprewriteが行われている状態で、それぞれのisolationレベルを分けてデータを持つような構造になっています。
この下で1つ特徴を挙げれば、CF_LockにTTLを入れるようになっています。このTTLものちほど紹介するので、ここではこのようなデータが入っていることを理解してもらえればと思います。また、CF_Writeのステータス情報も使って、ステータス情報の管理をしています。
2つ目はTSOです。commitの時に取得したTSO(Timestamp Oracle)はデータ不整合が起こるケースをすべてサポートするために、タイムスタンプを採用しています。先ほどGoogle Percolatorによるスナップショットと取得を紹介しましたが、スナップショットで不整合の起こるパターンのどこをサポートしているかと言うと、Dirty WriteやFuzzy Read、Lost Updateです。これらのケースに関してはサポートできています。
ただ、Write Skewと呼ばれるデータ不整合は、時系列で管理しないと発生してしまうので、これをサポートするためにTimestamp Oracleラインナブルの制御を入れています。
先ほどの基本的なトランザクションの処理にもありましたが、TiDBとPDでタイムスタンプを取得して、タイムスタンプにしたがって先ほどのスナップショットのレコードを作っていきます。Timestamp Oracleの番号は、Int64のシステム全体でユニーク値を必ず発行する仕組みになっています。
3つ目は、Two Phase Commitです。やはりGoogle Percolatorでは必須と思われるTwo Phase Commitも実装しています。先ほど紹介したとおり、例えば Bobが3ドル送り、Joeから9ドルにするという、BobからJoeに7ドル送るようなトランザクションがあった時、まずprewriteを実施します。(スライドを指して)こちらはprewriteの状態ですが、ノードが別々になっているので、ノード間でしっかりとデータの整合性を保つことが必要です。
まず、BobではTSO7(タイムスタンプ7を取得した)として、7ではデータ3を入れ込むとLockでprewrite状態です。Writeにはまだ何も書いていない状態です。Joeの状態に関しても9ドルを入れます。LockにはPrimary@Bob balと書いてありますが、Bobをprimaryとしたロックを取得し、7はない状態でprewriteが完了します。
ロックがすべて取得できれば、次のcommit処理にいきます。ロックがすでに1つでも取られている場合はロールバックというかたちになります。(スライドを指して)実際このcommit処理を行うと、次はどのような処理になるかがこちらの絵ですが、commitのTSOを再度取得して8番目のcommit処理に走ります。
prewriteが終わったあとには、commitがほぼ確定で走るようになっています。こちらに8、8とありますが、7が最新のデータとして、7番が記録されます。
(スライドを指して)こちらのJoeのところにもTSO7が最新のデータとして書き込まれ、この下のTSO7のPrimary Lockが消えるようになっています。primaryのLockだけ最初に削除して、Lockが終わるとTiDBはcommit処理が終わったとして返します。後ろに関しては、のちほど処理をするような流れです。
4つ目は、スナップショットのCAS(Compare And Swap)という機能です。スナップショットを取る際のデータをCASと呼ばれるOSの命令に入れるようになっています。(スライドを指して)こちらではkey=Bob, Data=5となっていますが、スナップショットを取った段階では同じデータです。基本的には、TiDBのデータ自体はオンメモリ上で更新します。
メモリ上で更新すると、トランザクション1とトランザクション2のどちらが更新したかがわからなくなります。その際に、CASの中でデータを入れ込みます。CASはマルチスレッド対応であり、一度データを書き込むと、次に書き込もうとしたトランザクションにエラーを返すような仕組みになっています。
先にデータがcommitされていると、次にデータが来た時、すでにそのデータは書き込まれている状態になります。楽観Lockでデータを持ってきても、ほかのトランザクションがすでにcommit処理していることに気づけるので、その時点でロールバックします。TiDBの場合はリトライ1になっているので、楽観Lockならもう一度commit処理(データのやり直し)をするのがCASの機能です。
5つ目は、TTLによるトランザクション制御です。トランザクションがTTLを確認して、ノードダウン時などに検知する仕組みです。先ほど紹介したPercolatorのロックのところに入っているTTLですが、heartbeatでTTLのexpireを伸ばす処理をします。このexpireが切れると、すでにLockがなくなっていると判断し、ほかのトランザクションがデータを更新できるような仕組みになっています。
(次回につづく)
関連タグ:
2024.10.29
5〜10万円の低単価案件の受注をやめたら労働生産性が劇的に向上 相見積もり案件には提案書を出さないことで見えた“意外な効果”
2024.10.24
パワポ資料の「手戻り」が多すぎる問題の解消法 資料作成のプロが語る、修正の無限ループから抜け出す4つのコツ
2024.10.28
スキル重視の採用を続けた結果、早期離職が増え社員が1人に… 下半期の退職者ゼロを達成した「関係の質」向上の取り組み
2024.10.22
気づかぬうちに評価を下げる「ダメな口癖」3選 デキる人はやっている、上司の指摘に対する上手な返し方
2024.10.24
リスクを取らない人が多い日本は、むしろ稼ぐチャンス? 日本のGDP4位転落の今、個人に必要なマインドとは
2024.10.23
「初任給40万円時代」が、比較的早いうちにやってくる? これから淘汰される会社・生き残る会社の分かれ目
2024.10.23
「どうしてもあなたから買いたい」と言われる営業になるには 『無敗営業』著者が教える、納得感を高める商談の進め方
2024.10.28
“力を抜くこと”がリーダーにとって重要な理由 「人間の達人」タモリさんから学んだ自然体の大切さ
2024.10.29
「テスラの何がすごいのか」がわからない学生たち 起業率2年連続日本一の大学で「Appleのフレームワーク」を教えるわけ
2024.10.30
職場にいる「困った部下」への対処法 上司・部下間で生まれる“常識のズレ”を解消するには