---
# System prepended metadata

title: 2-4 The Potential Dangers of Causal Consistency and an Explicit Solution

---

# 2-4 The Potential Dangers of Causal Consistency and an Explicit Solution

## Introduction
- 此篇論文說明 Casual Consistency 的系統為何在擴展性上會有問題，以及對於現今龐大的系統，要如何應對複雜的因果關係，而持續保持因果一致性

## Casual Consistency
- 保證結果一定在原因發生後才發生，以下情境，操作 a b c 是有因果關係存在
    1. Lewis 在留言 "Jenny在醫院處於無意識狀態" -> 操作a
    2. Jenny 醒來，Lewis 更新留言 "Jenny 終於醒來了" -> 操作b
    3. Mary 看到 Jenny 醒來的消息，留言 "真是太好了<b>(What terrific news!)</b>" -> 操作c
    
    - 假如不存在因果一致性，其他使用者有可能只看到 操作a 和 操作c，認為 Mary 在咒罵 Jenny

### 定義
- 每個 agent (我認為是意指 process) 讀到的資料版本有一定的順序，而這些資料版本遵守 `happens-before` 這個特性，用 $\rightarrow$ 表示
    - 假如一個資料有 v1 $\rightarrow$ v2 $\rightarrow$ v3 的版本變化，則一個 agent 做 兩次的 read 有可能先獲得 v1，再來是v3。v3 絕對不可能比 v1, v2 早讀出來。

- `happens-before` 是根據潛在因果關係 (`potential causality`) 決定出來的，而潛在因果關係反映了 3 種特性
    - 操作順序的一致性，先操作 a 再 b，a $\rightarrow$ b
    - 讀取出 b 的這個結果，是因為原先寫入 a，a $\rightarrow$ b，此種 write 也叫做 `casual history`
    - 遞移性，先 a 再 b，a $\rightarrow$ b；然後再先 b 再 c，b $\rightarrow$ c，a $\rightarrow$ c

- 收斂的因果一致性 (convergent causal consistency)
    - 當更新停止時，所有的 agent 在`最終`都會讀取到相同的值

### 步驟
- 每個 agent 在其本地紀錄一系列的寫行為，當遠端有一個寫行為要進來時，agent 需檢查與這個寫行為有相關的所有寫行為必須完成，agent 才能夠允許這個寫行為寫入本地。否則就持續等待直到其依賴的所有寫行為完成。
    - 今天有一系列行為是 w1 -> w2 -> w3，某一 agent 收到了 w1, w3
    - w1 可成功寫入，但 w3 須等到 w2 完成，w3 才可以進行

### 為什麼要等待
- 一個例子: Mary "喜歡" Greenpeace。 
- "喜歡"有這樣的一個關係: `使用者ID` <-> `公司ID`。而 `使用者ID` 對於使用者表也有關聯， `公司ID` 對於公司表也有關聯
- 因此在更新這樣的一個狀態會有 3 個寫動作
    - 查找使用者對應 ID，並把 ID 寫入狀態裡的 `使用者ID` : w1
    - 查找公司對應 ID，並把 ID 寫入狀態裡的 `公司ID` : w2
    - 最終把這關係寫入 : w3
    - 有這樣的關聯: w1 -> w3 ; w2 -> w3
- 假如在 "Greenpeace" 找到其 `公司ID` 之前，就做了狀態寫入，就會變只傳 `{Mary的使用者ID}` <-> `{空的}`
- 我們必須等待 "Greenpeace" 找到其 ID，才能做狀態更新，但這只是暫時性的，因為我們相信公司ID最終一定會回傳回來

### 實作等待
- 當在做寫入時，會先有一個 agent 寫入，並通知其他 agents
- 此時其他 agent 會先 buffer 這個寫入，因為他們每個要確定這個 write 的之前所有關聯 write 都已經正確寫入，他才能把這個新的 write 寫入
- 於現實生活的資料中心，每個資料中心就是一個 agent。
- 雖然資料中心裡頭有很多伺服器，但因為是本地網路，這些伺服器的延遲很低，可以採用 strong consistency 來管理。

## 拓展 Casual Consistency 的潛在危險
### 吞吐量以及可見性延遲 (Throughput and Visibility Latency)
- 可見性延遲
    - 某個 write 因為其 dependency 還沒寫入，而持續卡住，也代表這個寫入還無法被使用者看到，這段時間就是可見性延遲
    - - 與網路延遲以及 dependency checking 的速度(apply-capacity)有關
- apply-capacity
    - 一個 data center 做 dependency checking 的速度
- 吞吐量
    - 整體系統單位時間內產生寫入行為的數量
    - 全局吞吐量就被受限於 apply-capacity 最小的那個 data center，因為因果一致性須確保所有的 data center 在最終都會有一樣的值 (convergent)
- 在 apply-capacity 固定的情況下
    - 吞吐量高，可見性延遲就會長；反之相反

### 在因果一致性的情況下拓展 data centers
- data center 的處理速度會被受限於最慢的一個 (論文的舉例讓我很困惑 點點點)
    - 假設 data center 的 apply capacity 是 A，為了避免 data center 因為過多的寫入行為，而導致需排隊一直等待 dependency checking，因此不能讓全域吞吐量超過 A
    - 今次有兩個 apply capacity 都是 A 的 data center，我們可以平分整個系統產生的吞吐量，因此每個 data center 處理的速度是 A/2
    - N個 data center 就是 A/N，但整個系統的吞吐量還是只能處理 A
    - 而且假如有 data center 處理速度較慢，大家都必須配合他維持相同的速度，造成全域吞吐量降低
- 一個 data center 的 apply-capacity 會與 data center 數量成正比
    - 假如每個 data center 產生的吞吐量為 1K
    - 只有 1 個 data center，全域吞吐量為 1K，data center apply-capacity 為 1K
    - 有 2 個 data center，全域吞吐量為 2K，每個 data center 的 apply-capacity 也必須升級為 2K
    - 有 3 個 data center，每個 data center 的 apply capacity 升級為 3K
    - 原有的 2 個 data center，從 2K 升級成 3K => (3-2)/2 = 50%
    - 新的 data center 因為本來沒有，需額外增加，而一加進來的 apply capacity 須是 3K => 3/(2+2) = 75%
    - 全域吞吐量從 2K 變 3K => (3-2)/3 = 33%
    - 需要升級 data center 的效能 50+75=125%，整個系統的處理量卻只增加 33%
:::warning
在因果一致性下，處理速度會受限於最慢的實體。並且越多的實體，每個實體的效能也要增加
:::

### 過度複雜的關係依賴圖
- 在龐大的因果一致性系統，潛在的因果關係影響的深度很遠，導致 dependency check 會變得很久
    - 假如一個使用在滑過 10 個貼文後留言，這 10 個貼文跟這個留言就有潛在的因果關係
    - 每個貼文背後可能又是因為其他貼文，因果關係無窮無盡
:::warning
檢查 potentail casuality 導致 apply-capacity 降低，進而影響全域吞吐量
:::

- 也許加入一個 "stable version" 來確定其背後的 dependency 都有寫入了，就可以免除 dependency check 的過程，但是
    1. 只要有分區，stable version 就會不一樣，只能等待分區問題解決
    2. datacenters may slow in applying new versions, in turn decreasing the rate of stabilization. (?)

## Explict Casaulity
- 比起追蹤所有的潛在因果關係，何不追蹤最有關係的那個(Explict Casaulity)即可
    - A 喜歡 B 的貼文，雖然 B 的貼文背後可能又有很多因果關係，但 A 最主要是只跟 B 的貼文有強烈關係
- 改成只追蹤 Explict Casaulity 
    - 關係依賴圖將變得簡單且淺層，而且可能會產生多個不交集關係圖，進而可以平行地做 dependency check 以及 write
    - 大幅降低 dependency check 的次數，進而改善 apply capacity 以及 total global throughput
- 此種關係通常從應用層即可知道
    - 應用程式要寫入 "A 喜歡 B 的貼文" 的狀態，就有: "B 貼文" $\rightarrow$ "A 喜歡 B 的貼文" 的關係
    - 我們不須再透過資料庫層，去看 B 的貼文背後還有哪些因果關係，因為我們只在乎 "A 喜歡 B 的貼文" 這件事
    - 只是此種關係的定義就必須讓程式撰寫者去撰寫
- 與潛在因果關係的比較
    - 潛在因果關係通常只會在資料庫層連結，並是使用"物理性"的特性紀錄，像是收發時間
    - Explict Casaulity 使用應用層 API 即可傳遞關係，且通常是易於理解的
- 限制
    1. 使用者可以繞過此種關係
        - A 告訴 B "你一定要看看這些照片"，會有這樣的關係: "照片 object" $\rightarrow$ "你一定要看看這些照片"
        - 但單從這句話無法知道照片是指哪些照片
        - 因此要有對應的機制去修補這樣的因果關係
    2. 在不知道應用的 domain knowledge 之前，Explict Casaulity 很難判斷