分佈式系統咋作同步?虐死人!

原創:小姐姐味道(微信公衆號ID:xjjdog),歡迎分享,轉載請保留出處。mysql

分佈式系統,經過數據冗餘,來保證數據的安全。要寫一個分佈式系統,一道繞不過去的坎,那就是數據同步。程序員

同步,這兩個字,折磨死了不少人。web

是同步,仍是異步?是push,仍是pull?誰是master,誰是slave?下線會怎樣,上線了又會怎樣?中心化,or對等節點?redis

這些問題,無一不拷打者分佈式系統的設計者。算法

下面,咱們將看一下主流的幾個存儲服務,是如何解決數據同步問題的。sql

MySQL如何作主從同步?

mysql的主服務器叫作master,從服務器叫作slave。mongodb

主服務器將變動記錄在binlog中,slave將經過獨立的線程拷貝這些記錄,而後重放。數據庫

binlog的格式分爲statement、row、mixed三種。緩存

  • statement 將變動的sql語句寫入到binlog中,在準確性方面會有必定影響
  • row 將每一條記錄的變化,寫入到binlog中
  • mixed 上面兩種的結合。MySQL會判斷何時有用statement,何時用row

因爲是異步線程去拷貝,slave很容易會出現延遲。當master不幸宕機,將會形成延遲的數據丟失。安全

replicationseminew.png

爲了解決異步複製的問題,5.5版本以後,MySQL引入了半同步複製(semi sync)的概念。半同步處於異步和全量同步之間,master執行完事務以後,並不直接返回,而是要等待至少一個slave寫入成功才返回。因爲須要與至少一個slave進行交互,性能相比較異步複製確定是有很多折損的。

全複製模式固然是要等待全部的slave節點複製完成,這種安全性最高,可是效率也最低。從概念上來說,只有一個slave的半複製就是全複製。

5.7以後,mysql實現了組複製(group replication)協議。它支持單主模式和多主模式,但在同一個group內,不容許同時存在。聽起還好像很神奇,其實它仍是經過paxos協議去實現的。

Kafka如何作的副本同步?

kafka因爲是一個消息隊列,因此不須要考慮隨機刪除和隨機更新的問題,它只關注寫入問題便可。從結構上來講,kafka的同步單元是很是分散的:kafka有多個topic,每一個topic又分爲多個partition,副本就是基於partiton去作的。

主分區叫作leader,1-n個副本叫作follower。生產者在發送消息的時候,須要先找到該分區的leader,而後將數據發送給它。follower只是做爲一個備份存在,以便在主分區發生問題時可以頂上去。

x.jpg

kafka的主從同步,叫作ISR(In Sync Replica)機制。

那何時消息算是發送成功呢?這還要看ack的發送級別。

  • 0 表示異步發送,消息發送完畢就算是成功了
  • 1 leader主副本寫入完成,就算是發送成功了
  • -1 leader發送完成,而且ISR中的副本都須要回覆ack

0和1的狀況下,kafka都有丟失消息的可能。在-1的狀況下,也須要保證至少有一個follower commit成功才能保證消息安全。若是follower都不能追遇上leader,則會被移除出 ISR列表。沒錯,是直接移除。當ISR爲空,則kafka的分區和單機是沒有區別的,因此kafka提供了min.insync.replicas參數規定了最小ISR。

  • 當ISR不知足的時候怎麼辦?kafka固然是不會丟失消息了,由於此時生產者的提交是失敗的,消息根本進不了系統裏來
  • 當全部副本都不可用怎麼辦?此時,該partition將永不可用

副本之間的數據複製,是經過follower pull的方式,也就是拉取的方式去獲取的。

Redis的主從複製

redis是內存kv數據庫,速度上遠超其餘數據庫,理論上主從同步更容易。但在高流量和高QPS下,主從複製依然會發生問題。

redis的slave鏈接上以後,首先會進行一次全量同步。它會發送psync命令到master,而後master執行bgsave生成一個rdb文件。全量同步就是複製這個rdb快照文件到slave。

那在全量複製中間出現的數據怎麼辦呢?確定是要緩存起來的。master會開啓一個buffer,而後記錄全量複製過程當中產生的新數據,在全量同步完成以後再補齊增量數據。

slave斷線以後也不須要每次都執行全量同步,爲了配合增量,還引入了複製偏移量(offset)、複製積壓緩衝區(replication backlog buffer)和運行 ID (run_id)三個概念。能夠看出它都是爲了標識slave,以及它的複製位置和緩衝區用的。

image-20210802151100440.png

以後的同步,就能夠一直使用psync去複製。依然是異步複製。

能夠看出redis的主從複製一致性大量依賴內存,級別是很是弱的。可是它快。快能解決不少問題,因此應用場景是不一樣的。

ElasticSearch主從複製

es是基於lucene的搜索引擎,數據節點會包含多個索引(index)。每一個索引包含多個分片(shard),每一個分片又包含多個replica(副本)。

從上面的描述來看,這些概念是與kafka高度雷同的,es的複製單元是分片。

es的數據依然是先寫master,它一樣維護了一個同步中的slave列表(InSyncAllocationIds),處於yellow和red狀態的副本固然是不在這個列表中的。

master須要等待全部這些正常的副本寫入完成後,才返回給客戶端,因此一致性級別是比較高的,由於它的slave節點是要參與讀操做的,它是一個近實時系統。

因爲它是一個數據庫,因此依然會有刪除和更新操做。Translog至關於wal日誌,保證了斷電的數據安全,這和其餘rdbms的套路是一致的。

Cassandra集羣模式

cassandra是一個很是有名的CAP理論實踐數據庫,更多的像一個AP數據庫,目前在db-engines.com依然有較高的排名。

數據存儲是表的概念,一個表能夠存儲在多臺機器上。它的分區,是經過partition key來設計的,數據分佈很是依賴於hash函數。若是某個節點出現問題怎麼辦?那就須要一致性hash的支持。

cassandra很是有意思,它的複製(replicas)並不像其餘的主備數據同樣,它更像是多份master數據,這些數據都是同時向外提供服務的。當掉一個檢點,並不須要主備切換。

image-20210802151730781.png

爲何能夠作到這種程度呢?由於cassandra追求的是最終一致性。分佈式系統因爲副本的存在,不可避免的要異步或者同步複製。那到底複製到什麼程度纔算是合適的呢?QuorumR+W就是一個權衡策略。

quorum = (sum_of_replication_factors / 2) + 1
複製代碼

什麼意思呢?考慮到你有5個抽屜,而後隨機放入W個球,求須要多少次R,才能拿出一個球。假如你向裏面放了1個球,你須要打開5次,才能每次都有正確的判斷,此時R=五、W=1;當你放了2個球,則你只須要打開4次就能夠了;假如你放入了5個球,那就只須要讀一次。

當R+W>N的時候,屬於強一致性;當R+W<=N的時候,屬於最終一致性。

有意思的是,cassandra中的集羣信息,即meta信息,使用gossip(push-pull-gossip)進行傳遞。

MongoDB主從複製

mongodb有三種數據冗餘方式。一種是master-slave(不推薦使用),一種是replica set,一種是 sharding模式。

mongodb的副本集主從,就是標準的故障自動轉移實現方式,不須要人工介入。master節點當掉以後,會經過選舉從副本集中找出新的master節點,而後引導其餘節點鏈接到這個master。

mongodb的選舉算法,採用的是bully。

主節點的變動,會存放在特定的系統表中。slave會定時拉取這些變動,並應用。從這種描述中也能夠看出,mongodb在同步延遲或者單節點出問題的時候,會有丟失數據的可能。

總結

分佈式是爲了解決單機的容量問題,但它引入了一個新的問題,那就是數據同步。

數據同步要關注一致性,故障恢復以及時效性。

主要有兩種數據須要同步。

  • 元數據信息
  • 真正的數據

對於元數據信息,目前比較主流的作法,能夠參考使用raft協議進行數據分發。到了真正的數據同步方面,raft協議的效率仍是有些低的,因此會廣泛採用異步複製的方式。

在這種狀況下,異步複製列表,就成了關鍵的元數據信息,集羣須要維護這些節點的狀態。最壞的狀況下,異步複製節點所有不可用,master會本身運行在很是不可信的環境下。

爲了增長數據分配的靈活性,這些複製單元多會針對於sharding分片進行操做,由此帶來的,就是meta信息的爆炸。

分佈式系統這麼多,但並無一個可以統一的模式。有意思的是,即便是最低效的分佈式系統,也有大批的追隨者。不信?看看BTC的走勢就知道了。

做者簡介:小姐姐味道 (xjjdog),一個不容許程序員走彎路的公衆號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高併發世界,給你不同的味道。個人我的微信xjjdog0,歡迎添加好友,進一步交流。

相關文章
相關標籤/搜索