一.codis-proxy 結構
- 1.Topology
- 2.Slots
- 3.ServerGroup
- 4.Server
二.codis-proxy 啟動過程
1.初始化ProxyInfo
- Id
- Addr
- productName
2.Proxy 把自己標記成offline狀態,將自己注冊到zk上
- ProxyServer -> Topology -> Proxy -> CreateProxyInfo
- zk上的地址 /zk/codis/db_{productName}/proxy
3.Proxy 從zk上獲取自己的狀態
- 判斷zk上的狀態是online認為注冊成功,並且開始監控zk自己的變化
- 如果還是offline狀態,3秒以后重試,重新獲取zk上的狀態
4.監控子節點的狀態
- zk上的地址 /zk/codis/db_{productName}/actions
5.初始化slots
- 每個codis-proxy有1024個slots
- 在zk上逐個獲取slot
- 某一個slots在zk上的狀態的path是/zk/codis/db_{productName}/slots/slot_{i}
- slot的狀態,確保是online狀態
- 在zk上逐個獲取這個slot所在的server group
- 某一個server group在zk上的狀態的path是/zk/codis/db_{productName}/servers/group_{i}
- 獲取server group zk下的子節點列表
- 逐個在zk上獲取server group下的server,並創建server對象
- 這樣一個slot就是由 zk 上的slot zk上的server group(由server組成是一個一主多從的結構)組成
- 為了使用這個slot所以需要把server group中的那些servers中的主庫創建連接
- 這里用slot的dst字段標示了slot所在主庫的位置
- 同時在codis-proxy的redis連接池中添加這個主庫的連接
- 這里需要說明一點的是,由於這個slot有可能處於migrate狀態,在創建的時候同時記錄了他是從哪個server group遷移過來的在migrateFrom字段,並且把遷移的主庫添加到codis-proxy的連接池
6.開始事件循環
- 主要是處理之前監控的一些zk上的變更
7.監聽codis-proxy的端口
- block
三.codis-proxy 的對外服務過程
- 對一個redis key的操作先把這個key crc32到某一個slot上
- 如果這個slot處於pre migrate需要阻塞對這個slot的操作
- 判斷這個key是否處於migrate狀態,如果是的話,在slot的migrateFrom的redis上執行一個遷移命令,命令的參數的slot的dst的IP和端口還有KEY的名字
- migrateFrom的這個redis會把key遷移到dst上並刪除自己的key,所以migrateFrom是遷移中的那個老的實例,dst是遷移中的新實例
- 判斷遷移命令的返回值,成功的話認為遷移成功
- 遷移成功以后,我們都是從dst這個新實例來讀或者寫這個key的內容返回給客戶端
- 然后做的就是一個代理該做的事情了,寫目標讀寫,結果返回給客戶端
四.為什么codis要修改redis源碼來支持遷移
- 一個原因是slot下的key set不好獲得
- 一個原因就是redis的操作都是原子性的,如果在遷移的時候,是通過proxy的在老的上get,新的上set,這樣沒法保證其他proxy對這個key操作的原子性
一.codis-config 啟動過程
- 解析productName zk地址
- 利用zk創建一個分布式鎖 /zk/codis/db_{productName}/LOCK
- 關於利用zk創建分布式鎖的方法有很多
- lock的時候可以在一個root下創建一個自增的臨時節點,取root下的所有節點,自己是最小的認為獲得鎖,否則等待比自己小1的節點刪除
- 因為zk保證里一致性,所以這個鎖和單機操作系統中的信號量一樣,取這個mutex的值,lock時候就減1,unlock時候加1
- 具體ocdis-config是用的哪種實現因為是在另一個項目里,所以還沒看
- 在zk中創建配置 /zk/codis/db_{productName}/living-codis-config
- 一個defer 結束的時候刪除之前zk創建的path
- 啟動了一個監聽在10086的HTTP管理后台
二.codis-config 命令
- 如果命令是阻塞的,會先獲取之前的分布式鎖,執行完以后會釋放鎖,只不過是一個一級命令一個鎖
proxy命令
list命令,獲取所有codis-proxy的代理信息
- 保存在zk的/zk/codis/db_{productName}/proxy 的子節點下
offline/online命令,將一個codis-proxy設置為下線和上線狀態
- 先獲取/zk/codis/db_{productName}/proxy/{proxyName}的proxy信息
- 如果是將proxy設置為上線狀態,檢查proxy下的所有slot是online狀態
- 設置proxy狀態是上線狀態
- 如果是將proxy設置為下線狀態,那么先設置proxy的狀態為標記下線,也即是mark_offline
- 然后訂閱節點的變更,直到他的狀態為offline的時候認為下線成功
slot命令
migrate命令,遷移一個slot
- 從zk中獲取所有slot的狀態
- 檢查集群中是否有正在遷移的slot,保證集群中同時只能有一個slot在遷移
- 遷移某個slot的時候先獲取分布式鎖,表示開始遷移某個slot,結束的時候釋放
- 檢查遷移到的server gorup可用
- 進入二階段的提交的第一階段,通知所有proxy 這個slot處於pre_migrate狀態
- 等待所有proxy做出回復,修改slot狀態為migrate狀態,保存在zk上
- 在老的redis主庫上執行slotsmgrtslot命令遷移slot到新的redis主庫,直到slot中所有的key遷移完成