天天看點

Redis 叢集之Redis+Codis方案

【轉載請注明出處】: https://www.jianshu.com/p/41f97c494fc4

Redis 叢集解決方案有哪些

Redis 的叢集解決方案有社群的,也有官方的,社群的解決方案有 Codis 和Twemproxy,Codis是由我國的豌豆莢團隊開源的,Twemproxy是Twitter團隊的開源的;官方的叢集解決方案就是 Redis Cluster,這是由 Redis 官方團隊來實作的。下面的清單可以很明顯地表達出三者的不同點。

Codis Twemproxy Redis Cluster
resharding without restarting cluster Yes No
pipeline
hash tags for multi-key operations
multi-key operations while resharding - No( details )
Redis clients supporting Any clients Clients have to support cluster protocol

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。

Codis介紹

Codis 是一個分布式 Redis 解決方案, 對于上層的應用來說, 連接配接到 Codis Proxy 和連接配接原生的 Redis Server 沒有顯著差別 (

不支援的指令清單

), 上層應用可以像使用單機的 Redis 一樣使用, Codis 底層會處理請求的轉發, 不停機的資料遷移等工作, 所有後邊的一切事情, 對于前面的用戶端來說是透明的, 可以簡單的認為後邊連接配接的是一個記憶體無限大的 Redis 服務。

Codis 3.x 由以下元件組成:

  1. Codis Server:基于 redis-3.2.8 分支開發。增加了額外的資料結構,以支援 slot 有關的操作以及資料遷移指令。具體的修改可以參考文檔  redis 的修改
  2. Codis Proxy:用戶端連接配接的 Redis 代理服務, 實作了 Redis 協定。 除部分指令不支援以外( ),表現的和原生的 Redis 沒有差別(就像 Twemproxy)。
    • 對于同一個業務叢集而言,可以同時部署多個 codis-proxy 執行個體;
    • 不同 codis-proxy 之間由 codis-dashboard 保證狀态同步。
  3. Codis Dashboard:叢集管理工具,支援 codis-proxy、codis-server 的添加、删除,以及據遷移等操作。在叢集狀态發生改變時,codis-dashboard 維護叢集下所有 codis-proxy 的狀态的一緻性。
    • 對于同一個業務叢集而言,同一個時刻 codis-dashboard 隻能有 0個或者1個;
    • 所有對叢集的修改都必須通過 codis-dashboard 完成。
  4. Codis Admin:叢集管理的指令行工具。
    • 可用于控制 codis-proxy、codis-dashboard 狀态以及通路外部存儲。
  5. Codis FE:叢集管理界面。
    • 多個叢集執行個體共享可以共享同一個前端展示頁面;
    • 通過配置檔案管理後端 codis-dashboard 清單,配置檔案可自動更新。
  6. Storage:為叢集狀态提供外部存儲。
    • 提供 Namespace 概念,不同叢集的會按照不同 product name 進行組織;
    • 目前僅提供了 Zookeeper、Etcd、Fs 三種實作,但是提供了抽象的 interface 可自行擴充。

Codis 分片原理

在Codis中,Codis會把所有的key分成1024個槽,這1024個槽對應着的就是Redis的叢集,這個在Codis中是會在記憶體中維護着這1024個槽與Redis執行個體的映射關系。這個槽是可以配置,可以設定成 2048 或者是4096個。看你的Redis的節點數量有多少,偏多的話,可以設定槽多一些。

Codis中key的配置設定算法,先是把key進行CRC32 後,得到一個32位的數字,然後再hash%1024後得到一個餘數,這個值就是這個key對應着的槽,這槽後面對應着的就是redis的執行個體。

CRC32:CRC本身是“備援校驗碼”的意思,CRC32則表示會産生一個32bit(8位十六進制數)的校驗值。由于CRC32産生校驗值時源資料塊的每一個bit(位)都參與了計算,是以資料塊中即使隻有一位發生了變化,也會得到不同的CRC32值。

Codis之間的槽位同步

Codis把槽位資訊同步的工作交給了ZooKeeper來管理,當Codis的Codis Dashbord 改變槽位的資訊的時候,其他的Codis節點會監聽到ZooKeeper的槽位變化,會及時同步過來。如圖:

Codis中的擴容

因為Codis是一個代理中間件,是以這個當需要擴容Redis執行個體的時候,可以直接增加redis節點。在槽位配置設定的時候,可以手動指定Codis Dashbord來為新增的節點來配置設定特定的槽位。

在Codis中實作了自定義的掃描指令SLOTSSCAN,可以掃描指定的slot下的所有的key,将這些key遷移到新的Redis的節點中(話外語:這個是Codis定制化的其中一個好處)。

首先,在遷移的時候,會在原來的Redis節點和新的Redis裡都儲存着遷移的槽位資訊,在遷移的過程中,如果有key打進将要遷移或者正在遷移的舊槽位的時候,這個時候Codis的處理機制是,先是将這個key強制遷移到新的Redis節點中,然後再告訴Codis,下次如果有新的key的打在這個槽位中的話,那麼轉發到新的節點。

自動均衡政策

面對着上面講的遷移政策,如果有成千上萬個節點新增進來,都需要我們手動去遷移嗎?那豈不是得累死啊。當然,Codis也是考慮到了這一點,是以提供了自動均衡政策。自動均衡政策是這樣的,Codis 會在機器空閑的時候,觀察Redis中的執行個體對應着的slot數,如果不平衡的話就會自動進行遷移。

Codis安裝

依賴環境準備

下面這兩個依賴環境的搭建這裡不再介紹。

  • 安裝Zookeeper
  • 安裝Go

1. 下載下傳Codis安裝包

官方的釋出頁

找到最新的釋出版本下載下傳最新版3.2.2,如需要編譯安裝請參考

官方的編譯安裝說明

下載下傳安裝包之後解壓并重命名目錄,進入解壓目錄建立

config

檔案夾用來放置配置檔案位址,建立

logs

檔案夾将來放日志檔案。

2.安裝codis-dashboard(叢集管理工具)

config

檔案夾中建立配置檔案

dashboard.toml

(這些

配置檔案模闆

在源碼

config

目錄中可以找到),檔案内容:

##################################################
#                                                #
#                  Codis-Dashboard               #
#                                                #
##################################################

# Set Coordinator, only accept "zookeeper" & "etcd" & "filesystem".
# for zookeeper/etcd, coorinator_auth accept "user:password" 
# Quick Start
#coordinator_name = "filesystem"
#coordinator_addr = "/tmp/codis"
coordinator_name = "zookeeper"
coordinator_addr = "zk1:2181,zk2:2182,zk3:2183"
coordinator_auth = ""

# Set Codis Product Name/Auth.
product_name = "codis-demo"
product_auth = ""

# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:18080"

# Set arguments for data migration (only accept 'sync' & 'semi-async').
migration_method = "semi-async"
migration_parallel_slots = 100
migration_async_maxbulks = 200
migration_async_maxbytes = "32mb"
migration_async_numkeys = 500
migration_timeout = "30s"

# Set configs for redis sentinel.
sentinel_client_timeout = "10s"
sentinel_quorum = 2
sentinel_parallel_syncs = 1
sentinel_down_after = "30s"
sentinel_failover_timeout = "5m"
sentinel_notification_script = ""
sentinel_client_reconfig_script = ""           

為了友善管理建立啟動腳本

start-dashboard.sh

,腳本内容:

#!/bin/sh
#set -x
nohup  ./codis-dashboard --ncpu=4 --config=./config/dashboard.toml --log=./logs/dashboard.log --log-level=WARN &>/dev/null &           

執行啟動腳本啟動dashboard,然後浏覽器通路18080端口已經可以傳回目前叢集資訊。

啟動參數說明:

$ ./codis-dashboard -h
Usage:
    codis-dashboard [--ncpu=N] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR]
    codis-dashboard  --default-config
    codis-dashboard  --version

Options:
    --ncpu=N                    最大使用 CPU 個數
    -c CONF, --config=CONF      指定啟動配置檔案
    -l FILE, --log=FILE         設定 log 輸出檔案
    --log-level=LEVEL           設定 log 輸出等級:INFO,WARN,DEBUG,ERROR;預設INFO,推薦WARN           

預設配置檔案:

$ ./codis-dashboard --default-config | tee dashboard.toml
##################################################
#                                                #
#                  Codis-Dashboard               #
#                                                #
##################################################

# Set Coordinator, only accept "zookeeper" & "etcd"
coordinator_name = "zookeeper"
coordinator_addr = "127.0.0.1:2181"

# Set Codis Product {Name/Auth}.
product_name = "codis-demo"
product_auth = ""

# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:18080"           

| 參數 | 說明 |

| - | - |

| coordinator_name | 外部存儲類型,接受 zookeeper/etcd |

| coordinator_addr | 外部存儲位址 |

| product_name | 叢集名稱,滿足正則 w[w.-]* |

| product_auth | 叢集密碼,預設為空 |

| admin_addr | RESTful API 端口 |

3.安裝codis-proxy(用戶端連接配接的 Redis 代理服務)

config

proxy.toml

,檔案内容:

##################################################
#                                                #
#                  Codis-Proxy                   #
#                                                #
##################################################

# Set Codis Product Name/Auth.
product_name = "codis-demo"
product_auth = ""

# Set auth for client session
#   1. product_auth is used for auth validation among codis-dashboard,
#      codis-proxy and codis-server.
#   2. session_auth is different from product_auth, it requires clients
#      to issue AUTH <PASSWORD> before processing any other commands.
session_auth = ""

# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:11080"

# Set bind address for proxy, proto_type can be "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
proto_type = "tcp4"
proxy_addr = "0.0.0.0:19000"

# Set jodis address & session timeout
#   1. jodis_name is short for jodis_coordinator_name, only accept "zookeeper" & "etcd".
#   2. jodis_addr is short for jodis_coordinator_addr
#   3. jodis_auth is short for jodis_coordinator_auth, for zookeeper/etcd, "user:password" is accepted.
#   4. proxy will be registered as node:
#        if jodis_compatible = true (not suggested):
#          /zk/codis/db_{PRODUCT_NAME}/proxy-{HASHID} (compatible with Codis2.0)
#        or else
#          /jodis/{PRODUCT_NAME}/proxy-{HASHID}
jodis_name = "zookeeper"
jodis_addr = "zk1:2181,zk2:2182,zk3:2183"
jodis_auth = ""
jodis_timeout = "20s"
jodis_compatible = false

# Set datacenter of proxy.
proxy_datacenter = ""

# Set max number of alive sessions.
proxy_max_clients = 1000

# Set max offheap memory size. (0 to disable)
proxy_max_offheap_size = "1024mb"

# Set heap placeholder to reduce GC frequency.
proxy_heap_placeholder = "256mb"

# Proxy will ping backend redis (and clear 'MASTERDOWN' state) in a predefined interval. (0 to disable)
backend_ping_period = "5s"

# Set backend recv buffer size & timeout.
backend_recv_bufsize = "128kb"
backend_recv_timeout = "30s"

# Set backend send buffer & timeout.
backend_send_bufsize = "128kb"
backend_send_timeout = "30s"

# Set backend pipeline buffer size.
backend_max_pipeline = 20480

# Set backend never read replica groups, default is false
backend_primary_only = false

# Set backend parallel connections per server
backend_primary_parallel = 1
backend_replica_parallel = 1

# Set backend tcp keepalive period. (0 to disable)
backend_keepalive_period = "75s"

# Set number of databases of backend.
backend_number_databases = 16

# If there is no request from client for a long time, the connection will be closed. (0 to disable)
# Set session recv buffer size & timeout.
session_recv_bufsize = "128kb"
session_recv_timeout = "30m"

# Set session send buffer size & timeout.
session_send_bufsize = "64kb"
session_send_timeout = "30s"

# Make sure this is higher than the max number of requests for each pipeline request, or your client may be blocked.
# Set session pipeline buffer size.
session_max_pipeline = 10000

# Set session tcp keepalive period. (0 to disable)
session_keepalive_period = "75s"

# Set session to be sensitive to failures. Default is false, instead of closing socket, proxy will send an error response to client.
session_break_on_failure = false

# Set metrics server (such as http://localhost:28000), proxy will report json formatted metrics to specified server in a predefined period.
metrics_report_server = ""
metrics_report_period = "1s"

# Set influxdb server (such as http://localhost:8086), proxy will report metrics to influxdb.
metrics_report_influxdb_server = ""
metrics_report_influxdb_period = "1s"
metrics_report_influxdb_username = ""
metrics_report_influxdb_password = ""
metrics_report_influxdb_database = ""

# Set statsd server (such as localhost:8125), proxy will report metrics to statsd.
metrics_report_statsd_server = ""
metrics_report_statsd_period = "1s"
metrics_report_statsd_prefix = ""           

編寫啟動腳本

start-proxy.sh

#!/bin/sh
#set -x
nohup ./codis-proxy --ncpu=4 --config=./config/proxy.toml  --log=./logs/proxy.log --log-level=WARN &>/dev/null &           

執行啟動腳本,然後通路

11080

端口可以檢視代理資訊。

codis-proxy 啟動後,處于 waiting 狀态,監聽 proxy_addr 位址,但是不會 accept 連接配接,添加到叢集并完成叢集狀态的同步,才能改變狀态為 online。添加的方法有以下兩種:

  • 通過 codis-fe 添加:通過 Add Proxy 按鈕,将 admin_addr 加入到叢集中;
  • 通過 codis-admin 指令行工具添加,方法如下:

    $ ./codis-admin --dashboard=127.0.0.1:18080 --create-proxy -x 127.0.0.1:11080

其中 127.0.0.1:18080 以及 127.0.0.1:11080 分别為 dashboard 和 proxy 的

admin_addr

位址;

添加過程中,dashboard 會完成如下一系列動作:

  • 擷取 proxy 資訊,對叢集 name 以及 auth 進行驗證,并将其資訊寫入到外部存儲中;
  • 同步 slots 狀态;
  • 标記 proxy 狀态為 online,此後 proxy 開始 accept 連接配接并開始提供服務;

啟動參數說明:

$ ./codis-proxy -h
Usage:
    codis-proxy [--ncpu=N] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR] [--host-proxy=ADDR] [--ulimit=NLIMIT]
    codis-proxy  --default-config
    codis-proxy  --version

Options:
    --ncpu=N                    最大使用 CPU 個數
    -c CONF, --config=CONF      指定啟動配置檔案
    -l FILE, --log=FILE         設定 log 輸出檔案
    --log-level=LEVEL           設定 log 輸出等級:INFO,WARN,DEBUG,ERROR;預設INFO,推薦WARN
    --ulimit=NLIMIT             檢查 ulimit -n 的結果,確定運作時最大檔案描述不少于 NLIMIT           

預設配置檔案:

$ ./codis-proxy --default-config | tee proxy.toml
##################################################
#                                                #
#                  Codis-Proxy                   #
#                                                #
##################################################

# Set Codis Product {Name/Auth}.
product_name = "codis-demo"
product_auth = ""

# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:11080"

# Set bind address for proxy, proto_type can be "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
proto_type = "tcp4"
proxy_addr = "0.0.0.0:19000"

# Set jodis address & session timeout.
jodis_addr = ""
jodis_timeout = 10
jodis_compatible = false

# Proxy will ping-pong backend redis periodly to keep-alive
backend_ping_period = 5

# If there is no request from client for a long time, the connection will be droped. Set 0 to disable.
session_max_timeout = 1800

# Buffer size for each client connection.
session_max_bufsize = 131072

# Number of buffered requests for each client connection.
# Make sure this is higher than the max number of requests for each pipeline request, or your client may be blocked.
session_max_pipeline = 1024

# Set period between keep alives. Set 0 to disable.
session_keepalive_period = 60           

| product_name | 叢集名稱,參考 dashboard 參數說明|

| proto_type | Redis 端口類型,接受 tcp/tcp4/tcp6/unix/unixpacket |

| proxy_addr | Redis 端口位址或者路徑 |

| jodis_addr | Jodis 注冊 zookeeper 位址 |

| jodis_timeout | Jodis 注冊 session timeout 時間,機關 second |

| jodis_compatible | Jodis 注冊 zookeeper 的路徑 |

| backend_ping_period | 與 codis-server 探活周期,機關 second,0 表示禁止 |

| session_max_timeout | 與 client 連接配接最大讀逾時,機關 second,0 表示禁止 |

| session_max_bufsize | 與 client 連接配接讀寫緩沖區大小,機關 byte |

| session_max_pipeline | 與 client 連接配接最大的 pipeline 大小 |

| session_keepalive_period | 與 client 的 tcp keepalive 周期,僅 tcp 有效,0 表示禁止 |

注:Codis3 會将 jodis 節點注冊在 /jodis/{PRODUCT_NAME} 下,這點與 Codis2 不太相容,是以為了相容性,可以考慮将 jodis_compatible 設定成 true。

4.安裝codis-server(優化版的Redis)

codis-server的配置檔案和redis一樣,其本身就是在redis上改進而來。

建立配置檔案

config/codis-server/7001/redis.conf

bind 127.0.0.1
port 7001

daemonize no

pidfile /var/run/codis_7001.pid

logfile "./logs/codis-server/7001/redis.log"

save 900 1
save 300 10
save 60 10000

dir ./config/codis-server/7001
  
appendonly yes
appendfsync always           

建立啟動腳本

start-server-7001.sh

#!/bin/sh
#set -x
nohup ./codis-server ./config/codis-server/7001/redis.conf &>/dev/null &           

同樣的方法可以配置多個codis-server。

啟動完成後,可以通過 codis-fe 提供的界面或者 codis-admin 指令行工具添加到叢集中。

5.啟動codis-fe(叢集管理界面)

這是個可選元件,也可以通過codis-admin指令行工具來管理叢集。

start-fe.sh

#!/bin/sh
#set -x
nohup ./codis-fe --ncpu=1 --log=./logs/fe.log --log-level=WARN --zookeeper=zk1:2181,zk2:2182,zk3:2183 --listen=0.0.0.0:8090 &>/dev/null &           

執行啟動腳本,然後通路8090端口即可看到叢集管理界面。

$ ./codis-fe -h
Usage:
    codis-fe [--ncpu=N] [--log=FILE] [--log-level=LEVEL] [--assets-dir=PATH](--dashboard-list=FILE|--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT) --listen=ADDR
    codis-fe  --version

Options:
    --ncpu=N                        最大使用 CPU 個數
    -d LIST, --dashboard-list=LIST  配置檔案,能夠自動重新整理
    -l FILE, --log=FILE             設定 log 輸出檔案
    --log-level=LEVEL               設定 log 輸出等級:INFO,WARN,DEBUG,ERROR;預設INFO,推薦WARN
    --listen=ADDR                   HTTP 服務端口           

配置檔案 codis.json 可以手動編輯,也可以通過 codis-admin 從外部存儲中拉取,例如:

$ ./codis-admin --dashboard-list --zookeeper=127.0.0.1:2181 | tee codis.json
[
    {
        "name": "codis-demo",
        "dashboard": "127.0.0.1:18080"
    },
    {
        "name": "codis-demo2",
        "dashboard": "127.0.0.1:28080"
    }
]           

6.使用codis-admin(叢集管理的指令行工具)

執行

./codis-admin -h

可以檢視可執行的指令及參數。

  • dashboard服務和proxy服務的停用
    ./codis-admin  --proxy=127.0.0.1:11080 --shutdown
    ./codis-admin --dashboard=127.0.0.1:18080 --shutdown           
  • codis-dashboard 異常退出的修複

    當 codis-dashboard 啟動時,會在外部存儲上存放一條資料,用于存儲 dashboard 資訊,同時作為 LOCK 存在。當 codis-dashboard 安全退出時,會主動删除該資料。當 codis-dashboard 異常退出時,由于之前 LOCK 未安全删除,重新開機往往會失敗。是以 codis-admin 提供了強制删除工具:

    1. 确認 codis-dashboard 程序已經退出(很重要);
    2. 運作 codis-admin 删除 LOCK:
    ./codis-admin --remove-lock --product=codis-demo --zookeeper=zk1:2181,zk2:2182,zk3:2183           
  • codis-proxy 異常退出的修複

    通常 codis-proxy 都是通過 codis-dashboard 進行移除,移除過程中 codis-dashboard 為了安全會向 codis-proxy 發送 

    offline

     指令,成功後才會将 proxy 資訊從外部存儲中移除。如果 codis-proxy 異常退出,該操作會失敗。此時可以使用 codis-admin 工具進行移除:
    1. 确認 codis-proxy 程序已經退出(很重要);
    2. 運作 codis-admin 删除 proxy:
    $ ./codis-admin --dashboard=127.0.0.1:18080 --remove-proxy --addr=127.0.0.1:11080 --force           
    選項 

    --force

     表示,無論 

    offline

     操作是否成功,都從外部存儲中将該節點删除。是以操作前,一定要确認該 codis-proxy 程序已經退出。

7.配置codis-ha

start-ha.sh

#!/bin/sh
#set -x
nohup ./codis-ha --log=./logs/ha.log --log-level=WARN --dashboard=127.0.0.1:18080 &>/dev/null &           

因為 codis-proxy 是無狀态的,可以比較容易的搭多個執行個體,達到高可用性和橫向擴充。

對 Java 使用者來說,可以使用基于 Jedis 的實作 

Jodis

 ,來實作 proxy 層的 HA:

  • 它會通過監控 zookeeper 上的注冊資訊來實時獲得目前可用的 proxy 清單,既可以保證高可用性;
  • 也可以通過輪流請求所有的proxy實作負載均衡。

如果需要異步請求,可以使用基于Netty開發的 

Nedis

對下層的 redis 執行個體來說,當一個 group 的 master 挂掉的時候,應該讓管理者清楚,并手動的操作,因為這涉及到了資料一緻性等問題(redis的主從同步是最終一緻性的)。是以 codis 不會自動的将某個 slave 更新成 master。

關于外部 codis-ha 工具,這是一個通過 codis-dashboard 開放的 RESTful API 實作自動切換主從的工具。該工具會在檢測到 master 挂掉的時候主動應用主從切換政策,提升單個 slave 成為新的 master。

需要注意,codis 将其中一個 slave 更新為 master 時,該組内其他 slave 執行個體是不會自動改變狀态的,這些 slave 仍将試圖從舊的 master 上同步資料,因而會導緻組内新的 master 和其他 slave 之間的資料不一緻。是以當出現主從切換時,需要管理者手動建立新的 sync action 來完成新 master 與 slave 之間的資料同步(codis-ha 不提供自動操作的工具,因為這樣太不安全了)。

Codis使用

通路

http://IP:8090

打開叢集管理,左側的菜單顯示了codis叢集清單。

添加組和sever

可以看到添加的三個codis-sever中7002是master,7001和7003是slave,這裡的主從關系不用在配置檔案中來配置主從關系,codis會自己配置主從,可以使用redis用戶端做個測試:

$ ./redis-cli -c -p 7002
127.0.0.1:7002> set k1 v1
OK
127.0.0.1:7002> set k2 v2
OK
127.0.0.1:7002> exit

$ ./redis-cli -c -p 7001
127.0.0.1:7001> get k1
"v1"
127.0.0.1:7001> get k2
"v2"
127.0.0.1:7001> set k3 v3
# (error) READONLY You can't write against a read only slave.
127.0.0.1:7001> exit

$ ./redis-cli -c -p 7003
127.0.0.1:7003> get k1
"v1"
127.0.0.1:7003> get k2
"v2"
127.0.0.1:7003> set k3 v3
# (error) READONLY You can't write against a read only slave.
127.0.0.1:7003> exit           

可以看到隻能在master寫入,寫入的資料也同步到了slave上。此時去看7003和7001的配置檔案發現codis自動在配置檔案上加了

slaveof 127.0.0.1 7002

,假設此時master挂掉了

可以看到codis-ha自動将7003當成master,然後将7001和7002都停止了(程序不在),好危險,因為redis是最終一緻性,此時的資料一緻性也無法保證,而且将其他節點直接停止,此時的7003壓力将非常大。此時再将7001和7002重新開機,然後再次加入,發現codis會将這兩個執行個體再次停止,原因很簡單,因為原來7002是master,7001是7002的slave,配置并沒有變,不允許有兩個master,而且目前7003是master,是以需要手動更改配置檔案才能加入這個組。

假設現在沒有codis-ha,master 7003挂掉了會怎麼樣。

可以看到,并沒有将其他節點當成master的操作,此時重新開機7003就可以恢複目前組的叢集狀态,也不需要手動更改配置檔案和手動加入組。

添加proxy

設定Slots

使用redis用戶端連接配接proxy測試:

$ ./redis-cli -c -p 19000
127.0.0.1:19000> get k1
"v1"
127.0.0.1:19000> set k001 v001
OK
127.0.0.1:19000> get k001
"v001"
127.0.0.1:19000> exit           

此時假設master 7003挂了(沒用codis-ha)會怎麼樣?

$ ./redis-cli -c -p 19000
127.0.0.1:19000> get k1
(error) ERR handle response, backend conn reset
127.0.0.1:19000> set k002 v002
(error) ERR handle response, backend conn reset
127.0.0.1:19000> exit           

可以看到變成了既不可讀也不可寫了,這時啟動codis-ha繼續測試

codis-ha選擇了7001作為master,使用redis用戶端連接配接proxy測試:

$ ./redis-cli -c -p 19000
127.0.0.1:19000> get k1
"v1"
127.0.0.1:19000> get k001
"v001"
127.0.0.1:19000> set k0002 v0002
OK
127.0.0.1:19000> get k0002
"v0002"
127.0.0.1:19000> exit           

可以看到目前是可以讀也可以寫的。