目前redis叢集開源的方案主要有redis cluster,codis,twemproxy等,這幾個方案裡面都不支援select指令,即使用者無法使用select進行邏輯db的切換,這樣會給之前使用redis單機的使用者帶來一定困擾,導緻很多使用者在遷移到叢集方案的時候需要改造代碼,本文探讨redis叢集支援select指令的方案實作。
阿裡雲的redis叢集版由3大元件構成:
redis-config : 叢集管理工具
redis-server : 優化過源碼的redis,支援slot, 擴容遷移等
redis-proxy : 單線程,c++14語言實作的核心
資料鍊路圖如下所示,使用者的請求通過proxy負載均衡之後分發到後端多個節點進行請求。
redis通常作為緩存,使用者在通路redis的時候都希望延遲盡量低,是以我們選擇了c++進行開發,另外為了使用更多c++的新特性,我們選擇了c++14進行開發,大量精簡了代碼提高了代碼可閱讀性。為了簡化模型proxy設計成單程序單線程的結構,所有使用者請求都隻會在一個工作線程上進行轉發。另外為了保證雲資源之間的隔離性,每個使用者都具有獨立的proxy避免不同使用者之間的互相影響。同時proxy提供了http的接口用于管控系統的控制和查詢。阿裡雲redis叢集proxy特性如下:
支援單slot指令,支援set,get等單key指令
支援多key指令,支援mset,mget等分布在不同db進行請求的指令
支援pubsub訂閱指令
支援相同slot上的事物
支援select指令
熱更新,連結不斷開
高性能
低延時
從以上特性我們可以看到阿裡雲redis的proxy支援了絕大部分的redis的指令,具有很高的相容性。後續阿裡雲redis叢集proxy還會提供block類指令支援,讀寫分離等特性。
簡單的方案如上圖proxy可以維護和用戶端一對一的連結,對于所有用戶端的請求建立一對一的連結,所有請求都直接進行轉發到後端處理。這樣的方案可以直接實作select指令的支援,但是這樣的方案帶來的問題就是需要頻繁和後端redis建立連結,性能比較差,而且在使用者使用短連接配接的情況下還會造成連結風暴導緻鍊路不穩定。
方案二proxy和後端redis之間維護一個長連接配接,所有的指令都通過該長連接配接進行轉發,proxy需要維護每個前端client的db資訊,在轉發指令的時候顯示的增加select調用。這個方案如果在前端client使用不同db的時候會導緻後端db連結頻繁進行db的切換,而且qps放大的倍數直接和client連結數目相關,會極大的影響叢集的性能。
如上圖proxy到redis之間每個db都維護一個長連接配接,每個長連接配接建立的時候都會執行select指令标注該連結為某個db的連結。使用者執行select指令之後我們就标記該連結為對應的db,proxy在接收到使用者請求之後根據連結db資訊轉發到後端對應的長連接配接上,如果沒有存在的長連接配接則建立一個對應的db長連接配接。考慮到原生的redis支援的db數目為16個db,在後端redis節點數目不多的情況下,proxy支撐的連接配接數是有限的。這種方案可以降低proxy的連結數目,同時可以讓指令在相同連結上合并發送提高proxy到redis的性能。