新聞中心
分布式數(shù)據(jù)庫系統(tǒng)的容錯(cuò)處理 – 100% 成功率, 超時(shí)和性能
作者:佚名 2021-06-30 14:55:39
運(yùn)維
數(shù)據(jù)庫運(yùn)維
分布式 本文分享實(shí)際經(jīng)驗(yàn), 介紹什么樣的選擇是普適的, 各位可以參考。

之前寫過一篇文章, 介紹"可靠通信三原則". 對于一個(gè)分布式數(shù)據(jù)庫, 如果想實(shí)現(xiàn) 100% 高可用(也即客戶端的請求永遠(yuǎn)不會(huì)返回失敗), 同樣可以用可靠通信三原則中的重試?yán)碚摵腿ブ乩碚搧斫鉀Q. 但在實(shí)踐上, 需要在成功率, 耗時(shí)(速度和性能)各方面進(jìn)行取舍. 本文分享實(shí)際經(jīng)驗(yàn), 介紹什么樣的選擇是普適的, 各位可以參考.
客戶端訪問數(shù)據(jù)庫服務(wù)器, 發(fā)起大量的請求, 絕對不可能做到每一個(gè)請求都是成功的. 因?yàn)榫W(wǎng)絡(luò)原因, 請求可能失敗. 因?yàn)榉?wù)器內(nèi)部處理沖突, 或者分布式節(jié)點(diǎn)間協(xié)調(diào)沖突, 都可能導(dǎo)致請求失敗.
所謂容錯(cuò)處理, 就是在遇到錯(cuò)誤的時(shí)候進(jìn)行重試. 因?yàn)殄e(cuò)誤必然發(fā)生, 只有重試才能消除錯(cuò)誤的影響, 就好像 IP 層必然會(huì)丟包, 但 TCP 協(xié)議通過重傳達(dá)到某種程度的可靠傳輸.
某些實(shí)現(xiàn)了 Basic Paxos + 日志復(fù)制狀態(tài)機(jī)模型的系統(tǒng), 因?yàn)樗^的"Leaderless", 會(huì)產(chǎn)生大量沖突. 即使是使用 Raft, 在某些情況下意外發(fā)生選舉, 也會(huì)導(dǎo)致請求沖突.
面對沖突(失敗)到底應(yīng)該由誰來重試呢? 這涉及到工程實(shí)踐上模塊職責(zé)劃分的問題, 模塊職責(zé)的劃分, 往往比代碼實(shí)現(xiàn)更重要. 一般來說, 發(fā)生重試的位置越底層, 性能會(huì)越好; 發(fā)生重試的位置越上層, 判斷是否應(yīng)該重試的依據(jù)就能更全面.
我們簡單把數(shù)據(jù)庫系統(tǒng)(生態(tài))劃分為幾個(gè)大的模塊, 從底層(左)到上層(右)是:
- replication -> server -> client SDK -> user
最常見的做法是讓 user 自己重試, 例如常見的 Redis SDK, 如果某臺 server 宕機(jī)導(dǎo)致請求失敗, 那么要求用戶換一個(gè) IP, 重新創(chuàng)建連接, 再次重復(fù)請求.
某些系統(tǒng)會(huì)封裝專屬的 client SDK, 例如, 把官方的 Redis SDK 做一下簡單封裝, 攔截每一個(gè)請求的結(jié)果, 如果發(fā)現(xiàn)錯(cuò)誤, SDK 內(nèi)部就自動(dòng)重試. 這樣做, user 就不需要有重試邏輯, 代碼可以簡化. 是這樣的, 多個(gè)協(xié)作的模塊, 如果某個(gè)模塊攬了一些職責(zé), 那它的上層模塊就能省些工夫.
如果 user 既不想重試, client SDK 也不想重試, 那怎么辦呢? 能不能把職責(zé)全推給 server 呢? 絕對不可能, 參見這篇文章的總結(jié). 那么, 為什么 SDK 重試之后, user 就不需要重試呢? 因?yàn)?SDK 和 user 是在同一個(gè)運(yùn)行空間內(nèi), 它們是一個(gè)整體, 兩者之間沒有可靠傳輸問題.
那么, 既然 client SDK 必須有重試邏輯, server 是否就不需要有重試邏輯了呢? 理論上可以, 但實(shí)踐上, server 自身依然要降低自己的故障率, 降低故障率的必要手段就是 重試 . 例如, server 請求 paxos 模塊同步一條操作日志, 但因?yàn)榉穷A(yù)期的 multi-master 出現(xiàn), 導(dǎo)致和其它節(jié)點(diǎn)爭搶同一個(gè)位置失敗, 這時(shí), server 如果直接報(bào)錯(cuò)給 client, 那么, server 的故障數(shù)量就加一. 但是, server 可以重試, 再次調(diào)用 paxos 模塊, 去爭搶下一個(gè)位置, 直到成功. 這樣, client 就會(huì)很少見到 server 報(bào)錯(cuò).
但是, 無論是 server 還是 client 都不可能無限次重試, 因?yàn)槊恳淮沃卦嚩紩?huì)消耗時(shí)間, 最極端的情況可能要重試幾個(gè)小時(shí)直到永遠(yuǎn), 這當(dāng)然不行, 所以, 需要引入 超時(shí)機(jī)制 , 重試一定次數(shù)之后即使還是失敗, 也必須報(bào)錯(cuò)給上層.
重試會(huì)增加總的耗時(shí), 這樣, 給上層帶來的不好效果就是, 上層覺得下層速度慢, 性能差. 所以, 必須有系統(tǒng)思維, 做出判斷, 做綜合的取舍. 從經(jīng)驗(yàn)上看, 無論 server 還是 client SDK, 都必須分析細(xì)化, 盡可能重試, 以提高成功率. 大部分情況下, 開發(fā)者往往過多地放棄重試, 而較少地進(jìn)行重試, 畢竟, 多一種重試場景, 就多寫一段代碼, 人總是會(huì)想偷懶的.
要設(shè)計(jì)一個(gè)高可靠的系統(tǒng), 可靠傳輸三原則是非常有用的基礎(chǔ)理論, 但不是銀彈. 本質(zhì)上, 軟件開發(fā)就是大量的分析細(xì)化體力活, 以及對系統(tǒng)復(fù)雜度的把控.
重試帶來的額外問題就是去重, 這也是可靠傳輸三原則里的第二項(xiàng)原則. 你可能聽過"冪等性"這個(gè)詞匯, 和去重是一回事. 如果一個(gè)操作是非冪等的, 那么, 就不能重試.
但是, 實(shí)踐上, 我們可以把冪等性的職責(zé)向上推, 盡可能推給上層. 畢竟, 至少對于 user 來說, 100% 的成功率, 優(yōu)先級比對冪等性的疑慮要高得多. 用戶同意下層不考慮冪等性, 而大膽地去重試, 但是, 對下層偶然的失敗會(huì)非常敏感. 簡單說就是: 別管什么冪等性, 在超時(shí)時(shí)間限制以內(nèi), 大膽重試!
分享名稱:分布式數(shù)據(jù)庫系統(tǒng)的容錯(cuò)處理–100%成功率,超時(shí)和性能
當(dāng)前地址:http://www.5511xx.com/article/cdpcoci.html


咨詢
建站咨詢
