日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TiKV 源码解析系列 - Raft 的优化

發(fā)布時間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TiKV 源码解析系列 - Raft 的优化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這篇文章轉(zhuǎn)載TiDB大牛?唐劉 的博客:https://mp.weixin.qq.com/s?__biz=MzI3NDIxNTQyOQ==&mid=2247484544&idx=1&sn=7d8e412ecc5aaeb3f9b7cf391bdcf398&chksm=eb1623eadc61aafcefcfbdf36b388a5f96d3009d21641eb6ac67c57317d6c397ddeb58fc7d06&scene=21#wechat_redirect

由于工作原因,最近在學(xué)習(xí)TiDB中TiKV相關(guān)的知識,覺得寫得挺好的,并轉(zhuǎn)載留存。

在分布式領(lǐng)域,為了保證數(shù)據(jù)的一致性,通常都會使用 Paxos 或者 Raft 來實現(xiàn)。但 Paxos 以其復(fù)雜難懂著稱,相反 Raft 則是非常簡單易懂,所以現(xiàn)在很多新興的數(shù)據(jù)庫都采用 Raft 作為其底層一致性算法,包括我們的 TiKV。

當(dāng)然,Raft 雖然簡單,但如果單純的按照 Paper 的方式去實現(xiàn),性能是不夠的。所以還需要做很多的優(yōu)化措施。本文假定用戶已經(jīng)熟悉并了解過 Raft 算法,所以對 Raft 不會做過多說明。(還不熟悉?Raft,點(diǎn)這里:)TiKV 源碼解析系列——如何使用 Raft)

?

Simple Request Flow

這里首先介紹一下一次簡單的 Raft 流程:

1. Leader 收到 client 發(fā)送的 request。

2. Leader 將 request append 到自己的 log。

3. Leader 將對應(yīng)的 log entry 發(fā)送給其他的 follower。

4. Leader 等待 follower 的結(jié)果,如果大多數(shù)節(jié)點(diǎn)提交了這個 log,則 apply。

5. Leader 將結(jié)果返回給 client。

6. Leader 繼續(xù)處理下一次 request。

可以看到,上面的流程是一個典型的順序操作,如果真的按照這樣的方式來寫,那性能是完全不行的。

?

Batch and Pipeline

首先可以做的就是 batch,大家知道,在很多情況下面,使用 batch 能明顯提升性能,譬如對于 RocksDB 的寫入來說,我們通常不會每次寫入一個值,而是會用一個 WriteBatch 緩存一批修改,然后在整個寫入。 對于 Raft 來說,Leader 可以一次收集多個 requests,然后一批發(fā)送給 Follower。當(dāng)然,我們也需要有一個最大發(fā)送 size 來限制每次最多可以發(fā)送多少數(shù)據(jù)。

如果只是用 batch,Leader ?還是需要等待 Follower 返回才能繼續(xù)后面的流程,我們這里還可以使用 Pipeline 來進(jìn)行加速。大家知道,Leader 會維護(hù)一個 NextIndex 的變量來表示下一個給 Follower 發(fā)送的 log 位置,通常情況下面,只要 Leader 跟 Follower 建立起了連接,我們都會認(rèn)為網(wǎng)絡(luò)是穩(wěn)定互通的。所以當(dāng) Leader 給 Follower 發(fā)送了一批 log 之后,它可以直接更新 NextIndex,并且立刻發(fā)送后面的 log,不需要等待 Follower 的返回。如果網(wǎng)絡(luò)出現(xiàn)了錯誤,或者 Follower 返回一些錯誤,Leader 就需要重新調(diào)整 NextIndex,然后重新發(fā)送 log 了。

?

Append Log Parallelly

對于上面提到的一次 request 簡易 Raft 流程來說,我們可以將 2 和 3 并行處理,也就是 Leader 可以先并行的將 log 發(fā)送給 Followers,然后再將 log append。為什么可以這么做,主要是因為在 Raft 里面,如果一個 log 被大多數(shù)的節(jié)點(diǎn) append,我們就可以認(rèn)為這個 log 是被 committed 了,所以即使 Leader 再給 Follower 發(fā)送 log 之后,自己 append log 失敗 panic 了,只要 `N / 2 + 1` 個 Follower 能接收到這個 log 并成功 append,我們?nèi)匀豢梢哉J(rèn)為這個 log 是被 committed 了,被 committed 的 log 后續(xù)就一定能被成功 apply。

那為什么我們要這么做呢?主要是因為 append log 會涉及到落盤,有開銷,所以我們完全可以在 Leader 落盤的同時讓 Follower 也盡快的收到 log 并 append。

這里我們還需要注意,雖然 Leader 能在 append log 之前給 Follower 發(fā) log,但是 Follower 卻不能在 append log 之前告訴 Leader 已經(jīng)成功 append 這個 log。如果 Follower 提前告訴 Leader 說已經(jīng)成功 append,但實際后面 append log 的時候失敗了,Leader 仍然會認(rèn)為這個 log 是被 committed 了,這樣系統(tǒng)就有丟失數(shù)據(jù)的風(fēng)險了。

?

Asynchronous Apply

上面提到,當(dāng)一個 log 被大部分節(jié)點(diǎn) append 之后,我們就可以認(rèn)為這個 log 被 committed 了,被 committed 的 log 在什么時候被 apply 都不會再影響數(shù)據(jù)的一致性。所以當(dāng)一個 log 被 committed 之后,我們可以用另一個線程去異步的 apply 這個 log。

所以整個 Raft 流程就可以變成:

1. Leader 接受一個 client 發(fā)送的 request。

2. Leader 將對應(yīng)的 log 發(fā)送給其他 follower 并本地 append。

3. Leader 繼續(xù)接受其他 client 的 requests,持續(xù)進(jìn)行步驟 2。

4. Leader 發(fā)現(xiàn) log 已經(jīng)被 committed,在另一個線程 apply。

5. Leader 異步 apply log 之后,返回結(jié)果給對應(yīng)的 client。

使用 asychronous apply 的好處在于我們現(xiàn)在可以完全的并行處理 append log 和 apply log,雖然對于一個 client 來說,它的一次 request 仍然要走完完整的 Raft 流程,但對于多個 clients 來說,整體的并發(fā)和吞吐量是上去了。

?

Now Doing…

→ST Snapshot

在 Raft 里面,如果 Follower 落后 Leader 太多,Leader 就可能會給 Follower 直接發(fā)送 snapshot。在 TiKV,PD 也有時候會直接將一個 Raft Group 里面的一些副本調(diào)度到其他機(jī)器上面。上面這些都會涉及到 Snapshot 的處理。

在現(xiàn)在的實現(xiàn)中,一個 Snapshot 流程是這樣的:

1. Leader scan 一個 region 的所有數(shù)據(jù),生成一個 snapshot file。

2. Leader 發(fā)送 snapshot file 給 Follower。

3. Follower 接受到 snapshot file,讀取,并且分批次的寫入到 RocksDB。

如果一個節(jié)點(diǎn)上面同時有多個 Raft Group 的 Follower 在處理 snapshot file,RocksDB 的寫入壓力會非常的大,然后極易引起 RocksDB 因為 compaction 處理不過來導(dǎo)致的整體寫入 slow 或者 stall。

幸運(yùn)的是,RocksDB 提供了[SST]機(jī)制,我們可以直接生成一個 SST 的 snapshot file,然后 Follower 通過 injest 接口直接將 SST file load 進(jìn)入 RocksDB。

→Asynchronous ?Lease Read

在之前的 [Lease Read]?TiKV 源碼解析系列 - Lease Read?文章中,我提到過 TiKV 使用 ReadIndex 和 Lease Read 優(yōu)化了 Raft Read 操作,但這兩個操作現(xiàn)在仍然是在 Raft 自己線程里面處理的,也就是跟 Raft 的 append log 流程在一個線程。無論 append log 寫入 RocksDB 有多么的快,這個流程仍然會 delay Lease Read 操作。

所以現(xiàn)階段我們正在做的一個比較大的優(yōu)化就是在另一個線程異步實現(xiàn) Lease Read。也就是我們會將 Leader Lease 的判斷移到另一個線程異步進(jìn)行,Raft 這邊的線程會定期的通過消息去更新 Lease,這樣我們就能保證 Raft 的 write 流程不會影響到 read。

?

延展閱讀:

TiKV 源碼解析系列 - Lease Read

TiKV 源碼解析系列 - PD Scheduler

TiKV 源碼解析系列——Placement Driver

TiKV 源碼解析系列——multi-raft 設(shè)計與實現(xiàn)

TiKV 源碼解析系列——如何使用 Raft

總結(jié)

以上是生活随笔為你收集整理的TiKV 源码解析系列 - Raft 的优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。