Redis 系統架構
通過前面的學習,相信你已經掌握了 Redis 的原理、數據類型及訪問協議等內容。本課時,我將進一步分析 Redis 的系統架構,重點講解 Redis 系統架構的事件處理機制、數據管理、功能擴展、系統擴展等內容。
事件處理機制
Redis 組件的系統架構如圖所示,主要包括事件處理、數據存儲及管理、用于系統擴展的主從復制/集群管理,以及為插件化功能擴展的 Module System 模塊。
Redis 中的事件處理模塊,采用的是作者自己開發的 ae 事件驅動模型,可以進行高效的網絡 IO 讀寫、命令執行,以及時間事件處理。
其中,網絡 IO 讀寫處理采用的是 IO 多路復用技術,通過對 evport、epoll、kqueue、select 等進行封裝,同時監聽多個 socket,并根據 socket 目前執行的任務,來為 socket 關聯不同的事件處理器。
當監聽端口對應的 socket 收到連接請求后,就會創建一個 client 結構,通過 client 結構來對連接狀態進行管理。在請求進入時,將請求命令讀取緩沖并進行解析,并存入到 client 的參數列表。
然后根據請求命令找到 對應的redisCommand ,最后根據命令協議,對請求參數進一步的解析、校驗并執行。Redis 中時間事件比較簡單,目前主要是執行 serverCron,來做一些統計更新、過期 key 清理、AOF 及 RDB 持久化等輔助操作。
數據管理
Redis 的內存數據都存在 redisDB 中。Redis 支持多 DB,每個 DB 都對應一個 redisDB 結構。Redis 的 8 種數據類型,每種數據類型都采用一種或多種內部數據結構進行存儲。同時這些內部數據結構及數據相關的輔助信息,都以 kye/value 的格式存在 redisDB 中的各個 dict 字典中。
數據在寫入 redisDB 后,這些執行的寫指令還會及時追加到 AOF 中,追加的方式是先實時寫入AOF 緩沖,然后按策略刷緩沖數據到文件。由于 AOF 記錄每個寫操作,所以一個 key 的大量中間狀態也會呈現在 AOF 中,導致 AOF 冗余信息過多,因此 Redis 還設計了一個 RDB 快照操作,可以通過定期將內存里所有的數據快照落地到 RDB 文件,來以最簡潔的方式記錄 Redis 的所有內存數據。
Redis 進行數據讀寫的核心處理線程是單線程模型,為了保持整個系統的高性能,必須避免任何kennel 導致阻塞的操作。為此,Redis 增加了 BIO 線程,來處理容易導致阻塞的文件 close、fsync 等操作,確保系統處理的性能和穩定性。
在 server 端,存儲內存永遠是昂貴且短缺的,Redis 中,過期的 key 需要及時清理,不活躍的 key 在內存不足時也可能需要進行淘汰。為此,Redis 設計了 8 種淘汰策略,借助新引入的 eviction pool,進行高效的 key 淘汰和內存回收。
功能擴展
Redis 在 4.0 版本之后引入了 Module System 模塊,可以方便使用者,在不修改核心功能的同時,進行插件化功能開發。使用者可以將新的 feature 封裝成動態鏈接庫,Redis 可以在啟動時加載,也可以在運行過程中隨時按需加載和啟用。
在擴展模塊中,開發者可以通過 RedisModule_init 初始化新模塊,用 RedisModule_CreateCommand 擴展各種新模塊指令,以可插拔的方式為 Redis 引入新的數據結構和訪問命令。
系統擴展
Redis作者在架構設計中對系統的擴展也傾注了大量關注。在主從復制功能中,psyn 在不斷的優化,不僅在 slave 閃斷重連后可以進行增量復制,而且在 slave 通過主從切換成為 master 后,其他 slave 仍然可以與新晉升的 master 進行增量復制,另外,其他一些場景,如 slave 重啟后,也可以進行增量復制,大大提升了主從復制的可用性。使用者可以更方便的使用主從復制,進行業務數據的讀寫分離,大幅提升 Redis 系統的穩定讀寫能力。
通過主從復制可以較好的解決 Redis 的單機讀寫問題,但所有寫操作都集中在 master 服務器,很容易達到 Redis 的寫上限,同時 Redis 的主從節點都保存了業務的所有數據,隨著業務發展,很容易出現內存不夠用的問題。
為此,Redis 分區無法避免。雖然業界大多采用在 client 和 proxy 端分區,但 Redis 自己也早早推出了 cluster 功能,并不斷進行優化。Redis cluster 預先設定了 16384 個 slot 槽,在 Redis 集群啟動時,通過手動或自動將這些 slot 分配到不同服務節點上。在進行 key 讀寫定位時,首先對 key 做 hash,并將 hash 值對 16383 ,做 按位與運算,確認 slot,然后確認服務節點,最后再對 對應的 Redis 節點,進行常規讀寫。如果 client 發送到錯誤的 Redis 分片,Redis 會發送重定向回復。如果業務數據大量增加,Redis 集群可以通過數據遷移,來進行在線擴容。