MySQL 半同步 與Raft對比
MySQL的after_sync半同步與raft 保證一致性的方式有些類似。
after_sync是master在sync binlog後等待從庫把事務寫到relay log後的ack,拿到ack後,在commit,然後在返回給客戶端提交成功的資訊。
raft中的日誌有commit和applied 兩個列表,commited 代表日誌寫入了檔案,applied代表日誌應用到了狀態機。
raft也是leader先寫日誌,然後在等待大部分的節點資訊都寫入了日誌,提交了,然後leader在提交,提交日誌後,leader在應用到狀態機,然後在返回給客戶端提交成功的資訊, 給其他節點提交資訊,其他節點應用日誌到狀態機,其他節點網路慢的情況下,leader會不停重試傳輸。
針對leader1當機的幾種狀態下的故障。參考
https://www.cnblogs.com/mindwind/p/5231986.html
場景3中,新主會提交之前的日誌,客戶端在重試,不是重複執行了嗎?狀態機執行了2次命令。
這個狀態機不會重複執行,因為之前的leader已經掛了,還沒有apply log,所以不會傳送apply 的請求出去。
如果leader apply log,返回給客戶端確認,但是follower沒有收到apply的訊號,leader就掛了,雖然新主上有commit的日誌,但是不會apply,怎麼辦?
這個是會應用的,新的leader,在接受使用者請求之前會執行
然後會執行
func (r *Raft) processLogs(index uint64, future *logFuture) { // Reject logs we've applied already lastApplied := r.getLastApplied() if index <= lastApplied { r.logger.Printf("[WARN] raft: Skipping application of old log: %d", index) return } // Apply all the preceding logs for idx := r.getLastApplied() + 1; idx <= index; idx++ { // Get the log, either from the future or from our log store if future != nil && future.log.Index == idx { r.processLog(&future.log, future, false) } else { l := new(Log) if err := r.logs.GetLog(idx, l); err != nil { r.logger.Printf("[ERR] raft: Failed to get log at %d: %v", idx, err) panic(err) } r.processLog(l, nil, false) } // Update the lastApplied index and term r.setLastApplied(idx) }
在進行
for idx := r.getLastApplied() + 1; idx <= index; idx++
這個判斷的時候,lastapplied一定比index小,index就是lastindex,這樣已經是提交狀態的日誌會被applied。
raft實現了cap中的cp ,沒有保證a ,a代表的是使用者的請求一定有響應,在出現腦裂的情況下,如果一個leader的請求沒有被大多數節點接受,那麼就沒有辦法提交,沒法給客戶響應,如果3個節點中有2個節點掛掉,就剩一個節點,其實這個時候請求過來後,判斷不是主,不會執行,也會返回給客戶端not leader,所以這裡的響應,是指的不會處理請求,進行業務邏輯處理。
在raft程式碼中,我們可以看到是在apply log後才向客戶端傳送的響應
case commitEntry := <-r.fsmCommitCh:--透過這個channel能找到commit後向這個channel傳送的資料 // Apply the log if a command var resp interface{} if commitEntry.log.Type == LogCommand { start := time.Now() resp = r.fsm.Apply(commitEntry.log) metrics.MeasureSince([]string{"raft", "fsm", "apply"}, start) } // Update the indexes lastIndex = commitEntry.log.Index lastTerm = commitEntry.log.Term // Invoke the future if given。--給客戶端返回資訊 if commitEntry.future != nil { commitEntry.future.response = resp commitEntry.future.respond(nil) }
follower的冪等實現,就是判斷entries的第一個index,是否小於等於當前follower的最後一個logindex,如果是,把這之間的刪除掉
// Process any new entries if n := len(a.Entries); n > 0 { start := time.Now() first := a.Entries[0] last := a.Entries[n-1] // Delete any conflicting entries lastLogIdx, _ := r.getLastLog() if first.Index <= lastLogIdx { r.logger.Printf("[WARN] raft: Clearing log suffix from %d to %d", first.Index, lastLogIdx) if err := r.logs.DeleteRange(first.Index, lastLogIdx); err != nil { r.logger.Printf("[ERR] raft: Failed to clear log suffix: %v", err) return } }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25719946/viewspace-2791179/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【MySQL】半同步與增強半同步複製MySql
- Mysql半同步配置MySql
- 【總結】mysql半同步MySql
- MySQL 半同步複製MySql
- MySQL半同步複製MySql
- mysql 5.7半同步複製MySql
- MySQL 5.7半同步機制MySql
- MySQL的半同步複製MySql
- MySQL 5.5半同步複製的配置與監控MySql
- Mysql5.7半同步複製MySql
- MySQL的半同步是什麼?MySql
- MySQL半同步使用注意事項MySql
- MySQL的非同步複製和半同步複製MySql非同步
- mysql半同步複製的設定MySql
- MySQL 半同步複製+MMM架構MySql架構
- mysql 5.6 半同步主從安裝MySql
- MySQL半同步複製--after_rollbackMySql
- mysql5.5半同步複製探究MySql
- Swoole 協程 MySQL 客戶端與非同步回撥 MySQL 客戶端的對比MySql客戶端非同步
- MySQL 8 複製(二)——半同步複製MySql
- 半同步複製報錯mysql8.0.25MySql
- MySQL半同步複製--after_commitMySqlMIT
- mysql5.5.9半同步複製功能部署MySql
- mysql5.5中的半同步複製MySql
- #MySQL# mysql5.7新特性之半同步複製MySql
- MySQL主從複製之半同步複製MySql
- MySQL增強(Loss-less)半同步複製MySql
- mysql線上建立半同步複製的從庫MySql
- MySQL5.5半同步複製實現原理MySql
- 與MSSQL對比學習MYSQL的心得MySql
- 比較MySQL 5.6與前版的同步協議薦MySql協議
- javascript - 非同步與傳統多執行緒比對JavaScript非同步執行緒
- MySQL5.7半同步複製報錯案例分析MySql
- MySQL 5.5 Semi-sync 半同步複製測試MySql
- 雲時代,MySQL到ClickHouse資料同步產品對比推薦MySql
- MySQL與MongoDB設計例項對比QYMySqlMongoDB
- PostgreSQL初體驗及其與MySQL的對比MySql
- MySQL入門學習之——mysql與oracle死鎖對比MySqlOracle