從零開始設計一個分布式KV存儲:基于Raft的協程化實現

從零開始設計一個分布式KV存儲:基于Raft的協程化實現

本文將以一個最小可運行的分布式KV系統為例,帶你拆解如何用C++、Raft算法和協程模型構建高可用的Key-Value存儲。

一、為什么需要分布式KV?

單機KV(如Redis)存在單點故障容量瓶頸。分布式KV通過多副本+共識算法解決:

  • 高可用:半數節點存活即可服務
  • 強一致:Raft保證所有節點數據一致
  • 水平擴展:分片后可支持海量數據

二、整體架構:協程化的四層設計

我們的系統采用協程化架構(對比線程模型節省90%上下文切換開銷):

層級職責關鍵文件
客戶端發起Get/Put請求用戶代碼
KV服務處理客戶端請求,對接RaftkvServer.cpp
Raft核心日志復制、選舉、狀態機應用raft.cpp
RPC層節點間通信(基于協程的MPRPC)mprpcchannel.cpp
協程調度管理所有網絡IO和計算任務fiber.cpp

核心交互流程

ClientKVServerRaftStateMachinePut("x", "1")Propose日志條目日志復制到多數節點日志已提交應用Put操作返回成功ClientKVServerRaftStateMachine

三、Raft算法實現要點

1. 選舉機制(解決腦裂問題)

// raft.cpp 選舉觸發條件
void doElection() {if (m_status != Follower) return;// 隨機超時避免選票瓜分m_currentTerm++;convertToCandidate();// 并行向所有節點拉票for (peer : m_peers) {fiber([peer]{RequestVote(peer);});}
}

調試技巧:在doElection()打斷點,觀察m_currentTermvoteCount

2. 日志復制(保證一致性)

// AppendEntries RPC處理邏輯
bool AppendEntries1(...) {// 關鍵檢查:日志連續性if (prevLogIndex > 0 && log[prevLogIndex].term != prevLogTerm) {return false; // 日志不匹配}// 追加新日志log.erase(log.begin()+prevLogIndex+1, log.end());log.insert(...); 
}

常見錯誤:日志不一致會導致節點反復拒絕,需檢查prevLogIndex/Term

3. 狀態機應用(最終可見性)

// kvServer.cpp 應用Raft日志到KV狀態機
void GetCommandFromRaft() {while (lastApplied < commitIndex) {lastApplied++;auto cmd = log[lastApplied].command;// 協程安全地操作跳躍表fiber_mutex.lock();ExecuteOpOnKVDB(cmd);fiber_mutex.unlock();// 通知等待的客戶端applyCond.notify(cmd.id);}
}

四、協程化網絡層設計

為什么選擇協程?

  • 傳統方案:每個RPC一個線程 → 1000連接=1000線程(內存爆炸)
  • 協程方案:單線程可處理10萬協程(通過epoll+用戶態調度)

關鍵實現

// fiber.cpp 協程切換核心
void resume(Fiber* fiber) {// 保存當前上下文到調度器swapcontext(&m_scheduler, &fiber->ctx);
}// 網絡IO的協程化改造
void MprpcChannel::CallMethod(...) {// 非阻塞IO,但看起來是同步的int fd = connect(...);fiber_yield(); // 等待可寫write(fd, request);fiber_yield(); // 等待可讀read(fd, response);
}

五、存儲引擎:跳躍表的妙用

KV狀態機使用跳躍表而非哈希表:

  • 有序性:支持范圍查詢(未來擴展)
  • 并發友好:無鎖讀/細粒度鎖寫
  • 內存高效:O(log n)時間復雜度
// 插入操作示例
void ExecutePutOpOnKVDB(const PutArgs& args) {m_skipList.insert_or_assign(args.key, args.value);
}

六、調試指南:從日志看系統狀態

1. 選舉追蹤

# 開啟調試輸出
export RAFT_DEBUG=1# 典型日志
[DEBUG] Node 1 timeout, start election (term=5)
[DEBUG] Node 1 receive vote from Node 2
[DEBUG] Node 1 become Leader in term 5

2. 一致性檢查

# 查看所有節點日志一致性
for node in 1 2 3; doecho "=== Node $node ==="curl localhost:800$node/debug/log
done

3. 性能分析

# 協程調度統計
curl localhost:8001/debug/fiber | jq '.'

七、如何擴展這個系統?

  1. 分片:增加ShardMaster模塊,按Key范圍分片
  2. 壓縮:定期快照(參考Raft論文的Snapshot機制)
  3. 成員變更:實現Joint Consensus動態增刪節點
  4. 客戶端緩存:跟蹤Leader ID避免每次請求重定向

八、總結

通過本文,我們構建了一個教學級的分布式KV系統。關鍵收獲:

  • Raft的核心:選舉+日志復制+狀態機應用
  • 協程的威力:單線程支撐高并發RPC
  • 調試技巧:日志+調試接口快速定位問題

Reference

https://github.com/youngyangyang04/KVstorageBaseRaft-cpp

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92194.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92194.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92194.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

虛擬機或docker的ubuntu無界面安裝完成后鏡像源設置

ubuntu系統源 在裝好虛擬機或者docker鏡像后&#xff0c;直接使用apt update && apt upgrade是無法完更新的。 此時系統中也沒有vim工具&#xff0c;我們可以在清華源的網站中找到幫助文檔。mirrors.tuna.tsinghua.edu.cn/help/ubuntu/為了避免沖突&#xff0c;我們使用…

串口通信02 溫度傳感DS18B20 01 day49

九&#xff1a;串口通信 通信&#xff1a;無線和有線 ? 單工 半雙工 全雙工 并行&#xff1a;多個數據線 串行&#xff1a;一根數據線 同步&#xff1a;通信雙方使用同一個時鐘&#xff0c;SPI信息幀&#xff0c;有CLK引腳 異步&#xff1a;通信雙方使用不同時鐘&#xff0c;雙…

【FreeRTOS 】任務通知

FreeRTOS 任務通知任務通知簡介一 、發送通知1.1 xTaskNotify()1.2 xTaskNotifyFromISR()1.3 xTaskNotifyGive()1.4 xTaskNotifyAndQuery()1.5 xTaskNotifyAndQueryFromISR()二、接收通知2.1 ulTaskNotifyTake()2.2 xTaskNotifyWait()三、清除通知狀態和值3.1 xTaskNotifyState…

Android視圖狀態以及重繪

一、視圖狀態&#xff08;View States&#xff09;1. 五種核心狀態狀態作用修改方法特點enabled視圖是否響應交互setEnabled(boolean)禁用狀態下不響應onTouch事件focused視圖是否獲得焦點requestFocus()需同時滿足focusable和focusableInTouchModewindow_focused視圖所在窗口是…

vue3接收SSE流數據進行實時渲染日志

后端使用的是 Spring Boot WebFlux&#xff08;響應式編程框架&#xff09;&#xff0c;并且返回的是 Server-Sent Events (SSE) 流式數據&#xff0c;那么在 Vue3 中&#xff0c;需要使用 EventSource API 或 fetch 流式讀取 來正確獲取響應內容。方案 1&#xff1a;使用 Eve…

每日五個pyecharts可視化圖表-bars(6)

探索pyecharts庫中條形圖的高級用法與定制技巧 在數據可視化中&#xff0c;條形圖是最常用的圖表類型之一&#xff0c;它能夠清晰地展示不同類別之間的數量對比。今天&#xff0c;我們將繼續學習如何使用pyecharts創建5種不同風格的條形圖。pyecahts源碼 圖表1&#xff1a;帶…

【C語言】文件操作全解析

文章目錄一、為什么需要文件操作&#xff1f;二、認識文件&#xff1a;不止是磁盤上的存儲2.1 程序文件2.2 數據文件2.3 文件名的構成三、文本文件與二進制文件&#xff1a;數據的兩種形態3.1 存儲方式差異3.2 實例對比&#xff1a;整數10000的存儲3.3 二進制文件操作示例四、文…

C結構體的幾種定義形式 + typedef結合使用的好處

struct 語句定義了一個包含多個成員的新的數據類型&#xff0c;struct 語句的格式如下&#xff1a; struct tag { member-list member-list member-list ... } variable-…

SPICE電容矩陣

SPICE電容矩陣: 如果有許多條傳輸線,就可以用下標來標記每一條線。例如,如果有5條線,就用1~5分別標記,依慣例把返回路徑導體標記為導線0。圖10.6給出了5條導線和一個公共返回平面的橫截面圖。首先研究電容器元件,下一節再討論電感器元件。 在這個線的集合中,每對導線之間…

【Java】棧和隊列

文章目錄1.棧1.1 棧的定義1.2 棧的使用1.3 棧的模擬實現2.隊列2.1 隊列的定義2.2 隊列的使用2.3 隊列的模擬實現3.循環隊列3.1 循環隊列的概念3.2 循環隊列判斷空和滿4.雙端隊列Deque1.棧 1.1 棧的定義 棧是一種特殊的線性表&#xff0c;其只允許在固定的一段進行數據的插入或…

【性能測試】---測試工具篇(jmeter)

目錄 1、安裝并啟動jemeter 2、重點組件 2.1、線程組&#xff1a; 2.2、HTTP取樣器?編輯 2.3、查看結果樹 2.4、HTTP請求默認值 2.5、HTTP信息頭管理器 2.6、JSON提取器 2.7、JSON斷言 2.8、同步定時器 2.9、CSV數據文件設置 2.10、HTTP Cookie管理器 3、測試報告…

機器學習(12):拉索回歸Lasso

- 拉索回歸可以將一些權重壓縮到零&#xff0c;從而實現特征選擇。這意味著模型最終可能只包含一部分特征。 - 適用于特征數量遠大于樣本數量的情況&#xff0c;或者當特征間存在相關性時&#xff0c;可以從中選擇最相關的特征。 - 拉索回歸產生的模型可能更簡單&#xff0c;因…

Redis持久化存儲

Redis持久化存儲詳解 一、核心持久化機制 Redis提供兩種主要持久化方式&#xff1a;RDB&#xff08;快照&#xff09; 和 AOF&#xff08;追加文件&#xff09;&#xff0c;以及兩者的混合模式。 RDB&#xff08;Redis Database&#xff09;快照持久化 工作原理 RDB通過創建數據…

python學智能算法(三十四)|SVM-KKT條件回顧

【1】引言 前序學習進程中&#xff0c;對軟邊界拉格朗日方程進行了初步構建。 其中約定了兩個拉格朗日乘子要非負&#xff0c;其本質是要滿足KKT條件。 今天就乘此次機會&#xff0c;在回顧一下KKT條件。 【2】定義 當問題無約束的時候&#xff0c;只要讓函數梯度為零&#…

【網絡基礎】計算機網絡發展背景及傳輸數據過程介紹

本文旨在幫助初學者建立起計算機網絡的基礎認知&#xff0c;從網絡的發展背景到網絡協議的分層模型&#xff0c;再到IP與MAC地址的基本概念&#xff0c;全面覆蓋第一階段學習重點。 &#x1f4cc; 本節重點 了解計算機網絡的發展背景&#xff0c;掌握局域網&#xff08;LAN&am…

阿里云-通義靈碼:解鎖云原生智能開發新能力,讓云開發更“靈”~

免責聲明&#xff1a;此篇文章所有內容皆是本人實驗&#xff0c;并非廣告推廣&#xff0c;并非抄襲&#xff0c;如有侵權&#xff0c;請聯系筆者。 每日一句 信念其實就是相信未來&#xff0c; 相信內在&#xff0c; 以及坦然美好的心境。 目錄 每日一句 一. 引言 二.通義…

lesson33:Python協程詳解:從原理到實戰的異步編程指南

目錄 一、協程核心概念&#xff1a;輕量級并發的本質 1.1 什么是協程&#xff1f; 1.2 協程與線程/進程的對比 二、協程工作原理&#xff1a;事件循環與協作式調度 2.1 事件循環&#xff08;Event Loop&#xff09;&#xff1a;協程的"調度中心" 2.2 協作式調度…

深入理解C++模板進階:非類型參數、特化與分離編譯

前言C模板是泛型編程的核心&#xff0c;它允許我們編寫與類型無關的代碼。在掌握了模板的基礎知識后&#xff0c;我們需要進一步了解模板的高級特性&#xff0c;以便更靈活地使用它們。本文將深入探討三個重要的模板進階主題&#xff1a;非類型模板參數、模板特化以及模板的分離…

使用winsw把SpringBoot項目注冊成window服務

目錄 一、使用winsw注冊 1.1、項目打jar包 1.2、下載winsw 1.3、把 WinSW.NET4.exe 重新命名 1.4、編寫m配置文件用于配置注冊信息 1.5、創建文件夾存放你的文件 1.6、安裝服務 1.7、啟動服務 1.8、卸載服務 1.8、停止服務 一、使用winsw注冊 1.1、項目打jar包 例如項目jar包名…

進階向:Python開發簡易QQ聊天機器人

數字化時代的聊天機器人應用在當今數字化時代&#xff0c;聊天機器人已經成為日常生活和商業活動中不可或缺的一部分。根據市場研究數據顯示&#xff0c;全球聊天機器人市場規模預計將在2026年達到102億美元&#xff0c;年復合增長率達到34.75%。這些智能助手正廣泛應用于以下場…