寫這個數據庫也已經有段時間了,在我心中此項目的第一個版本算是完成了,所以做一下小結,更多的功能以後再繼續迭代即可!
1. 引言
1.1 編寫目的
學習搭建rpc框架,自己閱讀了部分redis實現源碼,想實現一個加深印象,將學習的網絡方面的知識學以致用。等等…
1.2 項目概述
客戶端和服務器協議:Google Protocol buffer
RPC部分實現的功能:序列化和反序列化,發送遠程命令
項目服務器使用Reactor模式設計的框架,爲每一個連接設置了相應的讀回調,寫回調,每個連接套接字設置了EPOLLIN+非阻塞模式。實現了string和hash兩種操作,並實現了save和bgsave兩種持久化操作,bgsave操作通過創建新進程實現。項目中添加了最大堆定時器,爲每個客戶端設置了保活時間。當客戶端產生一次活動時,會自動爲該客戶端延長時間,對於一些一直不活動的客戶端,服務器會定時檢查連接隊列,並剔除閒置客戶端。定時器通過統一事件源觸發。
客戶端實現比較簡單,使用readline進行命令行輸入,並設置了檢測命令的合法模塊,檢測客戶端是否與服務器建立了連接,要是沒建立連接,會嘗試和服務器建立5次連接。直到建立連接成功。
1.3 術語定義
術語名稱 | 術語含義 |
---|---|
GPB | Google Protocol Buffer |
Server | 服務器 |
Client | 客戶端 |
1.4 引用文檔
名稱 | 作者 |
---|---|
Redis設計與實現 | 黃建宏 |
Redis深度探險 | 錢文品 |
Google Protocol Buffer | Google Protocol Buffer |
高性能服務器 | 遊雙 |
2. 設計決策
2.1 設計目標
2.1.1 運行環境
LInux Ubuntu18.10
2.1.2 開發環境及工具
vim+vimplus+gcc 編譯器
2.1.3 技術限制
書讀的有點少
2.2 設計原則
嚴格遵守需求規格說明書設計,使用一些面嚮對象語言中的一些設計模式例如工廠模式,減少代碼的複用性。
3. 邏輯架構設計
3.1 設計決策
Server設計領域模型如下:
client設計:
3.2 軟件單元
- server端
直接看.cpp文件吧,類中的成員比較多,不好陳述,所以選擇每個.cpp文件中的相關方法,將整個項目的功能實現加以描述。
aeEventloop.cpp
第一個就不說了,見名知意!
addServerEvent主要功能就是初始化時創建監聽套接字,並設置好相應的回調函數。
addTimerEvent該方法創建一個eventfd並設置好相應的回調函數。
aeEventloop構造方法,創建了時間堆,創建了epoll檢測引擎
下面是析構函數
aeProcessEvent該方法處理不同的事件,當aeEventloop將事件收集到vecotor中,該方法就會將其中的各種方法進行分類處理。
initDataInfo初始化時間堆中的相關數據
kickClient處理不活躍的客戶端
notifyToSave 通知保存
setCallBack 設置回調函數
start 開始啓動服務例程
aeEpoll.cpp
很簡單的操作,可以看懂!
rpc.cpp
反序列化,發送響應請求。
aeEvent.cpp
讀回調,和寫回調函數。
timerHeap.cpp
MyTimer 時間堆上的節點,TimerManager是時間堆管理器。
detect_timers檢測到期時間,若有超時客戶端,就執行回調函數處理。
其它函數太雞肋,不解釋了。
cmdProcess.cpp
findCmd在進行發序列化之後,判查找命令是否存在。
initCmdCb初始化命令回調函數,每個命令對應一個回調函數。
initRedis 初始化數據庫(就是從文件中將已經持久化的數據讀出來)
processMsg處理不同的命令請求
sendMsg發送消息
cmdSet.cpp
addObjectToDb添加對象到數據庫。
append增加數據庫
countRedis獲取當前數據庫的數量
expend擴大容納數據庫容器的容量
findCmd 查找命令
getDB獲取指定數據庫對象
initCmdCb初始化命令集合
initRedis初始化數據庫
redisCommandProc 數據庫各種命令處理函數,根據命令的不同回調在命令集中找相應的回調函數
cb 數據庫各種命令對象對應的回調函數
redisDb.cpp和redisDb.h
因爲是鍵值數據庫,所以對於大部分對象而言操作比較相似,所以利用C++多態機制實現了工廠模式,父類爲抽象類dbObject,設置了許多虛方法,對於strings和hashSet都是繼承了dbObject,redisDb通過hashmap管理dbObject,如圖。鍵值爲請求的key對象,key對象,成員是要訪問對象的鍵值,類型,以及數據庫編號三元組唯一確定對象在數據庫中的值。
- redisDb.cpp
getValue
getValues hash獲取值,將以vector對象的形式返回。
該數據庫管理對象的模型如下:
- redisDb.h
目前實現了兩種類型的操作。
抽象基類。
hash操作,setValue實現多參數設置。
strings對象,內部數據。
equalFunc和hashFunc設置hash函數。
factory工廠根據不同提示,返回不同對象。
rdb.cpp
持久化功能
下面是兩大對象在文件中的存儲格式:
- hash
- string
ctp存的是類型編號,數字編號之類,在初始化數據庫的時候,都會通過正則表達式辨別。然後其他解析之類的函數就不作解釋了!可以看源代碼。
recoverDb.cpp
恢復數據庫,因爲我將每個數據庫單獨存在一個文件中,0號數據存在.db_0文件,後面以此類推,其中或有一個redis_fileName文件,存放的是數據庫文件名,在恢復的時候,先讀取.redis_fileName,將所有數據庫文件名存在vector中,然後遍歷vector再通過mmap映射將文件內容映射到string中,然後解析string就行。
客戶端設計比較簡單,讀者可自行研究!
3.3 處理流程
4 運行演示
源代碼 感謝star或者fork!本代碼僅供閱讀參考學習,在個人平臺上運行的話可能得安裝配置google protocol buffer!並且要考慮系統兼容性!