# 1-4 Weighted Voting for Replicated Data ## Introduction - Replication data 可以讓資料就近存取,也增加了資料的可用性 (availability),也增加可靠度 (reliability),如何有效管理副本顯得特別重要 - 本篇論文所提出的演算法概念如下 - 對於每個副本給與一些票數 - 對於每筆 transaction,他會一個一個累加 representative (副本)的票數,並收集這些副本,直到能超過 r/w 票數門檻,而這些副本便是我們 read/write quorum (候選人) - r 跟 w 有一個限制, r+w > v,v也就是所有 representative 的票數總和 - 運用鴿籠原理可知, read quorum 跟 write quorum 一定至少有一個是重複的 - 收集的 read quorum 一定有一個是最新版本的 - 一定會有一群票數總和加起來為 w 的 representative 是最新版本的 - 簡單說明如下 - 假如有3個副本,每個副本各1票 - r+w > v => r 和 w 設為 2 - 要讀必須讀兩個副本,要寫也要寫兩個副本 - 必定會有一個是重複的,而該重複的也會是最新版本 - 本演算法帶來的優點 - 就算有 node 壞掉,r/w 門檻有過還是可以進行 - 不需要複雜的檔案通訊機制? (It consists of a small amount of extra machinery that nlllS on top of a transactional file system. Although "voting" occurs as will become evident later in the paper, no complicated 11lessage based coordination mechanisms are needed.) - 符合 serial consistency,多個 transaction 看起來就像 sequential 進行,每次都能夠有最新版本給使用者 - r, w 和 每個 representative 的票數可以依據系統 / node 需求 (performance / reliability)客製設定 - 任何的副本都可以應用此演算法,包含本地暫存副本(快取)也是 - 演算法介紹是使用 Mesa 程式語言盡進行 ## Other Works - 在當時,分散式系統被歸納為兩類 - 有一個 primary site 進行版本更新,其餘 node 為儲存副本用 - 將所有 node 的版本都更新,如 SDD-1 是透過一個複雜的通訊機制來維護各副本的版本 :::info - 在進入演算法介紹前,簡單化假設 (其實好像也沒很重要) - 即使在不同機器上,任意物件(包含後面介紹的 class )被初始化後都有獨立的名字 - 所有機器上的 file system 底層運作方式一樣 ::: ## 基本物件 & 環境認識 - Files - bytes of array ![image](https://hackmd.io/_uploads/B1cSVit6a.png) - Containers - files 的存放處 - 例如: 硬碟 磁碟 - Transactions - 一系列的 Files 操作 - 由 begin 和 commit 包起來,commit 後,transaction 的行為才成立 ![image](https://hackmd.io/_uploads/BJVirsKTp.png) - ACID (沒有C): - 論文本身並沒有直接點名就是 DB 的 ACID 概念,有可能只是剛好符合 - 保證所有的寫行為都有成功,不然就是沒有任何一個成功,二選一 (Atomicity) - Serial Consistency (Isolation) - 一個完成的 transactions ,不會被硬體損壞受影響 (Durability) - 假如要對多個副本進行讀/寫行為,可以平行處理 (fork process 做事情),而 Forked process 可以透過這個回歸 parent process。 ![image](https://hackmd.io/_uploads/H1ZlcstT6.png) - 使用者手動放棄、電腦壞掉、通訊錯誤或是 lock conflict,可以進行 abort (放棄),如此,所有的 write 行為不會計數 ![image](https://hackmd.io/_uploads/Hy3eCotp6.png) - <b>Serial Consistency</b> - 多個 transaction 可能是 concurrent 進行,但是系統/演算法會決定出一個 order,讓其看起來 sequential 進行。 - 就像隱藏了 concurrency - 其餘規則 - 假如讀取的檔案是不可用的,`File.Read` 不會回傳;反之,`File.Write` 也一樣 - 未完成的 read 不影響 transaction 做 commit - 未完成的 write ,transaction 必須完成所有的 write 才能 commit - File Suite - 是一種 abstraction interface - 一個 file 的多個副本集合體。其中副本又被稱作 `representatives`,因為後續演算法是透過投票的方式進行 - 可以想成 - A檔案是一個抽象的檔案介面(File Suite),他本身有很多副本,散落於不同機器或目錄,A_1, A_2... - 但統一都對A檔案操作,而`representatives`有可能是A_1, A_2... - 被創建時要提供以下參數 - r: 判定讀行為成功的最少票數 - w: 判定寫行為成功的最少票數 - v: 存放每個`representatives`的陣列,會記錄每個`representatives`放在哪個 container,以及其所擁有的票數 ![image](https://hackmd.io/_uploads/r178enYpp.png) - 就如同操作一個 file(read, write, update, delete)。但是多了兩個 file 沒有的特徵 1. performance: 延遲性相關 2. reliability: 系統穩定性相關 - 可以針對著重哪個特徵,而對不同`representatives`有票數分配 - high performance -> heavily weighting high performance representatives - very reliable -> heavily weighting reliable representatives, or equally weighted representatives - 當時年代把分散式系統分類為 centralized 以及 decentralized,此篇論文表示此演算法兩者皆通 (呼應前面 related work 說的) - <b>decentralized structure</b> -> equally weighting representatives - <b>centralized structure</b> -> assigning of all of the votes to one representative - 可以針對應用的特性,像是 讀寫比、行為的成本 或是 期望的 reliability 以及 performance,設定不同的 r, w。 - r/w 低,(operation的)讀/寫 reliability 以及 performance 增加 - 不是指 data,是指 operation - 門檻低,很快就決定出 quorum (performance) - 門檻低,不會因為到不了門檻導致 operation 失敗 (reliability) ## 核心演算法 ### FileSuite - 初始化 - FileSuite 是透過 Monitor (OS 教過 Monitor) 實作出來的 - 對於 shared data 的操作會上 lock - FileSuite 會記錄以下資訊 1. suite: SuiteEntry 的陣列 - SuiteEntry紀錄每個`representatives`的名字、版本和票數 2. r 和 w 的設定 ![image](https://hackmd.io/_uploads/SksNuJ9Ta.png) - Read - 首先聚集特定數量的 <u>讀候選人</u> - 從這些 <u>讀候選人</u>中,通常是選擇可以反應最快的(延遲低) ![image](https://hackmd.io/_uploads/SkFZoJc6T.png) - Write - 首先聚集特定數量的 <u>寫候選人</u> - 在寫之前,每個<u>寫候選人</u>的版本必須是最新的,確保不會寫到過時的候選人 - 可平行地寫入每個候選人 (演算法用fork) :::info - 於演算法中 - quorum 是 Set,在上面 FileSuite 資料結構裡有寫到是 boolean array - suite 是多個 `representative` 的陣列 - for 迴圈整個 suite,並查看該 index 的 quorum 是不是 true,來得知是不是候選人 ::: ![image](https://hackmd.io/_uploads/HyV-oiq6T.png) ### 版本查詢 - 在上述 read / write 可以發現,在收集候選人的時候,演算法一定會確定有正確的版本在這些候選人中。也就是在對 file suite 操作前,會先做各個 representative 的 version 查詢。 - <b>針對每個 representative ,做 version 查詢</b> ![image](https://hackmd.io/_uploads/HJgldmoTp.png) :::info - Inquiry - 針對每個 representative 開始查詢 ::: ![image](https://hackmd.io/_uploads/r1mst7j6p.png) :::info - ReadPrefixInformation - 從 stable file system 讀取各 representative 的 version 還有投票規則 (Paper Figure 1) - 回傳的值作為參數傳給 `NewRepresentative` ::: ![image](https://hackmd.io/_uploads/ryQkqXiap.png) :::info - NewRepresentative - 更新 representative 的 version - 同時如果發現有 representative 的 version 是最新的,將其 voting rule 更新給 file suite ::: ![image](https://hackmd.io/_uploads/B1hncXoTT.png) ### 候選人收集 - 剛剛的 version 查詢,在確定 voting rule 是最新的之後,便會進入收集環節 - CrowdLarger 是一個 Condition variable (詳見 Monitor 介紹),是 lock 的一種。在剛剛的更新完成後,便會 unlock - Read - 除非有任一個 representative 更新了投票規則,否則持續等待 CrowdLarger - 對應演算法裡註解`-- until the first representative responds we don't have a seedfor the voting rules` - 對應內文的第一個 potential problem: `it is possible that a read quorum of the suite's representatives have not reported their version numbers.` - Collector 會選擇延遲低的 representative 當作 quorum,增進 performance - 對應演算法裡 function `SortRepresentativesBySpeed[];` - 開始累加票數,值至超過最新 voting rule 裡的 r quorum 門檻 - 回傳 quorum (boolean array),代表哪幾個 representative 是候選人 ![image](https://hackmd.io/_uploads/SkovlIs6a.png) - Write - 同前面 read 操作,會選擇延遲低的當作 quorum,並且持續累積票數,值至超過最新 voting rule 裡的 w quorum 門檻 - 特別注意的是,多了一個 condition <u>`IF suite[j].versionNumber = current`</u>,呼應前面說的寫候選人版本要是最新的 - 假如 r < w,可以相信 read quorum 已經比 write quorum 早收集完成,假如 write quorum 因為沒有夠多的 current version representative 可以加入,那就可以透過 read quorum 得知 current version,並先行更新過時的 representative,如此 loop 回去找 write quorum 時,便可收集足夠多的 write quorum - r >= w 呢? 就只能一直 loop 直到足夠多的 write quorum ![image](https://hackmd.io/_uploads/Sy6B3Ij6p.png) ![image](https://hackmd.io/_uploads/Bkj83IsT6.png) :::warning - 處理 r < w 的狀況如下 ::: ![image](https://hackmd.io/_uploads/SyL_nLj6a.png) ### 中斷行為 - 使用者中斷或是遭遇系統中斷,file suite的狀態就不完整,包含投票規則、各 representative 的狀態都應該被放棄不再被使用,就是直接設為空值(第一個紅框),並且等待下次版本查詢再重新替換狀態(第二個紅框) ![image](https://hackmd.io/_uploads/S1D11viTT.png) ![image](https://hackmd.io/_uploads/HkuekPoTT.png) ## 改進 ### 1. Weak Representatives (弱代表) - replicate 也可以存為 temporary data 於使用者本地電腦上,並給與 0 票 - 此種 replicate 不是為了 reliability,而是為了 performance,加快反應速度 - 透過上面的收集候選人演算法,temporary data 通常是反應最快的(因為存於使用者電腦上),而且因為 0 票,也會被納入候選人列表 - 以下例子為例: - 高讀寫比環境,一個 server(75ms 延遲),多使用者(使用者本地電腦 65ms 延遲) - representative 1 是 server 上的副本,2跟3是兩個使用者暫存在各自電腦的副本 - 前面有說累積票數要大於等於r/w,因此 quorum 便會有本地副本以及 server 上的副本 - 讀的話會選擇延遲低的,因此本地副本先行存取,因此底下延遲標示 65ms - 寫的話因為每個每個 write quorum 都要寫,因此取延遲最大的 representative 1 ![image](https://hackmd.io/_uploads/Hk_wXwna6.png) ### 2. Lock compatibility - 修改原有 lock 的規則,增進系統的 concurrency - 原有的 lock 規則 - No lock 就任何行為都可以做 - Read lock 只允許不做事或讀而已 - Write lock 只允許不做是 - 雖然 read 可以很多人同時讀,但 writer 只能有一個 - 給 write lock 一個 time out,讓 writer不能霸佔太久,是一個暫時性解法。後續會提到此解法不合適 ![image](https://hackmd.io/_uploads/HkZuOwhap.png) - 改過的 lock 規則 - 一個 transaction 中,所有的 write 是在 commit time 才發生的,commit time 之前其實只是處理在 buffer 中而已 - 透過這個特性,將 write lock 拆成兩個: I-Write, Commit - 當使用者正在新增資料時(原文使用 datum,不知跟 data 差在哪),I-Write 會上鎖,代表有意圖寫入 - 有意圖寫入,但還沒真的寫進去,reader 還是可以先讀舊資料 - 確定寫入後,轉為 Commit,直到 commit 結束並解鎖 - commit時,資料正在更新,不能讓使用者繼續讀舊資料 ![image](https://hackmd.io/_uploads/B1d7qvhTp.png) ### 3. Lower Degrees of Consistency - Degrees of Consistency,於 `Granularity of Locks and Degrees of Consistency in a Shared Data Base` 有說明各 degree 的標準 - 簡單思考可以想成,degree 越高,consistency 越強 - 假如有一個應用,只是單純提高 performance,或是他有額外的版本檢查機制,可以單純的把 r 設成 0,就可以利馬回傳任何一個結果,而不管他的版本對不對 ### 4. 最小可複製物件的種類 - 根據應用需求,可能會有不同種的物件做成副本 - 例如 DB ,可能會想複製 relation 或 index - 本演算法要求物件的版本號碼在 transaction 進行時不能被更動,因此最小的種類只能被限定為檔案 - 當一個檔案修改完後,版本後才會變動 ### 5. 打破 read lock - 假如允許強行破壞 read lock,帶來兩個優點 - 可以減少被放棄的 transactions ,如需 commit 的 write transaction ### 6. 重新給與票數 <b>TODO</b> ### 7. 複製 container - 假如使用者A使用 c d 容器,使用者B使用 d e 容器,當d容器下線時,使用者A B 的 transaction 有可能持續進行,也有可能都不能進行,給系統帶來一個不確定性 - 可以複製容器 d 出來,使用者可以把這個複製的容器當作一般容器操作 - 但如果是再複製的容器裡 create file , 他會建立一個 file suite。可以想成複製容器 d 的 d_1, d_2, d_3 .... 也都需要 create file,因此是建立一個這些在複製容器內副本的 file suite - 被複製的容器叫做 base container - 複製容器的幾個優點 - 增加了系統的 avalibility,同時系統也可以知道說 base container 下線後,可以改用 replicate container 進行 - 做到備份的功能 - 這些複製的 container 就算下線了,整體影響也不大 ### 8. 釋放 read lock - 針對版本查詢,因為版本查詢會去查所有 representative 的 version,每查一個,那個就會被上 read lock - 假如確定已經不會在 quorum 裡的 representative,可以先行釋放 read lock,而那些 representative 就可以被 commit 的操作改變 ### 9. Updating Representatives in Background - 可以在 replicated container 上更新舊的 representative,加強 replicated container 的作用 ## 實作 ### Violet :::spoiler 網路架構 ![image](https://hackmd.io/_uploads/rJlbPo_2TT.png) ::: :::spoiler Violet 介面 ![image](https://hackmd.io/_uploads/BypFi_nT6.png) ::: - Violet 是一個分散式的日曆系統 - 其背後用的檔案系統叫做 `DFS`,是一種 transactional file system - Transactional File System 代表他是用 transaction (前面有提到)的方式在操作 data - 其餘實作皆依照本篇演算法說明 - 他沒有說明 file suite 是對應到系統的甚麼東西,我猜是行程表 ### lock 問題 - 假如使用的是未改進的鎖規則。B使用者原先正在讀,A使用者要寫東西進去,導致B使用者不能讀,且A使用者一直不 commit (write 上 lock) - 如果用 time out 的方法解 - A使用者寫太久了,導致 time out - A使用者沒寫成功,B使用者也過了很久才看到東西,且兩者的資料都是舊的 - 使用改進的鎖規則 - A使用者有意圖寫,I-Write 上 lock,但這並不阻止B使用者讀 - 直到A使用者寫完了,雖然commit 的短暫時間讓B暫時不能讀,但commit 完後,兩使用者皆呈現新資料 ### 效能 - 展示兩組數據 - 讀/寫次數 - DFS 本身封包來回次數和 delay - DFS 是採用 `three phase commit protocol`,因此針對一個操作,基本上會有 3 次 message 的來回 - 效能圖 - Begin Transaction: 整個 transaction 初始化 - Add Server: 將其餘 server 加入此 transaction 的過程,想成新增其他副本所在伺服器的成本。不太確定為什麼這邊是5 - Inquiries: 演算法的版本查詢,因為每個 representative 都查,因此讀 m 次,並有 3m 次的訊息傳遞 - Read (第一個 read): 因為前面已經做完版本查詢和候選人收集,因此直接讀取回傳最快的 representative,花費讀取一次 - Subsequent Read: 都花費一次讀取 - Subsequent Write: 前面有提到,要寫就要寫給每個最新版本的 quorum,因此每次寫都寫 m 次 - Coordinator: 結束 transaction 的初始化? - Workers: 感覺是把原本操作在 buffer 的東西完整的寫進 file system,對每個 quorum 做一讀一寫,因此 3m+3m ![image](https://hackmd.io/_uploads/rJKCvt2TT.png)