---
# System prepended metadata

title: 1-4 Weighted Voting for Replicated Data

---

# 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)

