Skip to content

Instantly share code, notes, and snippets.

@umegaya
Last active August 29, 2015 14:17
Show Gist options
  • Save umegaya/13a38ae871009901c5d7 to your computer and use it in GitHub Desktop.
Save umegaya/13a38ae871009901c5d7 to your computer and use it in GitHub Desktop.
cockroach source code reading

========== cockroachの分散トランザクション

  • server(server.go) : リクエストを受け取り、rangeから探した処理先に送信する。
  • node(node.go) : serverが受け取ったリクエストをraft的に複数ノードにレプリケートする。
  • たぶん、server => node という流れで処理されるのだろう。

処理の階層構造

  • server
  • client.DB => TxnCoordSender => DistSender
  • txnをつくる => txnのタイムスタンプやstateを管理する => rangeから送信先を決定して送信
  • node
  • clietn.DB => TxnCoordSender => LocalSender
  • txnをつくる => txnのタイプスタンプやstateを管理する => ローカルのノードからコマンドのraftログへの書き込みを行う
  • なぜどちらもTxnCoordSenderでラップされているのか? => 必要に応じてどちらも分散txnができるようにしているのではないか?

TxnCoordSender

  • 呼び出し時にtxnを作るが、保存まではしない。保存はどこかでしているが、どこでやっているかは謎
  • txnは呼び出し側のメモリ上のmapに保持され、定期的なheartbeatで何かをしている。何をしている?
  1. 長い時間更新されてないtxnは削除
  2. 更新が続いている場合、そのtxnをキーに対応したノードのstorageに書き込む
  3. その後、heartbeatを受け取る側はそれのtsをみてtimestampをアップデートする
  4. 結果として更新されたtxnを呼び出し側に返す。abort/commitになればheartbeatは終わり
  • rangeにたいする操作を受けた側は、操作を行った側(TxnCoordSender)にtxnを返している
  • txnの状態および、エラーをみてtxnをコミットするかどうか決めている

EndTransaction

  • どうもputごとにraft logに書いて...をやっているわけではないらしい。TxnCoordSenderにコマンドをためてまとめて全部投げている。全transactionを一個のlogにするようなイメージかもしれない。
  • よくみたら1つ1つやっていた。
  • linearizability / serialized snapshot isolationの違いはタイムスタンプの違いをどのように許容するか、だけらしい。
  • 分散transactionで使われるTransaction recordとmvccのトランザクショナルナ更新は別なので注意 transaction recordをcommit => mvccのトランザクショナルナ更新となっている。

protocols

  • InternalPushTxn => 複数のtxnが競合した時に、可能であれば後のtxnで前のtxnを上書きする。あるいはgc的に途中で止まったtxnを終了させるなど
  • EndTransaction => txnの終了
  • InternalHeartbeatTxn => coordinatorが自分のtxnの状態でtxnレコードを更新し続ける。必要なのだろうか。特に5秒に一回しか更新しないのであまり効果的な気がしないが

heartbeat txnがレコードを作るのか?

  • EndTransaction/InternalPushTxnではレコードがなければ送ってきたtxnでレコードを作っている

InternalPushTxnはいつ呼ばれるか

  • txnを含むExecuteCmdが、対象となるレコードがすでに別のtxnでロックされていて(WriteIntentError)失敗した場合に、maybeResolveWriteIntentError経由で呼ばれている.
  • retryは、RunTransaction自体のretryとPushTxnによるretryがある。後者が失敗するとtransaction全体がretryになるイメージ。

consistentなreadのいみ

  • readする場合にリクエスト先がleaderであることを保証しなくてはいけない。これはreplicaのうち、そのノードがプライマリだと思っているノードにリクエストを投げればいいという話ではない(リクエストが届いた瞬間にはすでにリーダーではないかもしれないから)。consistentなリクエストを受け取ったノードは自身がリーダーになる必要がある。これがleader leaseの考え方であり、実装が必要。luactにおいてconsistentをしていしたばあいには、cockroachにおけるCONSENSUS-read consistencyの意味。

========== implementation plan

  1. rangeにnon-mvccに読み書きを行うsystem rangeを追加(flagで挙動をコントロール).bootstrapで作成してmeta2から検索可能にする
  2. range_managerにpush_txn/end_txn/hb_txnを追加。それぞれPushTxn/EndTransaction/HeartbeatTxnに相当。それぞれsystem rangeに対して発行される つまり、keyからsystem rangeのキーを作ってfindして、そこにpush/end/hbを発行する
  3. txncoordで_M.rmを使ってこの辺りのコマンドを送る。
  4. write commandの内部で読んでいるrange:writeをpcallにしてエラーを受け取る。エラーが起きた時にはpushtxnでリカバリーを試みる。失敗した場合はさらに外(txncoord.run_txn)にエラーをpropagate
  5. txncoord.run_txnはさらにtxn エラーなども見ながらretryを制御する。以上。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment