導讀:TDengine分布式集群功能已經開源,集群功能中最重要的一個模塊是數據復制(replication),現將該模塊的設計分享出來,供大家參考。歡迎大家對着設計文檔和GitHub上的源代碼一起看,歡迎各種反饋。
1: 數據復制概述
數據復制(Replication)是指同一份數據在多個物理地點保存。它的目的是防止數據丟失,提高系統的高可用性(High Availability),而且通過應用訪問多個副本,提升數據查詢性能。
在高可靠的大數據系統里,數據復制是必不可少的一大功能。數據復制又分為實時復制與非實時復制。實時復制是指任何數據的更新(包括數據的增加、刪除、修改)操作,會被實時的復制到所有副本,這樣任何一台機器宕機或網絡出現故障,整個系統還能提供最新的數據,保證系統的正常工作。而非實時復制,是指傳統的數據備份操作,按照固定的時間周期,將一份數據全量或增量復制到其他地方。如果主節點宕機,副本是很大可能沒有最新數據,因此在有些場景是無法滿足要求的。
TDengine面向的是物聯網場景,需要支持數據的實時復制,來最大程度保證系統的可靠性。實時復制有兩種方式,一種是異步復制,一種是同步復制。異步復制(Asynchronous Replication)是指數據由Master轉發給Slave后,Master並不需要等待Slave回復確認,這種方式效率高,但有極小的概率會丟失數據。同步復制是指Master將數據轉發給Slave后,需要等待Slave的回復確認,才會通知應用寫入成功,這種方式效率偏低,但能保證數據絕不丟失。
數據復制是與數據存儲(寫入、讀取)密切相關的,但兩者又是相對獨立,可以完全脫耦的。在TDengine系統中,有兩種不同類型的數據,一種是時序數據,由TSDB模塊負責;一種是元數據(Meta Data), 由MNODE負責。這兩種性質不同的數據都需要同步功能。數據復制模塊通過不同的實例啟動配置參數,為這兩種類型數據都提供同步功能。
在閱讀本文之前,請先閱讀《TDengine 2.0 整體架構》,了解TDengine的集群設計和基本概念。
TDengine 架構示意圖
特別注明:本文中提到數據更新操作包括數據的增加、刪除與修改。
2: 基本概念和定義
TDengine里存在vnode, mnode, vnode用來存儲時序數據,mnode用來存儲元數據。但從同步數據復制的模塊來看,兩者沒有本質的區別,因此本文里的虛擬節點不僅包括vnode, 也包括mnode, vgoup也指mnode group, 除非特別注明。
版本(version):
一個虛擬節點組里多個虛擬節點互為備份,來保證數據的有效與可靠,是依靠虛擬節點組的數據版本號來維持的。TDengine2.0設計里,對於版本的定義如下:客戶端發起增加、刪除、修改的流程,無論是一條記錄還是多條,只要是在一個請求里,這個數據更新請求被TDengine的一個虛擬節點收到后,經過合法性檢查后,可以被寫入系統時,就會被分配一個版本號。這個版本號在一個虛擬節點里從1開始,是單調連續遞增的。無論這條記錄是采集的時序數據還是meta data, 一樣處理。當Master轉發一個寫入請求到slave時,必須帶上版本號。一個虛擬節點將一數據更新請求寫入WAL時,需要帶上版本號。
不同虛擬節點組的數據版本號是完全獨立的,互不相干的。版本號本質上是數據更新記錄的transaction ID,但用來標識數據集的版本。
角色(role):
一個虛擬節點可以是master, slave, unsynced或offline狀態。
- master:具有最新的數據,容許客戶端往里寫入數據,一個虛擬節點組,至多一個master。
- slave:與master是同步的,但不容許客戶端往里寫入數據,根據配置,可以容許客戶端對其進行查詢。
- unsynced: 節點處於非同步狀態,比如虛擬節點剛啟動、或與其他虛擬節點的連接出現故障等。處於該狀態時,該虛擬節點既不能提供寫入,也不能提供查詢服務。
- offline: 由於宕機或網絡原因,無法訪問到某虛擬節點時,其他虛擬節點將該虛擬節點標為離線。但請注意,該虛擬節點本身的狀態可能是unsynced或其他,但不會是離線。
Quorum:
指數據寫入成功所需要的確認數。對於異步復制,quorum設為1,具有master角色的虛擬節點自己確認即可。對於同步復制,需要至少大於等於2。原則上,Quorum >=1 並且 Quorum <= replication(副本數)。這個參數在啟動一個同步模塊實例時需要提供。
WAL:
TDengine的WAL(Write Ahead Log)與cassandra的commit log, mySQL的bin log, Postgres的WAL沒本質區別。沒有寫入數據庫文件,還保存在內存的數據都會先存在WAL。當數據已經成功寫入數據庫數據文件,相應的WAL會被刪除。但需要特別指明的是,在TDengine系統里,有幾點:
- 每個虛擬節點有自己獨立的wal
- WAL里包含而且僅僅包含來自客戶端的數據更新操作,每個更新操作都會被打上一個版本號
復制實例:
復制模塊只是一可執行的代碼,復制實例是指正在運行的復制模塊的一個實例,一個節點里,可以存在多個實例。原則上,一個節點有多少虛擬節點,就可以啟動多少實例。對於副本數為1的場景,應用可以決定是否需要啟動同步實例。應用啟動一個同步模塊的實例時,需要提供的就是虛擬節點組的配置信息,包括:
- 虛擬節點個數,即replication number
- 各虛擬節點所在節點的信息,包括node的end point
- quorum, 需要的數據寫入成功的確認數
- 虛擬節點的初始版本號
3: 數據復制模塊的基本工作原理
TDengine采取的是Master-Slave模式進行同步,與流行的RAFT一致性算法比較一致。總結下來,有幾點:
-
一個vgroup里有一到多個虛擬節點,每個虛擬節點都有自己的角色
-
客戶端只能向角色是master的虛擬節點發起數據更新操作,因為master具有最新版本的數據,如果向非Master發起數據更新操作,會直接收到錯誤
-
客戶端可以向master, 也可以向角色是Slave的虛擬節點發起查詢操作,但不能對unsynced的虛擬節點發起任何操作
-
如果master不存在,這個vgroup是不能對外提供數據更新和查詢服務的
-
master收到客戶端的數據更新操作時,會將其轉發給slave節點
-
一個虛擬節點的版本號比master低的時候,會發起數據恢復流程,成功后,才會成為slave
數據實時復制有三個主要流程:選主、數據轉發、數據恢復。后續做詳細討論。
4: 虛擬節點之間的網絡鏈接
虛擬節點之間通過TCP進行鏈接,節點之間的狀態交換、數據包的轉發都是通過這個TCP鏈接(peerFd)進行。為避免競爭,兩個虛擬節點之間的TCP鏈接,總是由IP地址(UINT32)小的節點作為TCP客戶端發起。一旦TCP鏈接被中斷,虛擬節點能通過TCP socket自動檢測到,將對方標為offline。如果監測到任何錯誤(比如數據恢復流程),虛擬節點將主動重置該鏈接。
一旦作為客戶端的節點鏈接不成或中斷,它將周期性的每隔一秒鍾去試圖去鏈接一次。因為TCP本身有心跳機制,虛擬節點之間不再另行提供心跳。
如果一個unsynced節點要發起數據恢復流程,它與Master將建立起專有的TCP鏈接(syncFd)。數據恢復完成后,該鏈接會被關閉。而且為限制資源的使用,系統只容許一定數量(配置參數tsMaxSyncNum)的數據恢復的socket存在。如果超過這個數字,系統會將新的數據恢復請求延后處理。
任意一個節點,無論有多少虛擬節點,都會啟動而且只會啟動一個TCP server, 來接受來自其他虛擬節點的上述兩類TCP的鏈接請求。當TCP socket建立起來,客戶端側發送的消息體里會帶有vgId(全局唯一的vgroup ID), TCP 服務器側會檢查該vgId是否已經在該節點啟動運行。如果已經啟動運行,就接受其請求。如果不存在,就直接將鏈接請求關閉。在TDengine代碼里,mnode group的vgId設置為1。
5: 選主流程
當同一組的兩個虛擬節點之間(vnode A, vnode B)建立連接后,他們互換status消息。status消息里包含本地存儲的同一虛擬節點組內所有虛擬節點的role和version。
如果一個虛擬節點(vnode A)檢測到與同一虛擬節點組內另外一虛擬節點(vnode B)的鏈接中斷,vnode A將立即把vnode B的role設置為offline。無論是接收到另外一虛擬節點發來的status消息,還是檢測與另外一虛擬節點的鏈接中斷,該虛擬節點都將進入狀態處理流程。狀態處理流程的規則如下:
-
如果檢測到在線的節點數沒有超過一半,則將自己的狀態設置為unsynced.
-
如果在線的虛擬節點數超過一半,會檢查master節點是否存在,如果存在,則會決定是否將自己狀態改為slave或啟動數據恢復流程
-
如果master不存在,則會檢查自己保存的各虛擬節點的狀態信息與從另一節點接收到的是否一致,如果一致,說明節點組里狀態已經穩定一致,則會觸發選舉流程。如果不一致,說明狀態還沒趨於一致,即使master不存在,也不進行選主。由於要求狀態信息一致才進行選舉,每個虛擬節點根據同樣的信息,會選出同一個虛擬節點做master,無需投票表決。
-
自己的狀態是根據規則自己決定並修改的,並不需要其他節點同意,包括成為master。一個節點無權修改其他節點的狀態。
-
如果一個虛擬節點檢測到自己或其他虛擬節點的role發生改變,該節點會廣播它自己保存的各個虛擬節點的狀態信息(role和version).
具體的流程圖如下:
選擇Master的具體規則如下:
-
如果只有一個副本,該副本永遠就是master
-
所有副本都在線時,版本最高的被選為master
-
在線的虛擬節點數過半,而且有虛擬節點是slave的話,該虛擬節點自動成為master
-
對於2和3,如果多個虛擬節點滿足成為master的要求,那么虛擬節點組的節點列表里,最前面的選為master
按照上面的規則,如果所有虛擬節點都是unsynced(比如全部重啟),只有所有虛擬節點上線,才能選出master,該虛擬節點組才能開始對外提供服務。當一個虛擬節點的role發生改變時,sync模塊回通過回調函數notifyRole通知應用。
6: 數據轉發流程
如果vnode A是master, vnode B是slave, vnode A能接受客戶端的寫請求,而vnode B不能。當vnode A收到寫的請求后,遵循下面的流程:
-
應用對寫請求做基本的合法性檢查,通過,則給改請求包打上一個版本號(version, 單調遞增)。
-
應用將打上版本號的寫請求封裝一個WAL Head, 寫入WAL(Write Ahead Log)
-
應用調用API syncForwardToPeer,如多vnode B是slave狀態,sync模塊將包含WAL Head的數據包通過Forward消息發送給vnode B,否則就不轉發。
-
vnode B收到Forward消息后,調用回調函數writeToCache, 交給應用處理。
-
vnode B應用在寫入成功后,都需要調用syncAckForward通知sync模塊已經寫入成功。
-
如果quorum大於1,vnode B需要等待應用的回復確認,收到確認后,vnode B發送Forward Response消息給node A。
-
如果quorum大於1,vnode A需要等待vnode B或其他副本對Forward消息的確認。
-
如果quorum大於1,vnode A收到quorum-1條確認消息后,調用回調函數confirmForward,通知應用寫入成功。
-
如果quorum為1,上述6,7,8步不會發生。
-
如果要等待slave的確認,master會啟動2秒的定時器(可配置),如果超時,則認為失敗。
對於回復確認,sync模塊提供的是異步回調函數,因此APP在調用syncForwardToPeer之后,無需等待,可以處理下一個操作。在Master與Slave的TCP鏈接管道里,可能有多個Forward消息,這些消息是嚴格按照應用提供的順序排好的。對於Forward Response也是一樣,TCP管道里存在多個,但都是排序好的。這個順序,SYNC模塊並沒有做特別的事情,是由APP單線程順序寫來保證的(TDengine里每個vnode的寫數據,都是單線程)。
7: 數據恢復流程
如果一虛擬節點(vnode B) 處於unsynced狀態,master存在(vnode A),而且其版本號比master的低,它將立即啟動數據恢復流程。在理解恢復流程時,需要澄清幾個關於文件的概念和處理規則。
1. 每個文件(無論是archived data的file還是wal)都有一個index, 這需要應用來維護(vnode里,該index就是fileId*3 + 0/1/2, 對應data, head與last三個文件)。如果index為0,表示系統里最老的數據文件。對於mnode里的文件,數量是固定的,對應於acct, user, db, table等文件。
2. 任何一個數據文件(file)有名字、大小,還有一個magic number。只有文件名、大小與magic number一致時,兩個文件才判斷是一樣的,無需同步。Magic number可以是checksum, 也可以是簡單的文件大小。怎么計算magic,換句話說,如何檢測數據文件是否有效,完全由應用決定。
3. 文件名的處理有點復雜,因為每台服務器的路徑可能不一致。比如node A的TDengine的數據文件存放在 /etc/taos目錄下,而node B的數據存放在 /home/jhtao目錄下。因此同步模塊需要應用在啟動一個同步實例時提供一個path,這樣兩台服務器的絕對路徑可以不一樣,但仍然可以做對比,做同步。
4. 當sync模塊調用回調函數getFileInfo獲得數據文件信息時,有如下的規則:
- index 為0,表示獲取最老的文件,同時修改index返回給sync模塊。如果index不為0,表示獲取指定位置的文件。
- 如果name為空,表示sync想獲取位於index位置的文件信息,包括magic, size。Master節點會這么調用
- 如果name不為空,表示sync想獲取指定文件名和index的信息,slave節點會這么調用
- 如果某個index的文件不存在,magic返回0,表示文件已經是最后一個。因此整個系統里,文件的index必須是連續的一段整數。
5. 當sync模塊調用回調函數getWalInfo獲得wal信息時,有如下規則:
- index為0,表示獲得最老的WAL文件, 返回時,index更新為具體的數字
- 如果返回0,表示這是最新的一個WAL文件,如果返回值是1,表示后面還有更新的WAL文件
- 返回的文件名為空,那表示沒有WAL文件
6. 無論是getFileInfo, 還是getWalInfo, 只要獲取出錯(不是文件不存在),返回-1即可,系統會報錯,停止同步。
整個數據恢復流程分為兩大步驟,第一步,先恢復archived data(file), 然后恢復wal。具體流程如下:
-
通過已經建立的TCP鏈接,發送sync req給master節點。
-
master收到sync req后,以client的身份,向vnode B主動建立一新的專用於同步的TCP鏈接(syncFd)。
-
新的TCP鏈接建立成功后,master將開始retrieve流程,對應的,vnode B將同步啟動restore流程。
-
Retrieve/Restore流程里,先處理所有archived data (vnode里的data, head, last文件),后處理WAL data。
-
對於archived data,master將通過回調函數getFileInfo獲取數據文件的基本信息,包括文件名、magic以及文件大小。
-
master 將獲得的文件名、magic以及文件大小發給vnode B。
-
vnode B將回調函數getFile獲得magic和文件大小,如果兩者一致,就認為無需同步,如果兩者不一致 ,就認為需要同步。vnode B將結果通過消息FileAck發回master。
-
如果文件需要同步,master就調用sendfile把整個文件發往vnode B。
-
如果文件不需要同步,master(vnode A)就重復5,6,7,8,直到所有文件被處理完。
對於WAL同步,流程如下:
-
master節點調用回調函數getWalInfo,獲取WAL的文件名。
-
如果getWalInfo返回值大於0,表示該文件還不是最后一個WAL,因此master調用sendfile一下把該文件發送給vnode B。
-
如果getWalInfo返回時為0,表示該文件是最后一個WAL,因為文件可能還處於寫的狀態中,sync模塊要根據WAL Head的定義逐條讀出記錄,然后發往vnode B。
-
vnode A讀取TCP鏈接傳來的數據,按照WAL Head,逐條讀取,如果版本號比現有的大,調用回調函數writeToCache,交給應用處理。如果小,直接扔掉。
-
上述流程循環,直到所有WAL文件都被處理完。處理完后,master就會將新來的數據包通過Forward消息轉發給slave。
從同步文件啟動起,sync模塊會通過inotify監控所有處理過的file以及wal。一旦發現被處理過的文件有更新變化,同步流程將中止,會重新啟動。因為有可能落盤操作正在進行(比如歷史數據導入,內存數據落盤),把已經處理過的文件進行了修改,需要重新同步才行。
對於最后一個WAL (LastWal)的處理邏輯有點復雜,因為這個文件往往是打開寫的狀態,有很多場景需要考慮,比如:
- LastWal文件size在增長,需要重新讀;
- LastWal文件雖然已經打開寫,但內容為空;
- LastWal文件已經被關閉,應用生成了新的Last WAL文件;
- LastWal文件沒有被關閉,但數據落盤的原因,沒有讀到完整的一條記錄;
- LastWal文件沒有被關閉,但數據落盤的原因,還有部分記錄暫時讀取不到。
sync模塊通過inotify監控LastWal文件的更新和關閉操作。而且在確認已經盡可能讀完LastWal的數據后,會將對方同步狀態設置為SYNC_CACHE。該狀態下,master節點會將新的記錄轉發給vnode B,而此時vnode B並沒有完成同步,需要把這些轉發包先存在recv buffer里,等WAL處理完后,vnode A再把recv buffer里的數據包通過回調writeToCache交給應用處理。
等vnode B把這些buffered forwards處理完,同步流程才算結束,vnode B正式變為slave。
8: Master分布均勻性問題
因為Master負責寫、轉發,消耗的資源會更多,因此Master在整個集群里分布均勻比較理想。
但在TDengine的設計里,如果多個虛擬節點都符合master條件,TDengine選在列表中最前面的做Master, 這樣是否導致在集群里,Master數量的分布不均勻問題呢?這取決於應用的設計。
給一個具體例子,系統里僅僅有三個節點,IP地址分別為IP1, IP2, IP3. 在各個節點上,TDengine創建了多個虛擬節點組,每個虛擬節點組都有三個副本。如果三個副本的順序在所有虛擬節點組里都是IP1, IP2, IP3, 那毫無疑問,master將集中在IP1這個節點,這是我們不想看到的。
但是,如果在創建虛擬節點組時,增加隨機性,這個問題就不存在了。比如在vgroup 1, 順序是IP1, IP2, IP3, 在vgroup 2里,順序是IP2, IP3, IP1, 在vgroup 3里,順序是IP3, IP1, IP2。最后master的分布會是均勻的。
因此在創建一個虛擬節點組時,應用需要保證節點的順序是round robin或完全隨機。
9: 少數虛擬節點寫入成功的問題
在某種情況下,寫入成功的確認數大於0,但小於配置的Quorum, 雖然有虛擬節點數據更新成功,master仍然會認為數據更新失敗,並通知客戶端寫入失敗。
這個時候,系統存在數據不一致的問題,因為有的虛擬節點已經寫入成功,而有的寫入失敗。一個處理方式是,Master重置(reset)與其他虛擬節點的連接,該虛擬節點組將自動進入選舉流程。按照規則,已經成功寫入數據的虛擬節點將成為新的master,組內的其他虛擬節點將從master那里恢復數據。
因為寫入失敗,客戶端會重新寫入數據。但對於TDengine而言,是OK的。因為時序數據都是有時間戳的,時間戳相同的數據更新操作,第一次會執行,但第二次會自動扔掉。對於Meta Data(增加、刪除庫、表等等)的操作,也是OK的。一張表、庫已經被創建或刪除,再創建或刪除,不會被執行的。
在TDengine的設計里,虛擬節點與虛擬節點之間,是一個TCP鏈接,是一個pipeline,數據塊一個接一個按順序在這個pipeline里等待處理。一旦某個數據塊的處理失敗,這個鏈接會被重置,后續的數據塊的處理都會失敗。因此不會存在Pipeline里一個數據塊更新失敗,但下一個數據塊成功的可能。
10: Split Brain的問題
選舉流程中,有個強制要求,那就是一定有超過半數的虛擬節點在線。但是如果replication正好是偶數,這個時候,完全可能存在splt brain問題。
為解決這個問題,TDengine提供Arbitrator的解決方法。Arbitrator是一個節點,它的任務就是接受任何虛擬節點的鏈接請求,並保持它。
在啟動復制模塊實例時,在配置參數中,應用可以提供Arbitrator的IP地址。
如果是奇數個副本,復制模塊不會與這個arbitrator去建立鏈接,但如果是偶數個副本,就會主動去建立鏈接。
Arbitrator的程序tarbitrator.c在復制模塊的同一目錄, 編譯整個系統時,會在bin目錄生成。命令行參數“-?”查看可以配置的參數,比如綁定的IP地址,監聽的端口號。
11: 與RAFT相比的異同
數據一致性協議流行的有兩種,Paxos與Raft. 本設計的實現與Raft有很多類同之處,下面做一些比較。
相同之處:
- 三大流程一致:Raft里有Leader election, replication, safety,完全對應TDengine的選舉、數據轉發、數據恢復三個流程。
- 節點狀態定義一致:Raft里每個節點有Leader, Follower, Candidate三個狀態,TDengine里是Master, Slave, Unsynced, Offline。多了一個offlince, 但本質上是一樣的,因為offline是外界看一個節點的狀態,但該節點本身是處於master, slave 或unsynced的。
- 數據轉發流程完全一樣,Master(leader)需要等待回復確認。
- 數據恢復流程幾乎一樣,Raft沒有涉及歷史數據同步問題,只考慮了WAL數據同步。
不同之處:
- 選舉流程不一樣:Raft里任何一個節點是candidate時,主動向其他節點發出vote request, 如果超過半數回答Yes, 這個candidate就成為Leader,開始一個新的term. 而TDengine的實現里,節點上線、離線或角色改變都會觸發狀態消息在節點組類傳播,等節點組里狀態穩定一致之后才觸發選舉流程,因為狀態穩定一致,基於同樣的狀態信息,每個節點做出的決定會是一致的,一旦某個節點符合成為master的條件,無需其他節點認可,它會自動將自己設為master。TDengine里,任何一個節點檢測到其他節點或自己的角色發生改變,就會給節點組內其他節點進行廣播的。Raft里不存在這樣的機制,因此需要投票來解決。
- 對WAL的一條記錄,Raft用term + index來做唯一標識。但TDengine只用version(類似index),在TDengine實現里,僅僅用version是完全可行的, 因為TDengine的選舉機制,沒有term的概念。
如果整個虛擬節點組全部宕機,重啟,但不是所有虛擬節點都上線,這個時候TDengine是不會選出master的,因為未上線的節點有可能有最高version的數據。而RAFT協議,只要超過半數上線,就會選出Leader。
12: Meta Data的數據復制
TDengine里存在時序數據,也存在Meta Data。Meta Data對數據的可靠性要求更高,那么TDengine設計能否滿足要求呢?下面做個仔細分析。
TDengine里Meta Data包括以下:
- account 信息
- 一個account下面,可以有多個user, 多個DB
- 一個DB下面有多個vgroup
- 一個DB下面有多個stable
- 一個vgroup下面有多個table
- 整個系統有多個mnode, dnode
- 一個dnode可以有多個vnode
上述的account, user, DB, vgroup, table, stable, mnode, dnode都有自己的屬性,這些屬性是TDengine自己定義的,不會開放給用戶進行修改。這些Meta Data的查詢都比較簡單,都可以采用key-value模型進行存儲。這些Meta Data還具有幾個特點:
-
上述的Meta Data之間有一定的層級關系,比如必須先創建DB,才能創建table, stable。只有先創建dnode,才可能創建vnode, 才可能創建vgroup。因此他們創建的順序是絕對不能錯的。
-
在客戶端應用的數據更新操作得到TDengine服務器側確認后,所執行的數據更新操作絕對不能丟失。否則會造成客戶端應用與服務器的數據不一致。
-
上述的Meta Data是容許重復操作的。比如插入新記錄后,再插入一次,刪除一次后,再刪除一次,更新一次后,再更新一次,不會對系統產生任何影響,不會改變系統任何狀態。
對於特點1,本設計里,數據的寫入是單線程的,按照到達的先后順序,給每個數據更新操作打上版本號,版本號大的記錄一定是晚於版本號小的寫入系統,數據寫入順序是100%保證的,絕對不會讓版本號大的記錄先寫入。復制過程中,數據塊的轉發也是嚴格按照順序進行的,因此TDengine的數據復制設計是能保證Meta Data的創建順序的。
對於特點2,只要Quorum數設置等於replica,那么一定能保證回復確認過的數據更新操作不會在服務器側丟失。即使某節點永不起來,只要超過一半的節點還是online, 查詢服務不會受到任何影響。這時,如果某個節點離線超過一定時長,系統可以自動補充新的節點,以保證在線的節點數在絕大部分時間是100%的。
對於特點3,完全可能發生,服務器確實持久化存儲了某一數據更新操作,但客戶端應用出了問題,認為操作不成功,它會重新發起操作。但對於Meta Data而言,沒有關系,客戶端可以再次發起同樣的操作,不會有任何影響。
總結來看,只要quorum設置大於一,本數據復制的設計是能滿足Meta Data的需求的。目前,還沒有發現漏洞。
作者簡介:陶建輝,濤思數據創始人。1994年到美國留學,1997年起,先后在芝加哥Motorola、3Com等公司從事無線互聯網的研發工作。2008年初回到北京創辦和信,后被聯發科收購。2013年初創辦快樂媽咪,后被太平洋網絡收購。2017年5月創辦濤思數據,不僅主導了TDengine的整體架構設計,還貢獻了4萬多行代碼,每天仍然戰斗在研發第一線。