MIT6.824 Lab2

MIT6.824 Lab2

設計思路

  • Server :
    • Server每隔PingInterval(85ms)時間獲取View視圖
      • Primary : 設置自身屬性爲Primary
      • Backup : 設置自身屬性爲Backup
    • Get : 當Server爲Primary時返回相應值
    • Put/Append :
      • 第一階段 : 將數據傳入handler
      • 第二階段 : 等待直到handler處理完畢,返回
    • Confirm : 當Server爲Primary時,刪除TagMap中對應的Tag,表示這次操做已被Client確認
    • Sync : 當Server爲Backup時,將參數中的dataMap寫入Server自身的dataMap.
    • handler :
      • 模式一 : 接收Put/Append數據並寫入tempMap
      • 模式二 : 同步至Backup後將tempMap寫入dataMap
  • Client :
    • Client每隔PingInterval(100ms)時間獲取Primary地址
    • Client持續調用Get直到RPC返回結果(value or empty)
    • Client持續調用Get/Put/Append直到RPC返回結果(過程當中更新函數內Primary)
    • Client調用Put/Append時生成RandomKey,當RPC正確返回時,經過RPC函數Comfirm通知Server,Client已經獲知成功狀態
  • 同步 :
    • Server之間的同步並非逐條信息的同步,而是在短期內接收Client請求放入handler中
    • handler在收集信息後先同步到Backup,隨後寫入自身dataMap,此時將全部請求返回.

實現

  • Client的實現很簡單,檢查返回值狀態後調用Comfirm便可緩存

  • Server :
    • handler :
      • 經過select實現上述模式的切換.
      • case1 : 接收PutAppendChannel(同步模式)中的數據並寫入tempMap
      • case2 : 經過時間戳對tempMap中的數據進行排序,並處理Append方法(將已有數據與要處理的數據合併).若是backup不爲空則調用syncToBack來同步數據,同步完成後將tempMap中的數據寫入Server自身的dataMap中.清空臨時變量,並釋放barrier(關於barrier後面會詳細描述).
    • PutAppend :
      • 檢查Server是否爲Primary
      • 檢查Tag是否存在
      • 將數據寫入PutAppendChannel
      • 等待barrier並返回
    • Confirm : 刪除以前被Client註冊的PutAppend Tag.
    • Sync :
      • 檢查Server是否爲Backup
      • 檢查Tag是否存在
      • 將數據寫入dataMap
      • 異步Confirm To Primary
    • barrier :
      • 其實是阻塞管道加讀寫鎖來實現的
      • 由於咱們要實現一段時間內同步一次數據,因此咱們將整個行爲分爲三個部分
      • Step1:經過Channel將數據傳輸至handler中並嘗試得到讀鎖(此時已存在寫鎖,故阻塞).若是此時Channel是阻塞的,則說明handler正在同步,這些數據將等待直到Channel可寫
      • Step2:handler同步數據至Backup,釋放寫鎖(我在代碼中使用了Gosched,寫鎖解鎖時會喚醒等待的讀鎖,可是爲了保險起見,我仍是加上了).
      • Step3:全部PutAppend goroutines 得到讀鎖後立刻解除.此時由於Channel仍然在阻塞,因此handler在全部讀鎖釋放完畢後繼續執行,添加寫鎖並回到初始狀態.

須要注意的問題

  • Tag :
    • 爲何須要Tag : 當由於網絡緣由,Server收到並處理了Client的數據可是並無成功返回的時候,Client須要從新調用RPC.此時Server沒法區分是新的請求仍是沒收到返回值的從新調用
    • Tag須要注意什麼 : Tag一樣須要同步到Backup中,理由是當Primary處理完數據後忽然宕機,Client並無收到正確回覆.此時Client更新視圖後發現Primary地址發生變化將會從新將請求發至新的Primary.此時Primary沒法區分這是新的請求仍是從新調用.
  • Confirm :
    • 爲何須要Confirm : 通知Server對端已經收到成功回覆並刪除Server中的Tag
    • Confirm須要注意什麼 : 確認時注意更新視圖,不然有可能形成阻塞
  • View :
    • 爲何須要View : Server須要獲知當前運行的Primary和Backup.若是ViewService選舉自身成爲Primary或者Backup則要提供響應的服務.
    • View須要注意什麼 :
      • 調用Ping的時候須要發送ViewNum,若是此時Server是Backup,ViewNum並不會從收到的View中得到,而是緩存下來直到Primary同步完成後才更新.緣由是當Backup更新了ViewNum後,ViewService就會在Primary宕機之後將Backup選舉爲Primary,但此時Backup中可能並無數據.
      • 當Primary/Backup發送Ping失敗時,應取消自身的Primary/Backup狀態.理由是若是此時發生了分區,Primary對於ViewService不可達,但對於某些Client仍可達,則此時就會形成錯誤的處理,好比Get到髒數據,PutAppend返回成功結果可是Server已經再也不是Primary/Backup
  • handler :
    • 爲何須要handler : Primary須要同步數據到Backup中,若是咱們採用逐條同步的方式則會形成性能降低,若是加鎖的話,咱們沒法控制goroutines被喚醒的順序,這時候就可能形成了先收到的請求放在後面執行,此時就會形成髒數據.因此咱們將請求數據寫入Channel由handler統一處理
    • 爲何使用同步Channel : 爲了在handler同步過程當中阻塞後續的PutAppend請求,直到handler從新獲取了寫鎖
    • 爲何使用RWMutex : RWMutex在和咱們的行爲要求吻合,容許多個goroutines獲取某種狀態(RLock).容許在一個goroutines釋放(Unlock)後喚醒等待的goroutines.此時配合着同步管道handler goroutine恢復執行,從新設置狀態(Lock)後開始新一輪的處理網絡

    • handler須要注意什麼 :
      • Server在退出時執行Unlock操做,釋放被阻塞的PutAppend並將其結果設置爲NotPrimary
  • Other :
    • 全部RPC操做都應該在失敗狀態後從新獲取本地視圖(我經過atomic.Value來實現的無鎖)
相關文章
相關標籤/搜索