480 likes | 628 Views
Distributed Systems Chapter 5: Synchronization. B4 弘中 健. 全体の流れ. 分散システムの同期の基礎 Logical lock Distributed Snapshot Election Algorithm Mutual Exclusives Transaction. Distributed System. 複数のマシンのネットワーク これらのマシンは message passing によって通信する。 複数のプロセスを議論する時、それらはそれぞれ別々のマシンにあることを前提に話す。.
E N D
全体の流れ • 分散システムの同期の基礎 • Logical lock • Distributed Snapshot • Election Algorithm • Mutual Exclusives • Transaction
Distributed System • 複数のマシンのネットワーク • これらのマシンはmessage passingによって通信する。 • 複数のプロセスを議論する時、それらはそれぞれ別々のマシンにあることを前提に話す。
分散システム(DS)のClock • それぞれのマシンは独自に時間を刻んでいる。 • 時間は違うし、刻みも違う(clock interval)。 • ローカルプロセスはローカルのclockでcurrent timeを決定している。 • 複数のマシンで共同に仕事をする時に問題 • ex:ファイルの更新
どうclockを同期するか • Time serverを使う • ある時間間隔ごとにtime req.をして合わせる。 • 合わせても、すぐにまたズレる。 • Requestに不確定な遅延がある。 • Time Daemonを使う • Daemonが全マシンから時間をrequest • Daemonが平均時間をBroadcastする。 • Time serverの問題は解決されない。
結局。。。 • 結局、きっちり時間を合わせることは不可能 • でも、共同作業をする時は同期が大切 • 結局 • 絶対的な時間は問題じゃない • 物事(event)の順序に合意できればいい • →Logical Clocks
イベントとは • イベント: • あるプロセスが実行する単一のaction • Ex: send msg., receive msg., change sate • 一つのプロセスのイベントは全順序
Lamport’s Logical Clock • DSのおける、イベントの順序 • A “happens before” B ≡ A→B • 同一プロセスで、event eがevent e’の前の起きると • e→e’ • プロセス間でメッセージmを通信したら • Send(m)→Recv(m) • →はtransitive • A→B & B→C ⇒ A→C • →は半順序 • 順序づけられないイベントはA,Bは”concurrent” A || B
Lamport’s Logical Clock Algorithm • Ci:各プロセスが持つlogical clock • A→B ⇒ Ci(A)<Ci(B) • Ciは非減少 • 二つのプロセスで連携する時、Ci(x)=Cj(x) • プロセス番号を小数点をつけて順序をわざとつける。 • Ex: P1,P2でCi(x)=4 → C1(x)=4.1 C2(x)=4.2とする。 • プロセスPiでイベントがある時 • Ci++ • プロセスPiがmsgをsendする時 • クロックCiを添付する • プロセスPjがPiからmsgをrecvする時(Ciは添付されたもの) • Cj=max(Ci,Cj)+1
0 Figure10.5 0 0 Logical Clock Example • a→b→c→d→f ⇒ C1(a)<C1(b)<C2(c)<C2(d)<C3(f) • b||e • C1(e)<C3(b)は関係ない • A→B ⇒ C(A)<C(B)butC(A)<C(B) ⇏ A→B 1 2 3 4 1 5
Vector TimeStamp • Vector TimeStamp:VT • VTi : Piが管理するプロセス数長の配列 • VTi[i]: Piで起きたlocalイベント • 現在のPiを影響したlocalイベント • VTi[j] (i≠j) : 現在のPiを影響したPjのイベント • VTi≦VTj (for all i,j) • For all k VTi[k]≦VTj[k]
Pjは以後受け取ったmに影響されたことになる。当然、m自信が過去に影響されたものに対しても、影響されるはず。Pjは以後受け取ったmに影響されたことになる。当然、m自信が過去に影響されたものに対しても、影響されるはず。 Recv. というローカルイベントの対するもの Vector Stamp Algorithm • Init: VTi[j]=0 (j=1~N) • local event on Pi: VTi[i]++ • Pi send msg. m to Pj • VTiをmに添付(vtとする) • Pj recv. msg. m from Pi • VTj[k]=max(VTj[k],vt[k]) • VTj[j]++
(0,0,0) (0,0,0) (0,0,0) Vector TimeStamp Example • Timestampによって、因果関係がしっかりする! • VTi(A)<VTj(B) ⇔ A→B • VT2(d)<VT3(f) ⇔ d→f • !VTi(A)<VTj(B) & ! VTj(B)<VTi(A) ⇔ A||B • !VT3(e)<VT1(b) & !VT1(b)<VT3(e)⇔b||e • 勿論、まだ半順序関係です (1,0,0) (2,0,0) (2,0,0) (2,1,0) (2,2,0) (2,2,0) (0,0,1) (2,2,2)
Global State • Def:全てのプロセスの状態と、ネットワーク中漂っている(まだ届いてない)msg達 • Global stateを知ることは意外と重要 • Distributed GC • Program termination • Deadlock detection
Distributed Snapshot • Global stateを表現する手法 • いろいろあるが、distributed snapshot • Distributed Snapshot • 各プロセスがあったであろう状態(各プロセスのある時点でのイベント履歴)の和 • Cutともいう • そのうち、”consistent”であるもの • プロセス同士のイベント履歴が矛盾ぜす、一貫している
m1なんて送ってない! m1を受け取った Cuts Global Snapshot
Global State Implementation • 全てのプロセスは一方向通信チャネルをつかって繋がれている。 P2 P1 P3
Algorithm • 1. G Snapshotを取りたいプロセス • 自分のプロセスを状態を保存する。 • マーカーM(PIDがついた)を、自分のすべてのチャネルから送る。 • 2. Mを受け取ったらプロセス • 自分のプロセスの状態を保存していない時 • 自状態を保存し、自分の全てのチャネルからMを転送 • 以後、送って来るmsg全てを保存。 • 自分のプロセスの状態を既に保存した時 • 全てのプロセスからMが来たら、msg保存を終了し、保存したものをsnapshotを取りはじめたプロセスに送る。
アルゴリズムの図 M 状態保存 M M 到着msgを保存する区間: ここで到着したmsgはsnapshotでネットワーク上 漂っていたmsg
自分の処理が終っていなかったり、msgが届いたりしたら終わりじゃない自分の処理が終っていなかったり、msgが届いたりしたら終わりじゃない 子プロセスが一つでも終わりじゃないと、終わりじゃない Termination Detection • PjはPiからsnapshot markerを貰った ⇒ PiはPjの親 Term_detect(){ DONE=TRUE; recv(M,Pi);//PiからMを貰った、Piが親になる SS=local_snapshot();//snapshotのアルゴリズムに従う 子プロセスが決まる if(!(local_work_done(SS)) || gotmsg(SS) ){ send(CONTINUE,Pi); DONE=FALSE; } for all child process: Pc{ if(recv(Pc)==CONTINUE){ send(CONTINUE,Pi); DONE=FALSE; } } if(DONE) send(DONE,Pi); else send(CONTINUE,Pi); }
Election Algorithms • 全プロセスで同期を取ったりするにはcoordinatorが必要な場面が多々ある。 • Coordinatorを選出する方法が必要 • 仮定: • 選出中に誰も死なない • 全てのプロセスには番号がついていて、他のプロセス番号も全て知っている • 誰が生きているかは分からない
Bully Algorithm • 0.coordinatorがいないこと、新しいプロセスが登場したことに気づいたプロセスが始める • 自分よりもプロセス番号が高いプロセスにELECTION msgを送る。 • 1.ELECTIONメッセージを受け取った時 • Ok msgで返事し、自分よりもプロセス番号が高いプロセスにELECTION msgを送る。 • 2a.Ok msgが返って来た時 • 仕事終了 • 2b.誰からも返事がない時 • 自分がcoordinatorになったとbroadcastする。
!! OK ELECTION ELECTION OK C:4 C The flow P2 P1 P3 P0 P4 P5 C
Ring Algorithm • 仮定:自分のsuccessorプロセスは • Suc PID=(PID+1) mod PROCESS_NUM • 複数の人が同時に行ってもOK! • 0.Coordinatorが死んだことに気づいたプロセス • 自分のPIDと付けて、successorにELECTION msgを送る。 • 1a.ELECTION msgを受け取ったら • 自分のPIDを付け足して、successorにELECTION msgを転送する。 • 1b.Successorから返事がなかったら • その次のプロセスに同じmsgを送る。 • 2.自分のPIDを含むELECTION msgが届いたら終了 • 一番PIDが高いプロセスが新しいcoordinator
!! P2 P1 [1,] [1,2,] [4,0,] P3 P0 [4,] !! P4 P5 The flow, yet again C
Mutual Exclusives • DSでも同期を取るとき、lockを定義する必要がある。 • 仮定: • 全てのmsgは届く
Centralized Lock Algorithm • LOCK • CoordinatorにREQUEST msgを送る。 • GRANT msgを受け取るまでBLOCKする。 • Coordinatorはlockがfreeの時、GRANT msgを返信する。 • Lockがfreeじゃない時、返信せず、waiting queueにプロセスを入れる。 • Lockがfreeになったらcoordinatorはqueueの先頭のプロセスにGRANT msgを送る • UNLOCK • CoordinatorにRELEASE msgを送る。 • Coordinatorが死ぬと破綻する
Distributed Lock Algorithm • Lamport logical clockを使う • LOCK • REQ(PID,critical region name,TIMESTAMP)をbroadcastする。 • REQを受け取ったプロセスは • (i)構わない時はOK msgを送る • (ii)そのcritical regionに入っていると返事せずに、wait queueにPIDを入れる。 • (iii)自分もREQを出している時、自分が出したTIMESTAMPと今届いたREQのTIMESTAMPを比較する。自分の方が若かったら(i),そうでなかったら(ii) • 単純にTIMESTAMPの数値を比較する。 • 全てのプロセスからOKをrecvするとLockを取得する。 • UNLOCK • RELEASE(PID, critical region name)をbroadcastする。 • N points of failure…
Token Ring Lock Algorithm • 初期化:プロセス0でトークンを作る。 • トークンをプロセス間で回していく。 • Piはトークンをリングの次のプロセスPi+1に送る。 • Pi+1トークンを受け取るとOK msgを返信する。 • PiはOK msgを返ってこないとその次のプロセスにトークンを送る。 • トークンを受け取ると、critical regionに入ることが出来る。処理を終えて出たら、トークンを次のプロセスにsendする。 • トークンが持っているプロセスが死ぬと破綻する。
Transaction • 一連の処理をatomicallyに実行する。 • 成功したら結果を更新(commit)し、失敗したら行った仕事を捨てる。 • 作業中に担い手が死んでも、影響が出ないために大切。 • Atomic • 処理の結果は成功されるまでcommitされない。 • Consistent • System invariablesは前後で不変でないといけない。 • 作業中はルールを破ることが許される。 • 例えば、銀行のtransactionではお金の総和 • Isolated • 複数のtransactionが同時にあっても、ある逐次の順序で行われたと同じ結果が最終的にcommitされる。 • Durable • 一度commitした内容はもう戻せない。
Flat Transaction • 今まで説明したTransactionのこと • バニラ味 • 問題 • All or nothing…もったいない。。。 • 時間が掛かる • 例えば:あるメモリのアドレスが変更された時、全てのポインタを更新する。
Nested Transaction • Transactionは依存関係のない内容を子transactionに小分けし、複数のプロセスに負荷を分散する。 • 子transactionはさらに子transactionを作ってもいい。 • 木構造に仕事が分散される。 • 子transactionがcommitする時、親transactionにcommitする。 • 親transactionがABORTすると子transactionもABORTする。 • 子transactionがABORTすると、親transactionは次に何をするか考える。 • ABORT? retry?
Distributed Transaction • Nested Transactionとほぼ同じ • ただ、分散される仕事は互いに依存関係がある。 • 一つのFlat Transactionが複数のプロセスで行われる。 • データアクセスにはlockingなどの同期が必要
Atomicityのimplementation • Private Work Space • 触るデータを全てコピーし、作業はその上で行う。Commitする時に更新する。 • 実際は全コピーはせず、ポインタのみをコピー。 • Writeした内容のみを保持し、後でwrite back • Writehead log • Writeは実行される都度originalを更新し、logを取る。 • Abortする時はlogに従ってデータをroll backする。
Concurrency Control • Serially Equivalent Interleaving (SEI) • 同時に複数のtransactionがある時、全てのtransactionがある逐次の順番に実行されたと同じ結果を残す。 • だた、mutexを使うだけでは実現出来ない。 • 状態の変化は不可分で出来るが、複数のTransactionが自由な順序で変化を加えるので、isolation, consistencyを維持出来ない。
implementation • Data Manager • 指示されたread/writeをオブジェクトに実行する。 • Scheduler • SEIを実現するようにread/writeをscheduleし、data managerの指示を送る。 • Transaction Manager • 一つのtransactionに付き一つ • Transaction primitiveをread/writeの命令に解釈する。
Scheduler Scheduler Data Manager Data Manager Machine 1 Machine 2 Machine 3 Transactionの構成 Transaction Manager Scheduler Data Manager
Conflicting operation pair • 同時に走っているtransaction間での衝突 • 一つのオブジェクトに対する二つの命令の順序によって最終結果が異なる。 • Read-write operation pair • Write-write operation pair
Transaction 1: x=x-1 //x=4 y=y+1 Transaction 2: s=0 s=s+x //s=4 s=s+y //s=9 Example: x=y=5とする 終るとs=9…
Solution to the problem • 2 transaction Ti,Tj間の全てのconflicting operation pairにおいて、TiがTjよりも前にオブジェクトへの処理を完全に済ませれば、SEIは守られる。
2 Phase Locking • 今述べた条件が満たされるようにlockで同期を取る。 • 1.Tiの命令に対して、schedulerは既に発行したTjの同じオブジェクトに対する命令と衝突しないかチェック。 • 問題なければlockをロックして、Tiの命令は進む。 • 問題があれば、Tiはロックが貰えずブロックする。 • 2.data managerがそのオブジェクトへの更新はもうないとすると、lockを開放する。 • 3.Tiは一度一つのlockを開放すると、もう二度とどのオブジェクトに対してもlockの要求が出来ない。 • 複数取得したロックを開放して行く一方。 • Lock phase, release phaseがあることがミソ • 二つのプロセス間が最初ロックを巡って競う。勝ったプロセスが、その後ロックを取得し続ける。つまり、勝ったプロセスが一方的にcriticalなオブジェクトを先にアクセスし続ける。
Recovery from aborts • Dirty Read • Taがobjにwriteし、その後Tbがobjの値を使った。Taがabortした時、Tbが使った値がroll backされない。 • Premature Write • Taがobjにwriteし、その後、Tbがobjにwriteした。Taがabortした時、objの値がroll backされてしまい、Tbが正しく更新したobjの値が消えてしまう。
Transaction 1: x=x+2 //x=7 ABORT Transaction 2: y=x //y=7 yの値に影響が出る。。。 Dirty Read: Example X=5とする ・・・ x=5にroll back
Strict 2 Phase Locking • 2 phase lockingと同じ • ただ、transaction中にunlockを行うことはない。 • transactionがabort/commitする時に全てのlockをunlockする。 • Abortからのrecoveryが出来る。
Solution:Strict Execution • objへのread/writeは以前objにwriteしたtransactionがabort/commitするまで遅延する必要がある。
取得lock数 取得lock数 2 phase locking の比較 2 Phase Locking Strict 2 Phase Locking Unlock all at once Locking Phase Unlocking Phase abort/commit
Distributed 2 Phase Locking • Centralized 2 Phase Locking • システムで一つのLock Managerを用意すればいい。 • Coordinatorとか • Transactionの処理にはlock managerにlockのlock, unlockを要求する。
まとめ • DSをいじるにあたっての基礎 • Logical lock • Distributed Snapshot • Election Algorithm • Mutual Exclusive • Transaction