Codis——分布式Redis服務的解決方案


 Codis——分布式Redis服務的解決方案

 

之前介紹過的 Twemproxy 是一種Redis代理,但它不支持集群的動態伸縮,而codis則支持動態的增減Redis節點;另外,官方的redis 3.0開始支持cluster。

  

codis和twemproxy最大的區別有兩個:

  • codis支持動態水平擴展,對client完全透明不影響服務的情況下可以完成增減redis實例的操作;
  • codis是用go語言寫的並支持多線程,twemproxy用C並只用單線程。 后者又意味着:codis在多核機器上的性能會好於twemproxy;codis的最壞響應時間可能會因為GC的STW而變大,不過go1.5發布后會顯著降低STW的時間;如果只用一個CPU的話go語言的性能不如C,因此在一些短連接而非長連接的場景中,整個系統的瓶頸可能變成accept新tcp連接的速度,這時codis的性能可能會差於twemproxy。

 

codis和redis cluster的區別:

redis cluster基於smart client和無中心的設計,client必須按key的哈希將請求直接發送到對應的節點。這意味着:使用官方cluster必須要等對應語言的redis driver對cluster支持的開發和不斷成熟;client不能直接像單機一樣使用pipeline來提高效率,想同時執行多個請求來提速必須在client端自行實現異步邏輯。 而codis因其有中心節點、基於proxy的設計,對client來說可以像對單機redis一樣去操作proxy(除了一些命令不支持),還可以繼續使用pipeline並且如果后台redis有多個的話速度會顯著快於單redis的pipeline。同時codis使用zookeeper來作為輔助,這意味着單純對於redis集群來說需要額外的機器搭zk,不過對於很多已經在其他服務上用了zk的公司來說這不是問題:)

 

 


 

 

Codis 是豌豆莢公司開發的一個分布式 Redis 解決方案,用Go語言開發的。對於上層的應用來說,連接到 Codis Proxy 和連接原生的 Redis Server 沒有明顯的區別 (不支持的命令列表),Codis 底層會處理請求的轉發,不停機的數據遷移等工作。所有后邊的一切事情,對於前面的客戶端來說是透明的,可以簡單的認為后邊連接的是一個內存無限大的 Redis 服務。

Codis 由四部分組成:

  • Codis Proxy (codis-proxy),處理客戶端請求,支持Redis協議,因此客戶端訪問Codis Proxy跟訪問原生Redis沒有什么區別;
  • Codis Dashboard (codis-config),Codis 的管理工具,支持添加/刪除 Redis 節點、添加/刪除 Proxy 節點,發起數據遷移等操作。codis-config 本身還自帶了一個 http server,會啟動一個 dashboard,用戶可以直接在瀏覽器上觀察 Codis 集群的運行狀態;
  • Codis Redis (codis-server),Codis 項目維護的一個 Redis 分支,基於 2.8.21 開發,加入了 slot 的支持和原子的數據遷移指令;
  • ZooKeeper/Etcd,Codis 依賴 ZooKeeper 來存放數據路由表和 codis-proxy 節點的元信息,codis-config 發起的命令都會通過 ZooKeeper 同步到各個存活的 codis-proxy;

 

Codis 支持按照 Namespace 區分不同的產品,擁有不同的 product name 的產品,各項配置都不會沖突。

 

Codis 采用 Pre-sharding 的技術來實現數據的分片,默認分成 1024 個 slots (0-1023),對於每個key來說,通過以下公式確定所屬的 Slot Id:

SlotId = crc32(key) % 1024

每一個 slot 都會有一個且必須有一個特定的 server group id 來表示這個 slot 的數據由哪個 server group 來提供。數據的遷移也是以slot為單位的。

 

 

 


 

安裝與部署

  1. 安裝go;
  2. 安裝codis
    go get -u -d github.com/CodisLabs/codis
    cd $GOPATH/src/github.com/CodisLabs/codis
    make

     

  3. 安裝zookeeper;
  4. 啟動dashboard
    bin/codis-config dashboard

     

  5. 初始化slots,在zk上創建slot相關信息
    bin/codis-config slot init

     

  6. 啟動codis-redis,跟官方redis server方法一樣;
  7. 添加redis server group,每個 Group 作為一個 Redis 服務器組存在,只允許有一個 master, 可以有多個 slave,group id 僅支持大於等於1的整數。如: 添加兩個 server group, 每個 group 有兩個 redis 實例,group的id分別為1和2, redis實例為一主一從。
  8. bin/codis-config server add 1 localhost:6379 master
    bin/codis-config server add 1 localhost:6380 slave
    bin/codis-config server add 2 localhost:6479 master
    bin/codis-config server add 2 localhost:6480 slave

     

  9. 設置server group 服務的 slot 范圍,如設置編號為[0, 511]的 slot 由 server group 1 提供服務, 編號 [512, 1023] 的 slot 由 server group 2 提供服務
    bin/codis-config slot range-set 0 511 1 online
    bin/codis-config slot range-set 512 1023 2 online

     

  10. 啟動codis-proxy,
    bin/codis-proxy -c config.ini -L ./log/proxy.log  --cpu=8 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000

    剛啟動的 codis-proxy 默認是處於 offline狀態的, 然后設置 proxy 為 online 狀態, 只有處於 online 狀態的 proxy 才會對外提供服務

    bin/codis-config -c config.ini proxy online <proxy_name>  <---- proxy的id, 如 proxy_1

     

 

 

 

 

 


 

數據遷移(migrate)

安全和透明的數據遷移是 Codis 提供的一個重要的功能,也是 Codis 區別於 Twemproxy 等靜態的分布式 Redis 解決方案的地方。

數據遷移的最小單位是 key,我們在 codis redis 中添加了一些指令,實現基於key的遷移,如 SLOTSMGRT等 (命令列表),每次會將特定 slot 一個隨機的 key 發送給另外一個 codis redis 實例,這個命令會確認對方已經接收,同時刪除本地的這個 k-v 鍵值,返回這個 slot 的剩余 key 的數量,整個操作是原子的。

在 codis-config 管理工具中,每次遷移任務的最小單位是 slot。如: 將slot id 為 [0-511] 的slot的數據,遷移到 server group 2上,--delay 參數表示每遷移一個 key 后 sleep 的毫秒數,默認是 0,用於限速。

bin/codis-config slot migrate 0 511 2 --delay=10

遷移的過程對於上層業務來說是安全且透明的,數據不會丟失,上層不會中止服務。

注意,遷移的過程中打斷是可以的,但是如果中斷了一個正在遷移某個slot的任務,下次需要先遷移掉正處於遷移狀態的 slot,否則無法繼續 (即遷移程序會檢查同一時刻只能有一個 slot 處於遷移狀態)。

 

 

自動再平衡(auto rebalance)

Codis 支持動態的根據實例內存,自動對slot進行遷移,以均衡數據分布

bin/codis-config slot rebalance

要求:

  • 所有的codis-server都必須設置了maxmemory參數;
  • 所有的 slots 都應該處於 online 狀態, 即沒有遷移任務正在執行;
  • 所有 server group 都必須有 Master;

 

 

高可用(HA)

因為codis的proxy是無狀態的,可以比較容易的搭多個proxy來實現高可用性並橫向擴容。

對Java用戶來說,可以使用經過我們修改過的Jedis,Jodis ,來實現proxy層的HA。它會通過監控zk上的注冊信息來實時獲得當前可用的proxy列表,既可以保證高可用性,也可以通過輪流請求所有的proxy實現負載均衡。如果需要異步請求,可以使用我們基於Netty開發的Nedis

對下層的redis實例來說,當一個group的master掛掉的時候,應該讓管理員清楚,並手動的操作,因為這涉及到了數據一致性等問題(redis的主從同步是最終一致性的)。因此codis不會自動的將某個slave升級成master。 不過我們也提供一種解決方案:codis-ha。這是一個通過codis開放的api實現自動切換主從的工具。該工具會在檢測到master掛掉的時候將其下線並選擇其中一個slave提升為master繼續提供服務。

需要注意,codis將其中一個slave升級為master時,該組內其他slave實例是不會自動改變狀態的,這些slave仍將試圖從舊的master上同步數據,因而會導致組內新的master和其他slave之間的數據不一致。因為redis的slave of命令切換master時會丟棄slave上的全部數據,從新master完整同步,會消耗master資源。因此建議在知情的情況下手動操作。使用 codis-config server add <group_id> <redis_addr> slave 命令刷新這些節點的狀態即可。codis-ha不會自動刷新其他slave的狀態。

 

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM