[TOC]
## 2、分布式從ACID、CAP、BASE的理論推進
? 分布式實際上就是單一的本地一體解決方案,在硬件或者資源上不夠業務需求,而采取的一種分散式多節點,可以擴容資源的一種解決思路。它研究如何把一個需要非常巨大的計算能力才能解決的問題分成許多小的部分,然后把這些部分分配給多個計算機進行處理,最后把這些計算結果綜合起來得到最終的結果。
? 那么在了解分布式之前,我們應該從一體式的構造開始說明。
### 一、從本地事務到分布式理論
理解分布式之前,需要理解一個問題就是"事務"
> 事務提供一種機制將一個活動涉及的所有操作納入到一個不可分割的執行單元,組成事務的所有操作只有在所有操作均能正常執行的情況下方能提交,只要其中任一操作執行失敗,都將導致整個事務的回滾。
簡單地說,事務提供一種“ **要么什么都不做,要么做全套(All or Nothing)**”機制。

### 二、ACID理論
? 事務是基于數據進行操作,需要保證事務的數據通常存儲在數據庫中,所以介紹到事務,就不得不介紹數據庫事務的`ACID`特性,指數據庫事務正確執行的四個基本特性的縮寫。包含:
* **原子性(Atomicity)**
* **一致性(Consistency)**
* **隔離性(Isolation)**
* **持久性(Durability)**
#### (1) **原子性(Atomicity)**
? 整個事務中的所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個環節。

例如:銀行轉賬,從A賬戶轉100元至B賬戶:
A、從A賬戶取100元
B、存入100元至B賬戶。 這兩步要么一起完成,要么一起不完成,如果只完成第一步,第二步失敗,錢會莫名其妙少了100元。
#### (2) **一致性(Consistency)**
在事務開始之前和事務結束以后,數據庫數據的一致性約束沒有被破壞。

例如:現有完整性約束A+B=100,如果一個事務改變了A,那么必須得改變B,使得事務結束后依然滿足A+B=100,否則事務失敗。
#### (3) **隔離性(Isolation)**
? 數據庫允許多個并發事務同時對數據進行讀寫和修改的能力,如果一個事務要訪問的數據正在被另外一個事務修改,只要另外一個事務未提交,它所訪問的數據就不受未提交事務的影響。隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
例如:現有有個交易是從A賬戶轉100元至B賬戶,在這個交易事務還未完成的情況下,如果此時B查詢自己的賬戶,是看不到新增加的100元的。
#### (4) **持久性(Durability)**
? 事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
? 本地事務ACID實際上可用”統一提交,失敗回滾“幾個字總結,嚴格保證了同一事務內數據的一致性!
而分布式事務不能實現這種`ACID`。因為有CAP理論約束。接下來我們來了解一下,分布式中是如何保證以上特性的,那么就有了一個著名的CAP理論。
---
### 三、CAP理論
? 在設計一個大規模可擴放的網絡服務時候會遇到三個特性:一致性(consistency)、可用性(Availability)、分區容錯(partition-tolerance)都需要的情景.
? CAP定律說的是在一個分布式計算機系統中,一致性,可用性和分區容錯性這三種保證無法同時得到滿足,最多滿足兩個。

? 如上圖,CAP的三種特性只能同時滿足兩個。而且在不同的兩兩組合,也有一些成熟的分布式產品。
接下來,我們來介紹一下CAP的三種特性,我們采用一個應用場景來分析CAP中的每個特點的含義。

該場景整體分為5個流程:
流程一、客戶端發送請求(如:添加訂單、修改訂單、刪除訂單)
流程二、Web業務層處理業務,并修改存儲成數據信息
流程三、存儲層內部Master與Backup的數據同步
流程四、Web業務層從存儲層取出數據
流程五、Web業務層返回數據給客戶端
#### (1) 一致性Consistency
> “`all nodes see the same data at the same time`”
一旦數據更新完成并成功返回客戶端后,那么分布式系統中所有節點在同一時間的數據完全一致。
> 在CAP的一致性中還包括強一致性、弱一致性、最終一致性等級別,稍后我們在后續章節介紹。
一致性是指寫操作后的讀操作可以讀取到最新的數據狀態,當數據分布在多個節點上,從任意結點讀取到的數據都是最新的狀態。
##### 一致性實現目標:
* Web業務層向主Master寫數據庫成功,從Backup讀數據也成功。

* Web業務層向主Master讀數據庫失敗,從Backup讀數據也失敗。

##### 必要實現流程:

寫入主數據庫后,在向從數據庫同步期間要將從數據庫鎖定,待同步完成后再釋放鎖,以免在新數據寫入成功后,向從數據庫查詢到舊的數據。
##### 分布式一致性特點:
1. 由于存在數據同步的過程,寫操作的響應會有一定的延遲。
2. 為了保證數據一致性會對資源暫時鎖定,待數據同步完成釋放鎖定資源。
3. 如果請求數據同步失敗的結點則會返回錯誤信息,一定不會返回舊數據。
#### (2) 可用性(Availability)
> “`Reads and writes always succeed`”
服務一直可用,而且是正常響應時間。
對于可用性的衡量標準如下:
| 可用性分類 | 可用水平(%) | 一年中可容忍停機時間 |
| :--------------------------- | :------------ | :------------------- |
| 容錯可用性 | 99.9999 | <1 min |
| 極高可用性 | 99.999 | <5 min |
| 具有故障自動恢復能力的可用性 | 99.99 | <53 min |
| 高可用性 | 99.9 | <8.8h |
| 商品可用性 | 99 | <43.8 min |
##### 可用性實現目標:
* 當Master正在被更新,Backup數據庫接收到數據查詢的請求則立即能夠響應數據查詢結果。
* backup數據庫不允許出現響應超時或響應錯誤。

##### 必要實現流程:

1. 寫入Master主數據庫后要將數據同步到從數據庫。
2. 由于要保證Backup從數據庫的可用性,不可將Backup從數據庫中的資源進行鎖定。
3. 即時數據還沒有同步過來,從數據庫也要返回要查詢的數據,哪怕是舊數據/或者默認數據,但不能返回錯誤或響應超時。
##### 分布式可用性特點:
所有請求都有響應,且不會出現響應超時或響應錯誤。
#### (3) 分區容錯性(Partition tolerance)
> “`the system continues to operate despite arbitrary message loss or failure of part of the system`”
分布式系統中,盡管部分節點出現任何消息丟失或者故障,系統應繼續運行。
通常分布式系統的各各結點部署在不同的子網,這就是網絡分區,不可避免的會出現由于網絡問題而導致結點之間通信失敗,此時仍可對外提供服務。
##### 分區容錯性實現目標:
* 主數據庫向從數據庫同步數據失敗不影響讀寫操作。

* 其一個結點掛掉不影響另一個結點對外提供服務。

##### 必要實現流程:
1. 盡量使用異步取代同步操作,例如使用異步方式將數據從主數據庫同步到從數據,這樣結點之間能有效的實現松耦合。
2. 添加Backup從數據庫結點,其中一個Backup從結點掛掉其它Backup從結點提供服務。

##### 分區容錯性特點:
分區容忍性分是布式系統具備的基本能力。
### 四、CAP的”3選2“證明
#### (1) 基本場景
在小結中,我們主要介紹CAP的理論為什么不能夠3個特性同時滿足。

如上圖,是我們證明CAP的基本場景,分布式網絡中有兩個節點Host1和Host2,他們之間網絡可以連通,Host1中運行Process1程序和對應的數據庫Data,Host2中運行Process2程序和對應數據庫Data。
#### (2) CAP特性
`如果滿足一致性(C)`:那么`Data(0) = Data(0)`.
`如果滿足可用性(A)`: 用戶不管請求Host1或Host2,都會立刻響應結果。
`如果滿足分區容錯性(P)`: Host1或Host2有一方脫離系統(故障), 都不會影響Host1和Host2彼此之間正常運作。
#### (3) 分布式系統正常運行流程

如上圖,是分布式系統正常運轉的流程。
A、用戶向`Host1`主機請求數據更新,程序`Process1`更新數據庫`Data(0)`為`Data(1)`
B、分布式系統將數據進行同步操作,將`Host1`中的`Data(1)`同步的`Host2`中``Data(0)`,使`Host2`中的數據也變為`Data(1)`
C、當用戶請求主機`Host2`時,則`Process2`則響應最新的`Data(1)`數據
根據CAP的特性:
* `Host1`和`Host2`的數據庫`Data`之間的數據是否一樣為一致性(C)
* 用戶對`Host1`和`Host2`的請求響應為可用性(A)
* `Host1`和`Host2`之間的各自網絡環境為分區容錯性(P)
當前是一個正常運作的流程,目前CAP三個特性可以同時滿足,也是一個`理想狀態`,但是實際應用場景中,發生錯誤在所難免,那么如果發生錯誤CAP是否能同時滿足,或者該如何取舍?
---
#### (4) 分布式系統異常運行流程
假設`Host1`和`Host2`之間的網絡斷開了,我們要支持這種網絡異常,相當于要滿足`分區容錯性(P)`,能不能同時滿足`一致性(C)`和`可用響應性(A)`呢?

假設在N1和N2之間網絡斷開的時候,
A、用戶向`Host1`發送數據更新請求,那`Host1`中的數據`Data(0)`將被更新為`Data(1)`
B、弱此時`Host1`和`Host2`網絡是斷開的,所以分布式系統同步操作將失敗,`Host2`中的數據依舊是`Data(0)`
C、有用戶向`Host2`發送數據讀取請求,由于數據還沒有進行同步,`Process2`沒辦法立即給用戶返回最新的數據V1,那么將面臨兩個選擇。
第一,犧牲`數據一致性(c)`,響應舊的數據`Data(0)`給用戶;
第二,犧牲`可用性(A)`,阻塞等待,直到網絡連接恢復,數據同步完成之后,再給用戶響應最新的數據`Data(1)`。
這個過程,證明了要滿足`分區容錯性(p)`的分布式系統,只能在`一致性(C)`和`可用性(A)`兩者中,選擇其中一個。
#### (5) "3選2"的必然性
通過CAP理論,我們知道無法同時滿足`一致性`、`可用性`和`分區容錯性`這三個特性,那要舍棄哪個呢?
##### CA 放棄 P:
一個分布式系統中,不可能存在不滿足P,放棄`分區容錯性(p)`,即不進行分區,不考慮由于網絡不通或結點掛掉的問題,則可以實現一致性和可用性。那么系統將不是一個標準的分布式系統。我們最常用的關系型數據就滿足了CA,如下:

主數據庫和從數據庫中間不再進行數據同步,數據庫可以響應每次的查詢請求,通過事務(原子性操作)隔離級別實現每個查詢請求都可以返回最新的數據。
注意:
> 對于一個分布式系統來說。P是一個基本要求,CAP三者中,只能在CA兩者之間做權衡,并且要想盡辦法提升P。
##### CP 放棄 A
如果一個分布式系統不要求強的可用性,即容許系統停機或者長時間無響應的話,就可以在CAP三者中保障CP而舍棄A。
放棄可用性,追求一致性和分區容錯性,如Redis、HBase等,還有分布式系統中常用的Zookeeper也是在CAP三者之中選擇優先保證CP的。
<u>場景:</u>
跨行轉賬,一次轉賬請求要等待雙方銀行系統都完成整個事務才算完成。
##### AP 放棄 C
放棄一致性,追求分區容忍性和可用性。這是很多分布式系統設計時的選擇。實現AP,前提是只要用戶可以接受所查詢的到數據在一定時間內不是最新的即可。
通常實現AP都會保證最終一致性,后面講的BASE理論就是根據AP來擴展的。
<u>場景1:</u>
淘寶訂單退款。今日退款成功,明日賬戶到賬,只要用戶可以接受在一定時間內到賬即可。
<u>場景2:</u>
12306的買票。都是在可用性和一致性之間舍棄了一致性而選擇可用性。
你在12306買票的時候肯定遇到過這種場景,當你購買的時候提示你是有票的(但是可能實際已經沒票了),你也正常的去輸入驗證碼,下單了。但是過了一會系統提示你下單失敗,余票不足。這其實就是先在可用性方面保證系統可以正常的服務,然后在數據的一致性方面做了些犧牲,會影響一些用戶體驗,但是也不至于造成用戶流程的嚴重阻塞。
但是,我們說很多網站犧牲了一致性,選擇了可用性,這其實也不準確的。就比如上面的買票的例子,其實舍棄的只是強一致性。退而求其次保證了最終一致性。也就是說,雖然下單的瞬間,關于車票的庫存可能存在數據不一致的情況,但是過了一段時間,還是要保證最終一致性的。
#### (6) 總結:
> CA 放棄 P:如果不要求P(不允許分區),則C(強一致性)和A(可用性)是可以保證的。這樣分區將永遠不會存在,因此CA的系統更多的是允許分區后各子系統依然保持CA。
> CP 放棄 A:如果不要求A(可用),相當于每個請求都需要在Server之間強一致,而P(分區)會導致同步時間無限延長,如此CP也是可以保證的。很多傳統的數據庫分布式事務都屬于這種模式。
> AP 放棄 C:要高可用并允許分區,則需放棄一致性。一旦分區發生,節點之間可能會失去聯系,為了高可用,每個節點只能用本地數據提供服務,而這樣會導致全局數據的不一致性。現在眾多的NoSQL都屬于此類。
### 五、思考
#### 思考:按照CAP理論如何設計一個電商系統?
- 首先個電商網站核心模塊有**用戶,訂單,商品,支付,促銷管理**等
> 1、對于用戶模塊,包括登錄,個人設置,個人訂單,購物車,收藏夾等,這些模塊保證AP,數據短時間不一致不影響使用。
> 2、訂單模塊的下單付款扣減庫存操作是整個系統的核心,CA都需要保證,極端情況下面犧牲A保證C
> 3、商品模塊的商品上下架和庫存管理保證CP
> 4、搜索功能因為本身就不是實時性非常高的模塊,所以保證AP就可以了。
> 5、促銷是短時間的數據不一致,結果就是優惠信息看不到,但是已有的優惠要保證可用,而且優惠可以提前預計算,所以可以保證AP。
> 6、支付這一塊是獨立的系統,或者使用第三方的支付寶,微信。其實CAP是由第三方來保證的,支付系統是一個對CAP要求極高的系統,C是必須要保證的,AP中A相對更重要,不能因為分區,導致所有人都不能支付
### 六、分布式BASE理論
? CAP 不可能同時滿足,而`分區容錯性(P)`是對于分布式系統而言是必須的。如果系統能夠同時實現 CAP 是再好不過的了,所以出現了 BASE 理論。
#### (1) BASE理論
> 通用定義
BASE是**Basically Available(基本可用)**、**Soft state(軟狀態)**和**Eventually consistent(最終一致性)**三個短語的簡寫。
BASE是對CAP中一致性和可用性權衡的結果,其來源于對大規模互聯網系統分布式實踐的總結,是**基于CAP定理逐步演化**而來的,其核心思想是即使無法做到強一致性,但每個應用都可以根據自身的業務特點,采用適當的方法來使系統達到**最終一致性**。
> 兩個對沖理念:ACID和BASE
`ACID`是傳統數據庫常用的設計理念,`追求強一致性`模型。
`BASE`支持的是大型分布式系統,提出通過`犧牲強一致性`獲得`高可用性`。
#### (2) Basically Available(基本可用)
實際上就是兩個妥協。
* 對響應上時間的妥協:正常情況下,一個在線搜索引擎需要在0.5秒之內返回給用戶相應的查詢結果,但由于出現故障(比如系統部分機房發生斷電或斷網故障),查詢結果的響應時間增加到了1~2秒。
* 對功能損失的妥協:正常情況下,在一個電子商務網站(比如淘寶)上購物,消費者幾乎能夠順利地完成每一筆訂單。但在一些節日大促購物高峰的時候(比如雙十一、雙十二),由于消費者的購物行為激增,為了保護系統的穩定性(或者保證一致性),部分消費者可能會被引導到一個降級頁面,如下:

#### (3) Soft state(軟狀態)
- 原子性(硬狀態) -> 要求多個節點的數據副本都是一致的,這是一種"硬狀態"

- 軟狀態(弱狀態) -> 允許系統中的數據存在中間狀態,并認為該狀態不影響系統的整體可用性,即允許系統在多個不同節點的數據副本存在數據延遲。

#### (4) Eventually consistent(最終一致性)
上面說軟狀態,然后不可能一直是軟狀態,必須有個時間期限。在期限過后,應當保證所有副本保持數據一致性。從而達到數據的最終一致性。這個時間期限取決于網絡延時,系統負載,數據復制方案設計等等因素。

稍微官方一點的說法就是:
> 系統能夠保證在沒有其他新的更新操作的情況下,數據最終一定能夠達到一致的狀態,因此所有客戶端對系統的數據訪問最終都能夠獲取到最新的值。
#### (5) BASE總結
總的來說,BASE 理論面向的是大型高可用可擴展的分布式系統,和傳統事務的 ACID 是**相反的**,它完全不同于 ACID 的強一致性模型,而是**通過犧牲強一致性**來獲得可用性,并允許數據在一段時間是不一致的。
參考:
https://blog.csdn.net/weixin_44062339/article/details/99710968
https://blog.csdn.net/w372426096/article/details/80437198
https://www.solves.com.cn/it/cxkf/bk/2019-09-24/5229.html
https://www.jianshu.com/p/46b90dfc7c90
https://www.jianshu.com/p/9cb2a6fa4e0e
https://www.jianshu.com/p/68c7c16b3fbd
- 封面
- 第一篇:Golang修養必經之路
- 1、最常用的調試 golang 的 bug 以及性能問題的實踐方法?
- 2、Golang的協程調度器原理及GMP設計思想?
- 3、Golang中逃逸現象, 變量“何時棧?何時堆?”
- 4、Golang中make與new有何區別?
- 5、Golang三色標記+混合寫屏障GC模式全分析
- 6、面向對象的編程思維理解interface
- 7、Golang中的Defer必掌握的7知識點
- 8、精通Golang項目依賴Go modules
- 9、一站式精通Golang內存管理
- 第二篇:Golang面試之路
- 1、數據定義
- 2、數組和切片
- 3、Map
- 4、interface
- 5、channel
- 6、WaitGroup
- 第三篇、Golang編程設計與通用之路
- 1、流?I/O操作?阻塞?epoll?
- 2、分布式從ACID、CAP、BASE的理論推進
- 3、對于操作系統而言進程、線程以及Goroutine協程的區別
- 4、Go是否可以無限go? 如何限定數量?
- 5、單點Server的N種并發模型匯總
- 6、TCP中TIME_WAIT狀態意義詳解
- 7、動態保活Worker工作池設計