本文主要聊一聊主流開源產品的replication方式。node
replication和partition/sharding是分佈式系統必備的兩種能力。具體詳見複製、分片和路由.
對於海量數據來講,replication一方面能夠增長冗餘,保證系統可用性,一方面還能夠提高讀取的效率。
本文主要聚焦於replication,即假設每一個node都足以存下整個副本。mysql
按照有無leader以及leader數目能夠分爲:redis
具體詳見副本更新策略,主要有以下幾種算法
無中心的複製,能夠分爲三種拓撲結構,環形、星/樹型、網狀拓撲sql
主要分爲如下幾種數據庫
WAL
)PG使用的就是這種。segmentfault
logical log
)通常replication增長冗餘經常使用來作master的的熱備(支持查詢)/溫備(不支持查詢)緩存
一旦replication支持讀取的話,那麼就涉及讀的一致性問題,通常理論上除了強一致外,有這幾種最終一致性:併發
讀取的話,涉及讀己所寫,因果讀(
針對操做有序
)、單調讀(不讀到舊數據
)less
假設某份數據須要複製到3個節點,爲了保證強一致性,不須要全部節點都確認寫入操做,只須要其中兩個節點(也就是超半數節點)確認就能夠了。在這種狀況下,若是發生兩個相互衝突的寫入操做,那麼只有其中一個操做能爲超過半數的節點所承認,這就是寫入仲裁(write quorum),若是用稍微正規一點的方式說,那就是W>N/2,這個不等式的意思是參與寫入操做的節點數W,必須超過副本節點數N的一半,副本節點數又稱爲複製因子(replication factor)。
讀取仲裁(read quorum),也就是說想保證可以讀到最新的數據,必須與多少個節點聯繫才行。假設寫入操做須要兩個節點來確認(W=2),那麼咱們至少得聯繫兩個節點,才能保證獲取到最新數據。然而,假如某些寫入操做只被一個節點所確認(W=1),那麼咱們就必須3個節點都通訊一遍,才能確保獲取到的數據是最新的。一個狀況下,因爲寫入操做沒有得到足夠的節點支持率,因此可能會產生更新衝突。可是,只要從足夠數量的節點中讀出數據,就必定能偵測出此類衝突。所以,即便在寫入操做不具有強一致性的狀況下,也能夠實現除具備強一致性的讀取操做來。
這三者之間的關係,能夠用一個不等式來表述,即只有當R+W>N的時候,才能保證讀取操做的強一致性。
產品 | 複製方式 | 實現方式 | 其餘 |
---|---|---|---|
mysql | 主從半同步 | MySQL 5.0及以前的版本僅支持statement-based的複製,5.1+版本,當有不肯定語句時,就切換爲row-based log replication | 主從延遲處理 |
kafka | 主從ISR半同步 | leader寫入消息並複製到全部follower,ISR中的副本寫入成功返回ack給leader纔算commit成功 | 生產者能夠選擇是否等待ISR的ack |
elasticsearch | 主從半同步,默認replication=sync | consistency可選的值有quorum、one和all。默認的設置爲quorum | tradelog及fsync以及refresh |
pg | 主從異步複製 | 基於Write-ahead log | archive及stream方式 |
redis | 主從異步複製 | 增量Redis Protocol(全量增量長鏈接) | Sentinel failover |
mongo | 主從異步,Replica set模式 | 持久化的ring-buffer local.oplog.rs(initial_sync,steady-sync) | Arbiter選主 |
能夠看見一些對一致性要求高的,能夠採用半同步的機制,通常是基於quorum機制,像es就是基於這種機制,而kafka是採用ISR機制,兩者均可以配置
其餘的基本是異步複製,對於新加入的node以及recovery node的同步來講,採用不一樣的同步方式,新加入的通常採用全量同步,而處於正常狀態的node,通常是增量同步
In-Sync Replicas的縮寫,表示副本同步隊列
)全部的副本(replicas)統稱爲Assigned Replicas,即AR。ISR是AR中的一個子集,由leader維護ISR列表,follower從leader同步數據有一些延遲,任意一個超過閾值都會把follower剔除出ISR,存入OSR(Outof-Sync Replicas)列表,新加入的follower也會先存放在OSR中。AR=ISR+OSR。
當producer發送一條消息到broker後,leader寫入消息並複製到全部follower。消息提交以後才被成功複製到全部的同步副本。消息複製延遲受最慢的follower限制,重要的是快速檢測慢副本,若是follower「落後」太多或者失效,leader將會把它從ISR中刪除。
因而可知,Kafka的複製機制既不是徹底的同步複製,也不是單純的異步複製。事實上,同步複製要求全部能工做的follower都複製完,這條消息纔會被commit,這種複製方式極大的影響了吞吐率。而異步複製方式下,follower異步的從leader複製數據,數據只要被leader寫入log就被認爲已經commit,這種狀況下若是follower都尚未複製完,落後於leader時,忽然leader宕機,則會丟失數據。而Kafka的這種使用ISR的方式則很好的均衡了確保數據不丟失以及吞吐率。
es的一致性主要有兩個方面:
在Elasticsearch和磁盤之間是文件系統緩存。 在內存索引緩衝區中的文檔會被寫入到一個新的段中,可是這裏新段會被先寫入到文件系統緩存--這一步代價會比較低,稍後再被刷新到磁盤--這一步代價比較高。不過只要文件已經在緩存中, 就能夠像其它文件同樣被打開和讀取了。
在 Elasticsearch 中,寫入和打開一個新段的輕量的過程叫作 refresh 。 默認狀況下每一個分片會每秒自動刷新一次。這就是爲何咱們說 Elasticsearch是近實時搜索: 文檔的變化並非當即對搜索可見,但會在一秒以內變爲可見。
這些行爲可能會對新用戶形成困惑: 他們索引了一個文檔而後嘗試搜索它,但卻沒有搜到。這個問題的解決辦法是用 refresh API 執行一次手動刷新.
refresh_interval 能夠在既存索引上進行動態更新。 在生產環境中,當你正在創建一個大的新索引時,能夠先關閉自動刷新,待開始使用該索引時,再把它們調回來.
不一樣產品的replication細節不盡相同,可是大的理論是一致的,對於replication除了關注上述的replication相關方式外,還須要額外關注replication相關異常場景,才能作到成熟應用。