CODIS2.x原理 之 CODIS-PROXY實現原理

作者:鄒祁峯
郵箱:[email protected]
博客:http://blog.csdn.net/qifengzou
日期:2016.08.02 18:48:39
轉載請註明來自”祁峯”的CSDN博客

程序codis-proxy是連接client與codis-server之間的橋樑,且其主要處理流程充分體現了codis設計思想。要想深入理解codis原理,必須首先弄清楚codis-proxy各主要處理流程。

1 總體時序

Codis-proxy最主要的作用就是接收客戶端提交的redis命令,並將命令分發到後端codis-server集羣,再收集各命令的執行結果,最終將執行結果返回給客戶端。其大體處理時序圖如下:
這裏寫圖片描述

功能簡介:
1.客戶端:Redis命令的發起方
2.SN-接收協程:用於接收來自客戶端的請求
3.SN-發送協程:用於發送請求處理結果至客戶端
4.BC-發送協程:用於將客戶端的請求轉發到後端某codis-server服務
5.BC-接收協程:用於接收來自某codis-server服務的應答
6.REDIS服務:某codis-server服務

2 處理流程

2.1 接收客戶端連接

Codis-proxy完成初始化之後,將會啓動一個協程專門用來幀聽端口,並接收來自客戶端的連接請求。
這裏寫圖片描述

一旦收到客戶端的連接請求,幀聽協程將tcp連接對象放入連接隊列,另一個協程將會從連接隊列中取出該連接,併爲之創建Session對象,再爲該Session對象新建一個SN-接收協程和SN-發送協程。其中SN-接收協程負責接收來自客戶端的操作請求; SN-發送協程負責將發送操作應答給客戶端。

2.2 接收客戶端請求

SN-接收協程用於接收來自客戶端的請求。如果命令類型是QUIT、AUTH、SELECT、PING時, 則不用再轉發到後端服務。如果是MGET、MSET、DEL這種支持同時操作多個鍵的命令,則需要將該命令按照操作鍵的個數N拆散成N個操作,再分發到不同的後端發送隊列,某請求每分發一次,其等待計數加1。再將整個操作請求放入tasks隊列,交給SN-發送協程等待應答完成。
這裏寫圖片描述

注意事項:
1.Codis只支持通過select選擇0分區,選擇其他分區均會報錯。
2.如果pipeline中的命令個數超過tasks隊列的長度,可能會出現執行結果較長時間未返回的現象。
3.某請求每分發一次,其等待計數加1。

2.3 應答客戶端請求

SN-發送協程用於將請求處理結果發送給客戶端。SN-發送協程首先從tasks中獲取到客戶端提交的操作請求,之後直接阻塞等待應答,直到等待計數減爲0時,則認爲該請求的應答全部收到,再合併應答結果,並最終發送結果給客戶端。
這裏寫圖片描述

2.4 客戶端請求分發

請求分發的目的是將操作請求發送到正確的codis-server服務。
這裏寫圖片描述

注意事項:
1.通過crc32(KEY)%1024計算被操作的KEY屬於哪個slot對象。
2.如果正要被操作的KEY屬於被遷移的slot對象,則在放入bc.input隊列前,codis-proxy會給對應的codis-server發送遷移某KEY的指令,並阻塞等待遷移的結果。如果遷移成功,則再將本次的操作請求放入對應的bc.input隊列; 如果遷移失敗,則返回錯誤給客戶端。

2.5 轉發請求至後端

BC-發送協程的主要職責是將bc.input隊列中的數據發送到某codis-server服務。
這裏寫圖片描述

2.6 接收後端的應答

BC-接收協程的主要職責接收來自某codis-server的應答數據。每完成一次應答的接收,BC-接收協程就會發送應答完成信號,以此告知SN-發送協程完成一次應答接收。
這裏寫圖片描述

注意事項:
1.SN-發送協程每收到一次應答完成信號,其等待次數將會減1。如果等待次數減爲0時,SN-發送協程則認爲所有應答都已收到,可進行後續處理。

2.7 處理來自ZK事件

Codis使用zk存儲各結點的狀態,各結點通過zk的訂閱功能感知各結點狀態的變化並作出相應的處理,以此達到增強集羣擴展性和集羣容災性的目的。
這裏寫圖片描述

3 注意事項

3.1 配置相關

配置字段: session_max_timeout
作用說明:當客戶端與PROXY之間的連接超過此時間未發送有效操作命令時,PROXY端將主動關閉此連接。
問題描述:將此值配置爲非0時,可能出現的客戶端進行REDIS操作時出現EOF的錯誤。
問題原因:由於很多客戶端SDK使用的是同步等待Redis請求應答的機制,而非事件觸發機制管理與PROXY端的連接。這就出現PROXY端主動關閉連接後,客戶端並未感知關閉事件。待客戶端從連接池獲取的連接時,可能獲取的連接對象實際已被PROXY端關閉,致使客戶端進行REDIS操作時出現EOF的錯誤。
解決方案:將此值設置爲0,即:PROXY端永遠不超時。例如:codis後續版本reborn就已經取消了此值的配置。


配置字段: session_max_pipeline
作用說明:用於指定每次提交的PIPELINE中命令最大數。
問題描述:如果某此提交的PIPELINE中命令數超過此值,將可能導致PROXY發生阻塞,故客戶端也因此而阻塞。
問題原因:由於SN-接收協程會將PIPELINE中的請求拆分成N個命令,並依次放入tasks隊列中。而tasks隊列的長度與session_max_pipeline一致。
解決方案: 1. 控制客戶端提交的各PIPELINE中命令個數 2. 適當增大該值。

3.2 其他事項

問題描述:客戶端與PROXY端通信時,必須全部接收來自PROXY端的數據。特別是PIPELINE操作時一定需要遵守此原則。否則可能出現PROXY進程“偶爾”異常退出,而zk報的異常卻是:”session expired”。
解決方案:嚴格遵循“必須接收所有請求的應答”


問題描述:可通過控制域名的方式,使zk管理多個codis集羣。但是codis-proxy、codis-server、codis-cconfig、codis-ha等無法複用。即:codis集羣只可以複用zk集羣。

發佈了66 篇原創文章 · 獲贊 91 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章