經過某個節點的寫操做結果對後面經過其餘節點的讀操做可見。apache
若是更新數據後,併發訪問的狀況下可當即感知該更新,稱爲強一致性網絡
若是容許以後部分或所有感知不到該更新,稱爲弱一致性。併發
若在以後的一段時間(一般該時間不是固定的)後,必定能夠感知到該更新,稱爲最終一致性。app
便是任何一個沒有發生故障的節點必須在有限的時間內返回合理的結果(不管是正確的仍是錯誤的)。異步
部分節點宕機或者是沒法與其餘節點通訊時,各分區間還能夠保持分部式系統的功能,好比上海和北京兩個網絡分區,當上海分區光纖或其餘緣由致使網絡不通時,北京上海兩個分區之間不可通訊,可是最起碼要保證北京的分區中的分佈式系統功能可用。分佈式
分佈式系統中,一致性,可用性,分區容忍性最多隻可同時知足兩個,可是通常分區容錯性都是須要保障的,所以不少時候都是在可用性和一致性之間作權衡。以下一幅圖講解了CP和AP的兩種模式的具體表現形式:性能
首先看CP模式,N1和N2之間表明了網絡通訊,C表示客戶端,X表示新寫入的數據,Y表示舊數據,當C向N2發起請求時,因爲N2與N1之間網絡通訊異常,會致使N2不能同步到N1中的x,在保證一致性的狀況下,此時N2不會正常返回處理結果,要麼是等待網絡鏈接成功,將N1的Y獲取過來,保證數據一致,要麼系統出現錯誤,這樣的狀況是不能保證高可用的,可是保證了數據一致性。ui
AP模式下,N1和N2之間表明了網絡通訊,C表示客戶端,X表示新寫入的數據,Y表示舊數據,當C向N2發起請求時,因爲N2與N1之間網絡通訊異常,會致使N2不能同步到N1中的X,可是N2不會等待N1鏈接成功,或是返回錯誤信息,而是返回以前老的數據x,這樣系統可以正常的運行,可是數據的一致性並無保證,此時選擇了系統的高可用方案。spa
RDBMS的讀寫分離即爲典型的Master-slave方案3d
同步複製可保證強一隻性,可是會行影響性能(由於Master必需要等待全部的salve都接收到到更新才能返回)
異步複製提升可用性,可是會下降一致性,由於Master只須要本身寫操做完成,就當即返回,同時向Slave進行復制,這期間可能會出現某個或多個Slave因爲網絡或其餘緣由沒有更新到數據,形成數據不一致性。
主要用於去中心化(P2P)的分佈式系統中。DynamoDB與Cassandra即採用此方案,N表明副本數,W表明每次寫操做要保證的最少寫成功的副本數,R表明每次讀至少讀取的副本數,當W+R>N時,可保證每次讀取的數據至少有一個副本具備最新的更新,多個寫操做的順序難以保證,可能致使多副本間的寫操做順序不一致,Dynamo經過向量時鐘保證最終一致性。這裏能夠經過時間戳或者是自增主鍵之類的方式來保證過濾出讀取的最新的數據。
Google的Chubby,Zookeeper的Zab,RAFT等
Kafka提供了Replica保證了數據一致性
當某個Topic的replication-factor爲N切N大於1時,每一個Partition都會有N個副本(Replica),Replica的個數小於等於Broker數,即對每一個Partition而言每一個Broker上只會有一個Replica,所以可用Broker ID表示Replica,全部Partition的全部Replica默認狀況會均勻分佈到全部Broker上,如圖:
圖中能夠看到,Broker中存的是Topic2的Partition0和Topic2的Partition2的Replica,可是在Broker2中卻存了Topic2的Partition1和Topic2的Partition0的Replica,因此默認的Partition都是分佈在集羣節點上的,replica也同樣。這就能夠保證到某個節點掛掉以後,其餘的節點中保存的replica仍然能夠向消費者推送或被拉取消息,保證消息不丟失。
注意:
假如當前咱們搭建了三個Broker的集羣,可是我此時指定4個Replica時,會出現org.apache.kafka.common.errors.InvalidReplicationFactorException: Replication factor: 4 larger than available brokers: 3異常,如圖:
以下圖:
當producer想leader節點發送消息時,其他follower節點(我的理解跟slave相似)將會如其餘mq的consumer同樣去從主節點的topic中將數據拉取或被推送到自身節點中。這樣當leader節點掛掉以後,consumer訪問集羣時,仍然能夠從其餘的follower中獲取到最新數據,防止了數據丟失。
ISR: Leader會維護一個與其基本保持同步的Replica列表,該列表稱爲ISR(in-sync Replica),若是一個Follower比Leader落後太多,或者超過必定時間未發起數據複製請求,則Leader將其從ISR中移除,當ISR中全部Replica都向Leader發送ACK時,Leader即Commit(告訴Producer消息發送成功)。
Commit策略
1. 在Server中配置
replica.lag.time.max.ms:默認100000,最大未發起數據複製請求的時間。
replica.lag.max.messages:最大落後消息數,根據自身須要配置
2. Topic配置
min.insync.replicas=1: ISR列表最小個數,默認1,只有當request.required.acks爲-1時才生效,若是ISR中的副本數少於min.insync.replicas配置的數量時,客戶端會返回異常:org.apache.kafka.common.errors.NotEnoughReplicasExceptoin: Messages are rejected since there are fewer in-sync replicas than required。
3. Produce配置
request.required.acks=1,默認爲1,roducer發送數據到leader,leader寫本地日誌成功,返回客戶端成功;此時ISR中的副本尚未來得及拉取該消息,leader就宕機了,那麼這次發送的消息就會丟失,當爲-1時,當producer設置request.required.acks爲-1時,min.insync.replicas指定replicas的最小數目(必須確認每個repica的寫數據都是成功的),若是這個數目沒有達到,producer會產生異常。
如圖:
1. 能夠看到SR={A,B,C},Leader(A)節點中存在m1,m2,m3三條消息,F(B)存在m1,m2兩條消息,f(c)只存在m1一消息,因此這裏只會提交m1這條消息,由於m2這條消息尚未在ISR中完成複製。它只會提交三個ISR中都存在的消息。
2. 當L(A)在將消息m2複製到B,C以後掛掉,此時ISR中只有{B,C},B被選舉成爲新的主節點,當m2,m1都存在於B,C節點中時,B將會提交m1,m2兩條消息,不會提交m3消息。
3. 此時消息將都會發送到B節點上,C節點同步了B節點中的新發的消息m4,m5以後,將會提交m4,m5.
5.此時A節點鏈接集羣成功或重啓,可使用了,它會從B節點中同步從m1,到m5的消息,直到它的消息與B和C中的一致爲止,此時的Replica將會變成ISR={A,B,C},完成了Replica的恢復。這裏咱們發現m3並無存在了,這裏並非丟失了,只是當沒有主節點提交m3這條消息時,它將會自動反饋到Producer,Producer會重試,或作其餘處理,當重試成功後可能m3消息將會append到m5的後面,因此consumer消費消息時,咱們保證的順序性不是producer發送消息的順序,而是commit時的順序。
當ISR中的Replica所有宕機時,能夠經過以下方式處理:
1. 等待ISR中任一Replica恢復,並選它爲Leader。
缺點:等待時間較長,下降可用性(由於不能使用全部集羣節點),所以或ISR中的全部Replica都沒法恢復或者數據丟失,則該Partition將永不可用。
2. 選擇第一個恢復的Replica爲新的Leader,不管它是否在ISR中。
缺點:並未包含全部已被以前Leader Commit過的消息(由於它不在以前的ISR中),所以會形成數據丟失,可是它提升了可用節點的範圍,可用性比較高。