中科大-算法分析與設計-分布式算法復習知識點


一、分布式算法

1.1 導論

並行處理與分布式處理的區別

  • 並行處理目標:使用所有處理器執行一個大任務。
  • 分布式處理具有更高程度的不確定性和行為的獨立性,每個處理器都有自己獨立的任務。

分布式系統作用

  • 共享資源
  • 改善性能
  • 提高可靠性

模型:

  • 異步共享存儲模型:用於緊耦合機器
  • 異步 msg 傳遞模型:用於松散耦合機器及廣域網
  • 同步 msg 傳遞模型:msg 延遲上界已知,系統執行划分為輪執行,是異步系統的特例

1.2 消息傳遞中的基本算法

每個處理器\(p_i\)可以模型化為一個具有狀態集\(Q_i\)的狀態機

初始狀態\(Q_i\)包含一個特殊的初始狀態子集,每個inbuf必須為空,outbuf不一定為空。

轉換函數:將可訪問狀態的inbuf轉換到outbuf

配置:分布式系統上某點整個算法的全局狀態

事件計算事件傳遞事件

執行:配置和事件交錯的序列。

需滿足安全性條件和活躍性條件。

  1. 安全性:某個性質在每次執行的每個可達配置里都成立。“壞事從不發生”

  2. 活躍性:某個性質在每次執行的某些可達配置里成立。“最終某個好事發生”

滿足安全性條件稱為執行。同時滿足活躍性條件稱為容許執行

1.2.1 轉移系統與安全性和活躍性

轉移系統\(三元組 Triple \ S=(C,\rightarrow,I)\)\(C\)是配置集,\(I\)是初始配置的一個子集,\(\rightarrow\)是配置集上的二元轉移關系。

可達\(\exist \ 序列 \gamma_0 \rightarrow \gamma_1 \rightarrow \cdots \rightarrow \gamma_k = \delta,且\forall 0 \le i \le k-1,\gamma_i \rightarrow \gamma_{i+1},則稱\delta是可達的\)

安全性\(S=(C,\rightarrow,I),斷言/性質P總是成立\)

\(\{P\} \rightarrow \{Q\}:\forall \gamma \rightarrow \delta, if \ P(\gamma),then \ Q(\delta)\),即如果 P 在轉移前成立,則 Q 在轉移后成立

定義:\(P是S的不變式,\forall \gamma \in I,P(\gamma)成立且\{P\}\rightarrow\{P\},P總是成立\),P 為安全性條件

定理:如果 P 是 S 的不變式,那么對 S 的每次執行的每一配置 P 都成立

活躍性:在算法的每次執行的某些配置中,P 為真,且最終 P 為真。

判斷方法:

  • 范函數
  • 無死鎖 / 系統正常終止

范函數\(轉移系統S和斷言P,f:配置集C\rightarrow良基集\omega\)

良基集\(偏序集(\omega,<)是良基的,當且僅當不存在無窮遞減序列,即存在最小值\)

1.2.2 系統

異步系統

異步msg 傳遞時間和一個處理器的兩個相繼步驟之間的時間無上界

執行片段:一個有限或無限的序列,由配置事件交替組成

執行:從初始配置開始的執行片段

調度執行中的事件序列

容許執行:某個處理器有無限個計算事件(指處理器沒有出錯,並不是無限步),每個發送的 msg 都最終被傳遞。

同步系統

處理器按輪執行,一輪里,每個處理器可以發送一個 msg 到鄰居,每個處理器一接受到 msg 就計算。

:配置和事件序列可以划分為不相交的輪,每輪由一個傳遞事件一個計算事件組成。

同步系統與異步系統的區別:

  1. 無錯的同步系統中,算法的執行只取決於初始配置
  2. 異步系統中,算法可能有不同的執行(不代表不同的結果)

1.2.3 復雜性度量

消息復雜度:所有容許執行上發送消息總數的最大值

時間復雜度

  • 同步系統:最大輪數
  • 異步系統:所有計時容許執行中直到終止的最大時間

1.2.4 生成樹上的廣播和斂播

生成樹 ST:具有共同頂點不出現回路的子圖。

最小生成樹 MST:所有邊權值和最小的生成樹。

廣播

基本步驟

  1. \(p_r\)發送\(M\)給所有的孩子。
  2. 某節點收到父節點的\(M\)時,發送\(M\)給自己的所有孩子。
upon receiving no msg:
 if i=r then
        send <M> to all children;
  terminates;
upon receiving <M> from P_j:
 send <M> to all children;
 terminates;

消息復雜度\(O(n)\)

時間復雜度\(O(h),h為生成樹高度\)

斂播

基本步驟

  1. 每個葉子節點發送消息給雙親
  2. 每個非葉節點等待所有孩子的消息,之后再發消息給雙親

消息復雜度\(O(n)\)

時間復雜度\(O(h),h為生成樹高度\)

1.2.5 構造生成樹

Flooding 算法

消息復雜度:\(O(2m-(n-1))\)

事件復雜度:\(O(D),D為網直徑\)

基本思想

  1. 根節點發送消息\(M\)給所有鄰居

  2. \(P_i\)收到來自\(P_j\)的消息\(M\)且是第一次收到消息\(M\)時,\(P_i\)發送\(<parent>\)\(P_j\)\(P_i\)向其他向自己發送消息\(M\)的節點發送\(<reject>\)\(P_i\)\(P_j\)以外的鄰居發送消息\(M\)

  3. \(P_i\)收到\(P_j的<parent>\)消息,則表明\(P_i是P_j的父節點\)

Code for Pi (0<=i<=n-1)
初值:parent=nil;集合children和other均為空集

upon receiving no message:
    if i=r and parent=nil then { //根尚未發送M
     send M to all neighbors;
     parent:=i;} //根的雙親置為自己
upon receiving M from neighbor pj:
    if parent=nil then { //pi此前未收到過M,M是pi收到的第1個msg
     parent:=j;
     send <parent> to pj; //pj是pi的雙親
     send M to all neighbors except pj;
    }else //pj不可能是pi的雙親,pi收到的M不是第1個msg
     send <reject> to pj;
upon receiving <parent> from neighbor pj:
    children:=children∪{ j }; //pj是pi的孩子,將j加入孩子集
    if children∪other包含了除parent外的所有鄰居 then terminate;
upon receiving <reject> from neighbor pj:
    other:=other∪{ j }; //將j加入other,通過非樹邊發送的msg。
    if children∪other包含了除parent外的所有鄰居 then terminate

異步模型中,構造以\(p_r\)為根的生成樹

同步模型中,構造的一定是BFS

在異步系統中無法生成 BFS,因為消息傳遞無上界,最壞可能出現單鏈。

1.2.6 指定根構造 DFS 生成樹

基本思想

  1. 選定根節點\(P_r\),向某一鄰接節點發送消息\(M\)
  2. \(P_i\)收到\(P_j\)的消息\(M\)是第一個來自鄰接節點的消息時,認定\(P_j\)為其雙親,並向之后給自己發消息\(M\)的節點發送\(<reject>\)
  3. \(P_i\)向未發過消息的鄰居中任選一個發送消息\(M\),並等待回復
  4. \(P_i\)向所有鄰居發過消息,則\(P_i\)終止
Code for Pi (0<=i<=n-1)
初值:
parent = nil;
children = Φ;
unexplored = Pi's neighbors

upon receiving no message:
 if i=r and parent=nil then { //當Pi為根且未發送M
     parent:=i; // 將parent設置為自身
      任意 Pj ∈ unexplored
       將 Pj 從 unexplored 中刪去
     send M to Pj;}//endif
upon receiving M from neighbor Pj:
    if parent=nil then { //pi此前未收到過M
     parent:=j;
        將 Pj 從 unexplored 中刪去
        if unexplored!=Φ then {
           任意 Pk ∈ unexplored
       將 Pk 從 unexplored 中刪去
     send M to Pk;
        }else send <parent> to parent;
    }else send <reject> to pj; //當Pj已訪問過
upon receiving <parent> or <reject> from neighbor pj:
    if received <parent> then add j to children; // Pj是Pi的孩子
    if unexplored = Φ then { //Pi的鄰居均已訪問
     if parent!=i then send <parent> to parent; //Pi非根,返回至雙親
      terminate; //以Pi為根的DFS子樹已構造好
    }else{ //選擇Pi未訪問過的鄰居訪問
     任意 Pk ∈ unexplored
       將 Pk 從 unexplored 中刪去
     send M to Pk;
    }

消息復雜度,時間復雜度:\(O(m)\)

1.2.7 不指定根構造 DFS 生成樹

與領導者選舉問題類似,為破對稱問題

基本思想

  1. 每個結點均可自發喚醒,試圖構造一根以自己為根的 DFS 生成樹。若兩棵 DFS 樹試圖鏈接同一節點(未必同時),選擇根 ID 較大的 DFS 樹加入

  2. 每個結點設置一個 leader 變量,即為當前 DFS 樹的根 ID

  3. 結點自發喚醒時,將自己的 leader 發送給某一鄰居

Code for Pi (0<=i<=n-1)
初值:
parent = nil;
leader = 0;
children = Φ;
unexplored = Pi's neighbors

upon receiving no message: // 自主喚醒
    if parent=nil then { //若非空,則Pi在某子樹上,則Pi失去競選機會
     leader:=id; parent:=i; // 將parent設置為自身
      任意 Pj ∈ unexplored
       將 Pj 從 unexplored 中刪去
     send <leader> to Pj;}//endif
upon receiving <new_id> from neighbor Pj:
    if leader<new_id then { //將Pi所在樹合並到Pj所在樹中
     leader:=new_id; parent:=j;
      unexplored:=all neighbors of Pi except Pj; //重置未訪問鄰居集
       if unexplored!=Φ then { //原Pi所在DFS樹修改各自id
            任意 Pk ∈ unexplored
             將 Pk 從 unexplored 中刪去
      send <leader> to Pk;
       }else send <parent> to parent;
    }else if leader=new_id then send <already> to Pj;
upon receiving <parent> or <already> from neighbor pj:
    if received <parent> then add j to children;
    if unexplored = Φ then { //Pi的鄰居均已訪問
     if parent!=i then send <parent> to parent; //Pi非根,返回至雙親
      else terminate as root of the DFS tree; //以Pi為根的DFS子樹已構造好
    }else{ //選擇Pi未訪問過的鄰居訪問
     任意 Pk ∈ unexplored
       將 Pk 從 unexplored 中刪去
     send <leader> to Pk;
    }

一個具有 m 條邊,n 個節點的網絡,自發啟動的節點由 p 個,ID 值最大的啟動時間為 t。

消息復雜度:\(O(pn^2)\)

時間復雜度:\(O(t+m)\)

1.3 環上選舉算法

匿名的:環中處理器沒有唯一的標識符,每個處理器具有相同的狀態機

一致性、均勻的:不知道處理器的數目

解釋一致性和非一致性:

算法一:向右轉發 n 步 msg,然后終止。 => non_uniform

算法二:向右轉發 msg,直到 msg 發送者收到 msg。 => uniform

在一個匿名的、一致性算法中,所有處理器只有一個狀態機。

在一個匿名的、非一致性算法中,每個 n 值對應一種狀態機。

  • 同步環系統不存在匿名的、一致性的領導者選舉算法
  • 異步環系統不存在匿名的領導者選舉算法

1.3.1 異步環

開調度:在算法 A 的一次調度中,有一條邊上無消息傳遞,則為開邊。

(開調度未必是容許的調度,是容許執行的一個有限前綴)

異步環上的選舉算法有消息復雜度下界\(O(nlg \ n)\)

\(O(n^2)的算法\)

基本思想

  1. 每個處理器發送一個標識符 msg 給左鄰居,然后等着接收右鄰居的 msg。
  2. 每個處理器收到 msg 時,若收到的 id 大於自身,則向左鄰居轉發。
  3. 若處理器收到自己的標識符 id,則宣布自己是 leader,並發終止 msg 給左鄰居,然后終止
  4. 若處理器收到終止 msg,則向左轉發,然后終止

核心思想:處理器向左鄰居發送標識符 msg,通過比對 id 確定 leader,只有最大的 id 消息會回到他自己。

Code for Pi (0<=i<=n-1)
初值:asleep=true; id = i;

While (receiving no message) do
  (1) if asleep do
      (1.1) asleep = false
      (1.2) send <id> to left-negihbor
   end if
End while
While (receiving <i> from right-neighbor) do
 (1) if id < <i> then send <i> to left-neighbor
       end if
 (2) if id = <i> then
      (2.1) send <Leader,i> to left-neighbor
      (2.2) terminates as Leader
   end if
End while
While (receiving <Leader,j> from right-neighbor) do
 (1) send <Leader,j> to left-neighbor
 (2) terminates as non-Leader
End while

消息復雜度:\(O(n^2)\)

\(O(nlg(n))\)的算法

k 鄰居:據某一處理器距離不超過 k 的處理器,左邊有 k 個,右邊有 k 個,共有\(2k+1\)個。

基本思想

  1. 階段 0:每個節點向兩個 1-鄰居發送 id 消息,若鄰居的 id 小於此消息則回復 reply,否則吞沒。若一個節點收到兩個鄰居的 reply,則自認為 leader,並進入階段 1。
  2. 階段\(l\):在上一階段成為 leader 的處理器,繼續發送 id 消息給\(2^l\)鄰居,若收到來自左右兩個方向的 reply,則自認為 leader。
  3. 若收到自己的消息,則終止。

核心思想:第\(l\)階段一個處理器試圖成為其\(2^l\)-鄰居的臨時 leader。只有在\(l-th\)階段成為 leader 的處理器才能繼續\((l+1)-th\)階段。

Code for Pi (0<=i<=n-1)
初值:asleep=true;

upon receiving no msg:
      if  asleep then{
       asleep:=false;//每個結點喚醒后不再進入此代碼
        send <probe,id, 0, 0> to left and right;
      }
upon receiving <probe, j, l,d> from left_or_right (resp, right):
    if(j=id) then //收到自己id終止,省略發終止msg
       send <leader,id> to left neighbour;
        terminate as the leader;
    if(j>id) and (d<2^l) then //向前轉發probe msg
     send <probe, j, l, d+1> to right_or_left (resp, left)
    if(j>id) and (d≥2^l) then //到達最后一個鄰居仍未沒收
     send <reply, j, l > to left_or_right (resp, right) // 回答
    // 若j<id, 則沒收probe消息
upon receiving <reply ,j , l> from left (resp, right):
    if j≠id then // 判斷是否轉發到初始點
     send <reply, j, l> to right (resp, left); //轉發reply
    else //j=id時,Pi已收到一個方向的回答msg
     if already received <reply, j, l> from right (resp, left) then //也收到另一方向發回的reply
    send <probe, id, l+1, 0> to left and right; //Pi是phase l的臨時leader,繼續下一階段
upon receiving <leader, idj> from right:
    send <leader, idj> to left;
    terminate as nonleader;

階段\(k\),臨時 leader 樹最多為\(\frac{n}{2^k+1}\),啟動的 msg 數目最多為\(4*2^k\)

消息復雜度:\(O(nlg \ n)\)

1.3.2 同步環

消息復雜度上界\(O(n)\),下界\(O(nlg \ n)\)

上界\(O(n)\)

  • 非均勻:要求環中所有節點開始於同一輪
  • 均勻:節點可以開始於不同輪

證明上界的非均勻算法

必須知道環大小 n,所有節點開始於同一輪

假定 id 最小的為 leader

基本思想:按階段運行,每個階段由 n 輪組成。階段\(i\)中,處理器 id 也為\(i\)的選舉為 leader,然后終止算法。

各節點互不知道彼此的 id 值。

消息復雜度:恰有 n 個消息被發送,\(O(n)\)

證明上界的均勻算法

無需知道環大小

一個處理可以:自發喚醒或被動喚醒

基本思想

  1. 源於\(id=i\)節點的 msg,在被轉發前延遲\(2^i-1\)輪。
  2. 每個自發喚醒的節點繞環發送一個喚醒 msg,且無延遲
  3. 若節點在啟動前收到喚醒 msg,則該節點只作轉發操作。

只有自發喚醒的節點,才有可能選為 leader

初值:asleep=true;waiting = ф;R = 計算事件中接收msg的集合;s = ф;//the msg to be sent

if asleep then {
    asleep:=false;
    if R = Φ then { // pi未收到過msg,屬於自發喚醒
        min:=id;   // 參與選舉
        s:=s+{<id>}; // 准備發送
    }else{ //已收到過msg,但此前未啟動,被喚醒故Pi不參與
     min:=∞; //選舉,置min為∞ ,使其變為relay結點
     // relay:=true; ?
    }
}
for each <m> in R do {// 處理完收到的m后相當於從R中刪去
    if m < min then { // 收到的id較小時通過
     become not elected;  // Pi未被選中
     // 可用relay控制使轉發節點不延遲?
     將<m>加入waiting且記住m何時加入; // m加入延遲轉發
     min:=m;
    } // if m > min then it is swallowed
    if m=id then become elected; // Pi被選中
} //endfor
for each <m> in waiting do
    if <m> 是在2^m-1輪之前接收的 then
     將<m>從waiting中刪去並加入S
send S to left;

發送的消息:

  • 第一類:第一階段的 msg(喚醒 msg
  • 第二類:最終 leader 的 msg 進入自己的第二階段之前發送的第二階段 msg(其他節點發的)
  • 第三類:最終 leader 的 msg 進入自己的第二階段之后發送的第二階段 msg(包括 leader 發的)

第一類總數最多\(n\)

第二類總數最多\(n\)

第三類總數最多\(2n\)

消息復雜度:\(O(4n)\)

有限制的下界\(O(nlg \ n)\)

序等價:兩個環\(x_0,x_1,\cdots,x_n-1\)\(y_0,y_1,\cdots,y_n-1\)\(x_i < x_j,當且僅當y_i<y_j\)

若一算法只與環上標識符之間的相對次序相關,而與具體 id 無關,則該算法一定只是基於標識符的比較

對於每個\(n\ge8,n是2的方冪\),存在大小為 n 的環\(S_n\),使得基於比較的同步 leader 選舉算法 A,在容許執行里發送的 msg 數目為\(O(nlg \ n)\)

構造\(S_n\)

  1. 定義大小為 n 的環\(R_n^{rev}\),令\(P_i\)的 id 為\(rev(i):i的二進制逆序列\)
  2. 將環划分為長度為\(j,j為2的方冪\)的連續片段,則這些片段是序等價的。
  3. 片斷數為\(\frac{n}{j}\)

1.4 計算模型

計算模型的復雜性:

  • 系統由並發部件構成
  • 無全局時鍾
  • 必須捕捉部件可能的失效

對策:

  • 因果關系
  • 一致狀態
  • 全局狀態

為什么分布式系統缺乏全局系統狀態

  1. 非即時通信(傳播延時,資源競爭,丟失 msg 重發)

  2. 相對性影響(大多數計算機的實際時鍾存在漂移,時鍾同步依舊是一個問題

  3. 中斷(不可能在同一時刻觀察一個分布式系統的全局狀態)

次序\(e_1 < e_2:事件e_1發生在e_2之前\)

定序

  • 發生在同一節點上的事件滿足全序,\(e_1<_pe_2\)
  • \(e_1\)發送消息,\(e_2\)接收消息,則\(e_1<_me_2\)

Happens-before 關系\(<_H\),一種偏序關系

並發事件:兩個事件不能由 \(<_H\) 定序

有時將 Happens-before 關系描述為一個有向無環圖

image-20220103152117876

如何將 H 關系的偏序關系轉變成全序關系:

  • 在有向無環圖 DAG 上的拓撲排序
  • Lamport 算法

1.4.1 Lamport 時間戳

基本思想

  • 事件 e有附加時間戳:e.TS
  • 節點有局部時間戳:my_TS
  • msg有附加時間戳:m.TS
  • 節點執行事件時,將自己的時間戳賦給該事件。
  • 節點發送 msg時,將自己的時間戳給所有的 msg。
  • 接收消息時,本地時間戳更新為最大值
  • 發送消息時,使用本地時間戳打標簽
Initially: my_TS = 0;
On event e:
    if(e == 接收消息m) then
     my_TS = max(m.TS, my_TS)); // 取msg時間戳和節點時間戳較大值
     my_TS++;
     e.TS = my_TS; // 給事件e打時間戳
     if(e == 發送消息m) then
      m.TS = my_TS; // 給消息打時間戳

每一時間的時間戳大於前驅時間的時間戳

問題:不同的時間可能有相同的時間戳(並發事件)

改進算法:使用節點地址作為時間戳低位,如\(1.1,2.2\)。標號后按字典序得到全序關系。

問題:無法通過時間戳判定兩個事件是否有因果關系

1.4.2 向量時間戳

向量時間戳 VT\(e.VT是個數組,e.VT[i]=k表示再節點i上,事件e之前有k個事件(可包括自己)\)

基本思想

  • 節點有局部向量時間戳:my_VT

  • 事件 e 有向量時間戳:e.VT

  • msg 有向量時間戳:m.VT

Initially: my_VT=[0,0,,,0];
On event e:
    if(e == 接收消息m) then
  for i= 1 to M do // 向量時間戳的每個分量只增不減
      my_VT[i] = max(m.VT[i], my_VT[i]);
    my_VT[self]++; // self是本節點的名字
    e.VT = my_VT; // 給事件e打時間戳
    if(e == 發送消息m) then
     m.VT = my_VT; // 給消息m打時間戳

向量時間戳比較:

e1.VT = (5,4,1,3)
e2.VT = (3,6,4,2)
e3.VT = (0,0,1,3)
  1. e1 和 e2 之間沒有完全大於或完全小於的關系,則 e1 和 e2 是並發的。

  2. e3 在因果序上先於 e1

1.4.3 因果通信

處理器不能選擇 msg 到達的時間,但是可以抑制過早到達的 msg。

如 TCP 中的 FIFO 通信。

基本思想

  • 抑制從 P 發送的消息,知道可以斷定沒有其他消息早於 m 發生
  • 在每個節點上:
    • \(earliest[1...M]:不同節點當前能夠傳遞的消息時間戳的下界\)
    • \(blocked[1...M]P:阻塞隊列數組,每個分量是一個隊列\)
Causal Msg Delivery
Definition:
    時間戳lk:
     使用Lamport時間戳,lk=1;
      使用向量時間戳,lk=(0,,,0,1,0,,,0),第k位為1;
Initially:
    earliest[k] = lk,k=1,,,M // 不同節點當前能傳遞的消息時間戳的下界
    blocked[k] = {},k=1,,,M // 阻塞隊列置空

On the receipt of msg <m> from node P:
    delivery_list = {}
    if (blocked[p]==空) then
     earliest[p] = m.timestamp;
      blocked[p].push_back(m); // 處理收到的消息
    //處理阻塞隊列
    while(∃k使blocked[k]非空 &&
     對i=1,,,M(除k和self外) not_earliest(earliest[i],earliest[k],i) )
      // 沒有消息比k更早到
    {
     將blocked[k]隊頭元素m’出隊,且加入到delivery_list;
     if (blocked[k]!=空) then
      earliest[k] = m’.timestamp;
     else
       increment earliest[k] by lk
    }
    deliver the msgs in delivery_list; // 按因果序

可能發生死鎖(一節點上時間不發送你要的 msg)

該因果通信算法常用於組播


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM