SlideShare a Scribd company logo
Spanner に関する技術メモ
発表者:通りすがりの @enakai00
Disclaimer:
この記事は個人的なものです。ここで述べられていること
は私の個人的な意見に基づくものであり、私の雇用者に
は関係はありません。
Spannerのインフラデザイン
https://research.google.com/archive/spanner.html
全体構成
Spanserver ⇒ Bigtable に類似の Key-Valueストア
Spanserver は Bigtable の Tablet server に相当 ⇒ Tablet の実体は Colossus 上に存在
DC (Zone) 間で Tablet の内容をレプリケーション(Paxosベースのアルゴリズム)
spanserver
(Table A)
spanserver
(Table B)
spanserver
(Table C)
Zone 1
spanserver
(Table A)
spanserver
(Table B)
spanserver
(Table C)
Zone 2
spanserver
(Table A)
spanserver
(Table B)
spanserver
(Table C)
Zone 3
replica replica
Horizontal Consistency
VerticalConsistency
Spannerのチャレンジ
● 同一 Zone の spanserver 間のデータ整合性をどう確保するか?
● Zone 間のデータ整合性をどう確保するか?
ところで、Spanserver間のデータの整合性って何?
⇒ トランザクションの仕組みから
 整合性の意味を考えてみましょう。
トランザクションの動作
https://cloud.google.com/spanner/docs/transactions
ロックの種類
Shared Read Lock(共有ロック)
● 他のトランザクションからの書き込みを禁止
● 他のトランザクションからの読み込みは可能
● 他のトランザクションは同時に共有ロックを取得可能
Exclusive Write Lock(排他ロック)
● 他のトランザクションからの読み書きを禁止
● 他のトランザクションは同時にロックを取得できない
● 他のトランザクションが先に共有ロック/排他ロックを取っている場合は、排他ロックは
とれない。
リードライト・トランザクションにおけるロックの利用
AさんからBさんに50円送金するトランザクション
⇒ 外部からは時刻 t2 にすべての変更がまとめて行われたように見える
A : 100
B : 200
C : 1300
A : 100
B : 200
C : 1300
A : 50
B : 200
C : 1300
共有ロック
排他ロック
Read A = 100 Read B = 200
Write A = 50
Write B = 250
トランザクション開始
この時点では何も
書き込まれない
Commit
A : 50
B : 250
C : 1300
A : 100
B : 200
C : 1300
A : 50
B : 250
C : 1300
トランザクション中に読んだデータが
勝手に書き換えられることを防止
書き換え中の中途半端な状態が
読み取られることを防止
A : 100
B : 200
C : 1300
トランザクション終了
t1 t2
t2
書き込みデータには
Commit時の
タイムスタンプを付与
TNX B
TNX A と TNX B が平行に走る例
⇒ TNX B は時刻 t2 以前に開始しているが、そこは関係なくて、外部からは、
  TNX B の処理は時刻 t3 にすべてまとめて行われたように見える!!!!
 (トランザクション中に読んだデータはすべて共有ロックで守られているので、
  どの時刻に読んだと考えても同じ結果になる点に注意)
A : 100
TNX A
B : 200
C : 1300
A : 100
B : 200
C : 1300
共有ロック
排他ロック
Read A = 100 Read B = 200
Write A = 50
Write B = 250
Commit
A : 50
B : 250
C : 1300
t1 t2
A : 50
B : 250
C : 1300
Read C = 1300 Read B = 250 Write B = 350
Write C = 1200
A : 50
B : 350
C : 1200
Commit
A : 50
B : 350
C : 1200
t3
TNX A はデータ A を書き換える(t = t2)
TNX B はデータ B を書き換える(t = t3)
この時、さらに別のトランザクションが A と B の値を読み取ると何が見えべきか?
読み取りリクエストを発行した時刻を T として・・・
● 時刻 t1 < T < t2 ⇒ (A, B) = (100, 200)
● 時刻 t2 < T < t3 ⇒ (A, B) = (101, 200)
● 時刻 t3 < T ⇒ (A, B) = (101, 201)
内部的には、「時刻 T 以前のタイムスタンプの中で最新のタイムスタンプのデータ」を spanserver から
取り出すことでこれを実現
⇒ リードオンリー・トランザクションでは、ロックを取得する必要がない!
A : 100 A : 100 A : 101 A : 101
B : 201
A : 101
B : 201B : 200
A : 101
t2
B : 200B : 200
t2 t2
B : 200
t1 t1 t1
t1 t3t1 t1 t1 t1
タイムスタンプベースのトランザクションの課題
行Aと行Bを別々のSpanserverが担当していて、サーバー間で時刻
同期がとれていなくて、行Bにタイムスタンプ t3 を振った時に、間違っ
て t3 < t2 にしちゃったら・・・
だめじゃん!
⇒ Truetime APIで解決
(参考)
タイムスタンプを使用しない従来型のアプローチ
Table A Table B
RDB without read transaction
Write 1
Write 2
Read 1
Read 2
RDB with read transaction
using read-lock mechanism
Table A Table B
Write 1
Write 2
Read 1
read lock
lock release
リードオンリー・トランザクションでもリードロックが発生する
ので性能が上がらない。
NG
Table A Table B
Write 1
Write 2
Read
RDB with read transaction
using MVCC (multi version concurrency control)
Write 0
Transaction ID
0
1
2
get ID
read ID=0
read ID=0
トランザクションIDを一元管理する処理がボトルネックになる
Table A Table B
Write 1
Write 2
Read
Spanner's approach
Use timestamp as a transaction ID
Write 0 get current time
read time=0
read time=0
Spannerでは、トランザクションIDの代わりにタイムスタンプを使用す
ることで、ボトルネックを排除
time=0
time=1
time=2
よくわかった。
それでは、Zone間のデータの整合性って何???
⇒ 今回は省略。m(_ _)m
Truetime APIで t3 > t2 を保証する方法
https://research.google.com/archive/spanner-osdi2012.pptx
commit
start
Time range
t=0 t=2
Choose commit timestamp as latest possible time t2=X
Realtime
Time range
t=2 t=4
Write data at t(real) > t2 = X
t(real)=X
Truetime API
⇒ 信頼出来る時刻の範囲 (t_after, t_before) を返すAPI
commit
finish
上記の commit finish 以降、つまり、t(real) > t2 = 2 の瞬間に次のトランザクションの
commit start が発生したとすると、 t3 > t(real) > t2 が保証される
(commit start 〜 commit execute の間は、排他ロックが取得されているので、同じ行を含む他のトランザ
クションの commit start は発行されない。)
排他ロック
取得完了
Fluctuations of time drifts from time servers
(excerpt from the research paper)
Hardware maintenance
of two time servers
Network latency
improvement
Truetime APIの精度
Truetime APIが返す時刻 (t_after, t_before) の幅が大きいと commit 処理時の
待ち時間が長くなるので、できるだけ小さい幅で返すことが重要
Thanks!

More Related Content

Spannerに関する技術メモ