1. 程式人生 > 實用技巧 >使用docker-compose建立Cluster模式 redis叢集

使用docker-compose建立Cluster模式 redis叢集

使用docker-compose建立Cluster模式 redis叢集

版本資訊:5.0.6
參考連結

Cluster是真正的叢集模式了,哨兵模式解決了主從模式不能自動故障恢復的問題,但是同時也存在難以擴容以及單機儲存、讀寫能力受限的問題,並且叢集之間都是一臺redis全量的資料拷貝,這樣所有的redis都冗餘一份,就會大大消耗記憶體空間。

叢集模式實現了redis資料的分散式儲存,實現資料的分片,每個redis節點儲存不同的內容,並且解決了線上的節點收縮(下線)和擴容(上線)問題。

叢集模式真正意義上實現了系統的高可用和高效能,但是叢集同時進一步使系統變得越來越複雜,下面來了解下叢集的運作原理。

一、資料分割槽原理

叢集的原理圖還是很好理解的,在redis叢集中採用的是虛擬槽分割槽演算法,會把redis叢集分成16384個槽(0-16383)。

比如:下圖所示三個master,會把0-16383範圍內的槽可能分成三部分(0-5000)、(5001-11000)、(11001-16383)分成三個資料快取點的槽範圍。

當客戶端請求過來,會首先通過對key進行CRC16(資料通訊領域中最常用的一種差錯校驗碼)校驗並對16384取模( CRC16(key)%16384 )計算出key所在的槽,然後再到對應的槽上進行取資料或者存資料,這樣就實現了資料的訪問更新。


之所以進行分槽儲存,是將一整堆的資料進行分片,防止單臺的redis資料量過大,影響效能的問題。

二、節點通訊

節點之間實現了將資料進行分片儲存,那麼節點之間又是怎麼通訊的呢?這個和哨兵模式中用到的命令一樣。

首先新上線的節點,會通過Gossip協議向老成員傳送Meet訊息,表示自己是新加入的成員。

老成員收到Meet訊息後,在沒有故障的情況下會回覆PONG訊息,表示歡迎新節點的加入,除了第一次傳送Meet訊息後,之後都會定期傳送PING訊息,實現節點之間的通訊。

通訊的過程中會為每一個通訊的節點開通一條tcp通道,之後就是定時任務,不斷的向其他節點發送PING訊息,這樣做的目的就是為了瞭解節點之間的元資料儲存情況,以及健康狀況,以便及時發現問題。

三、資料請求

上面說到了槽資訊,在Redis的底層維護了一個數組存放每個節點的槽資訊 unsigned char myslots[CLUSTER_SLOTS/8]。
因為它是一個二進位制陣列,只有儲存0和1值,如下圖所示:

這樣陣列只表示自己是否儲存對應的槽資料,若是1表示存在該資料,0表示不存在該資料,這樣查詢的效率就會非常的高,類似於布隆過濾器,二進位制儲存。

比如:叢集節點1負責儲存0-5000的槽資料,但是此時只有0、1、2儲存資料,其他的槽還沒有存資料,所以0、1、2對應的值是1。

並且,每個redis底層還維護了一個clusterNode陣列,大小也是16384,用於儲存負責對應槽的節點IP、埠資訊,這樣每一個節點就為了其他節點的元資料資訊,便於及時的找到對應的節點。

當新節點加入或者節點收縮,通過PING命令通訊,及時的更新自己clusterNode陣列中的元資料資訊,這樣有請求過來也就能及時的找到對應的節點。

有兩種其他的情況就是,若是請求過來發現,資料發生了遷移,比如新節點加入,會使舊的快取節點資料遷移到新節點。

請求過來發現舊節點已經發生了資料遷移並且資料被遷移到新節點,由於每個節點都有clusterNode資訊,通過該資訊的IP和埠,此時舊節點就會向客戶端傳送一個MOVED的重定向請求,表示資料已經遷移到新節點上,你要訪問這個新節點的IP和埠就能拿到資料,這樣就能重新獲取到資料。

倘若正在發生資料遷移呢?舊節點就會向客戶端傳送一個ASK重定向請求,並返回給客戶端遷移的目標節點的IP和埠,這樣也能獲取到資料。

四、擴容和收縮

擴容和收縮也就是節點的上線和下線,可能節點發生故障了,故障自動恢復的過程(節點收縮)。節點的收縮和擴容時,會重新計算每一個節點負責的槽範圍,併發根據虛擬槽演算法,將對應的資料更新到對應的節點。

還有前面講的新加入的節點會首先發送Meet訊息,以及發生故障後,哨兵老大節點的選舉,master節點的重新選舉,slave怎樣晉升為master節點,和哨兵模式一樣。

五、優缺點

5.1優點

叢集模式是一個無中心的架構模式,將資料進行分片,分佈到對應的槽中,每個節點儲存不同的資料內容,通過路由能夠找到對應的節點負責儲存的槽,能夠實現高效率的查詢。

並且叢集模式增加了橫向和縱向的擴充套件能力,實現節點加入和收縮,叢集模式是哨兵模式的升級版,哨兵的優點叢集都有。

5.2缺點

快取的最大問題就是帶來資料一致性問題,在平衡資料一致性的問題時,兼顧效能與業務要求,大多數都是以最終一致性的方案進行解決,而不是強一致性。

並且叢集模式帶來節點數量的劇增,一個叢集模式最少要六臺機器,因為要滿足半數原則的選舉方式,所以也帶來了架構的複雜性。

slave只充當冷備,並不能緩解master的讀的壓力。

六、實操

6.1 目錄結構

  • 一個docker-compose.yaml檔案
  • 六個節點的redis.conf檔案以及對應的data目錄

6.2 docker-compose.yaml檔案

version: '3'

services:
  #1 節點
  redis_cluster1:
    image: redis:latest
    container_name: redis_cluster1
    restart: always
    ports:
      - 6379:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.10
    volumes:
      - ./redis_cluster1.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data1:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf "
  #2 節點
  redis_cluster2:
    image: redis:latest
    container_name: redis_cluster2
    restart: always
    ports:
      - 6380:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.11
    volumes:
      - ./redis_cluster2.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data2:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf "
  #3 節點
  redis_cluster3:
    image: redis:latest
    container_name: redis_cluster3
    restart: always
    ports:
      - 6381:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.12
    volumes:
      - ./redis_cluster3.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data3:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf " 
  #4 節點
  redis_cluster4:
    image: redis:latest
    container_name: redis_cluster4
    restart: always
    ports:
      - 6382:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.13
    volumes:
      - ./redis_cluster4.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data4:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf " 
  #5 節點
  redis_cluster5:
    image: redis:latest
    container_name: redis_cluster5
    restart: always
    ports:
      - 6383:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.14
    volumes:
      - ./redis_cluster5.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data5:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf " 
  #6 節點
  redis_cluster6:
    image: redis:latest
    container_name: redis_cluster6
    restart: always
    ports:
      - 6384:6379
    networks:
      mynetwork:
        ipv4_address: 172.19.0.15
    volumes:
      - ./redis_cluster6.conf:/usr/local/etc/redis/redis.conf:rw
      - ./data6:/data:rw
    command:
      /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf " 
networks:
  mynetwork:
    external: true
  • 六個節點的IP分別是172.19.0.10172.19.0.11172.19.0.12172.19.0.13172.19.0.14172.19.0.15
  • 六個節點內部埠均為6379
  • 六個節點與宿主機對映的埠為637963806381638263836384
  • 指定對應的redis.conf配置檔案和資料目錄的對映關係

6.3 redis.conf檔案

port 6379
bind 0.0.0.0
protected-mode no
timeout 0
save 900 1 # 900s內至少一次寫操作則執行bgsave進行RDB持久化
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
appendonly yes
appendfsync everysec
# requirepass 12345678
# 開啟叢集模式 
cluster-enabled yes 
# 如果設定了密碼,需要指定master密碼
# masterauth 12345678 
# 請求超時時間
cluster-node-timeout 10000 
# 叢集的配置 配置檔案首次啟動自動生成 
cluster-config-file nodes_6061.conf 
  • 注意不要設定密碼

6.4 啟動

6.4.1 啟動各個節點服務

在docker-compose.yaml目錄執行 docker-composet up 命令啟動所有的節點服務

~/Documents/workspace/docker_mapping_volume/redis_cluster docker-compose up
Creating redis_cluster2 ... done
Creating redis_cluster4 ... done
Creating redis_cluster6 ... done
Creating redis_cluster5 ... done
Creating redis_cluster1 ... done
Creating redis_cluster3 ... done
Attaching to redis_cluster6, redis_cluster1, redis_cluster4, redis_cluster3, redis_cluster2, redis_cluster5
redis_cluster1    | 1:C 08 Sep 2020 14:02:09.773 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster2    | 1:C 08 Sep 2020 14:02:10.230 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster2    | 1:C 08 Sep 2020 14:02:10.230 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster2    | 1:C 08 Sep 2020 14:02:10.230 # Configuration loaded
redis_cluster3    | 1:C 08 Sep 2020 14:02:10.109 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster3    | 1:C 08 Sep 2020 14:02:10.110 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster3    | 1:C 08 Sep 2020 14:02:10.110 # Configuration loaded
redis_cluster1    | 1:C 08 Sep 2020 14:02:09.778 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster4    | 1:C 08 Sep 2020 14:02:10.007 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster4    | 1:C 08 Sep 2020 14:02:10.007 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster4    | 1:C 08 Sep 2020 14:02:10.007 # Configuration loaded
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.129 * No cluster configuration found, I'm 6c6613503ce3076684afa34fb5891be8d2ba4e94
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.276 * No cluster configuration found, I'm 3da7f792d1878a2434a6b6bb543d7b12837d1509
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.292 * Running mode=cluster, port=6379.
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.292 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.292 # Server initialized
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.292 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster5    | 1:C 08 Sep 2020 14:02:10.250 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster5    | 1:C 08 Sep 2020 14:02:10.250 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster5    | 1:C 08 Sep 2020 14:02:10.250 # Configuration loaded
redis_cluster1    | 1:C 08 Sep 2020 14:02:09.788 # Configuration loaded
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.031 * No cluster configuration found, I'm 54af7ff69f5c432bd35314ed5387be1e98a2a093
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.037 * Running mode=cluster, port=6379.
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.037 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.037 # Server initialized
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.037 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.135 * Running mode=cluster, port=6379.
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.135 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.135 # Server initialized
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.135 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster4    | 1:M 08 Sep 2020 14:02:10.048 * Ready to accept connections
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.840 * No cluster configuration found, I'm 2565c2f0f9fbeb06ed335115e29a56802c9b07e8
redis_cluster3    | 1:M 08 Sep 2020 14:02:10.141 * Ready to accept connections
redis_cluster6    | 1:C 08 Sep 2020 14:02:09.773 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_cluster6    | 1:C 08 Sep 2020 14:02:09.774 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
redis_cluster6    | 1:C 08 Sep 2020 14:02:09.774 # Configuration loaded
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.848 * Running mode=cluster, port=6379.
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.288 * No cluster configuration found, I'm 23db4d75289b983095061b94472e21a3f99cacf2
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.810 * No cluster configuration found, I'm de7e2df63cab77ebd431e425f058d380aa44cee9
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.858 * Running mode=cluster, port=6379.
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.858 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.858 # Server initialized
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.859 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.850 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster6    | 1:M 08 Sep 2020 14:02:09.862 * Ready to accept connections
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.850 # Server initialized
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.851 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster1    | 1:M 08 Sep 2020 14:02:09.855 * Ready to accept connections
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.346 * Running mode=cluster, port=6379.
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.346 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.346 # Server initialized
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.346 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_cluster2    | 1:M 08 Sep 2020 14:02:10.361 * Ready to accept connections
redis_cluster5    | 1:M 08 Sep 2020 14:02:10.379 * Ready to accept connections

6.4.2 建立叢集

在redis5.0之後建立叢集統一使用redis-cli。建立叢集命令如下

redis-cli --cluster create --cluster-replicas 1 172.19.0.10:6379 172.19.0.11:6379 172.19.0.12:6379 172.19.0.13:6379 172.19.0.14:6379 172.19.0.15:6379

其中 cluster-replicas 1 代表一個master後面有幾個slave節點。

~ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2c2a8fdb47f7        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6384->6379/tcp   redis_cluster6
531d8789b9cf        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6381->6379/tcp   redis_cluster3
7e4394ac21bd        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6383->6379/tcp   redis_cluster5
620dfd7fca31        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6380->6379/tcp   redis_cluster2
14eda4f4ad53        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6379->6379/tcp   redis_cluster1
f5b5db4a777b        redis:latest        "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:6382->6379/tcp   redis_cluster4
~ docker exec -it 2c2a8fdb47f7 redis-cli --cluster create --cluster-replicas 1 172.19.0.10:6379 172.19.0.11:6379 172.19.0.12:6379 172.19.0.13:6379 172.19.0.14:6379 172.19.0.15:6379
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.19.0.14:6379 to 172.19.0.10:6379
Adding replica 172.19.0.15:6379 to 172.19.0.11:6379
Adding replica 172.19.0.13:6379 to 172.19.0.12:6379
M: 2565c2f0f9fbeb06ed335115e29a56802c9b07e8 172.19.0.10:6379
   slots:[0-5460] (5461 slots) master
M: 3da7f792d1878a2434a6b6bb543d7b12837d1509 172.19.0.11:6379
   slots:[5461-10922] (5462 slots) master
M: 6c6613503ce3076684afa34fb5891be8d2ba4e94 172.19.0.12:6379
   slots:[10923-16383] (5461 slots) master
S: 54af7ff69f5c432bd35314ed5387be1e98a2a093 172.19.0.13:6379
   replicates 6c6613503ce3076684afa34fb5891be8d2ba4e94
S: 23db4d75289b983095061b94472e21a3f99cacf2 172.19.0.14:6379
   replicates 2565c2f0f9fbeb06ed335115e29a56802c9b07e8
S: de7e2df63cab77ebd431e425f058d380aa44cee9 172.19.0.15:6379
   replicates 3da7f792d1878a2434a6b6bb543d7b12837d1509
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 172.19.0.10:6379)
M: 2565c2f0f9fbeb06ed335115e29a56802c9b07e8 172.19.0.10:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 6c6613503ce3076684afa34fb5891be8d2ba4e94 172.19.0.12:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 54af7ff69f5c432bd35314ed5387be1e98a2a093 172.19.0.13:6379
   slots: (0 slots) slave
   replicates 6c6613503ce3076684afa34fb5891be8d2ba4e94
S: de7e2df63cab77ebd431e425f058d380aa44cee9 172.19.0.15:6379
   slots: (0 slots) slave
   replicates 3da7f792d1878a2434a6b6bb543d7b12837d1509
M: 3da7f792d1878a2434a6b6bb543d7b12837d1509 172.19.0.11:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 23db4d75289b983095061b94472e21a3f99cacf2 172.19.0.14:6379
   slots: (0 slots) slave
   replicates 2565c2f0f9fbeb06ed335115e29a56802c9b07e8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

由於這裡使用的是docker容器,所以我們使用 docker exec -it 2c2a8fdb47f7 redis-cli --cluster create --cluster-replicas 1 172.19.0.10:6379 172.19.0.11:6379 172.19.0.12:6379 172.19.0.13:6379 172.19.0.14:6379 172.19.0.15:6379 命令來建立叢集。

過程中會有一個提示Can I set the above configuration? (type 'yes' to accept) 輸入yes繼續,叢集會自動分配結果。

如果要建立帶密碼的叢集,新增 -a password即可

redis-cli --cluster create --cluster-replicas 1 172.19.0.10:6379 172.19.0.11:6379 172.19.0.12:6379 172.19.0.13:6379 172.19.0.14:6379 172.19.0.15:6379 -a password

6.5 驗證叢集是否建立成功

使用 redis-cli -c 命令選擇連線一個節點。

~ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2c2a8fdb47f7        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6384->6379/tcp   redis_cluster6
531d8789b9cf        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6381->6379/tcp   redis_cluster3
7e4394ac21bd        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6383->6379/tcp   redis_cluster5
620dfd7fca31        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6380->6379/tcp   redis_cluster2
14eda4f4ad53        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6379->6379/tcp   redis_cluster1
f5b5db4a777b        redis:latest        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:6382->6379/tcp   redis_cluster4
~ docker exec -it 2c2a8fdb47f7 redis-cli -c
127.0.0.1:6379> 
127.0.0.1:6379> cluster nodes
6c6613503ce3076684afa34fb5891be8d2ba4e94 172.19.0.12:6379@16379 master - 0 1599574177026 3 connected 10923-16383
23db4d75289b983095061b94472e21a3f99cacf2 172.19.0.14:6379@16379 slave 2565c2f0f9fbeb06ed335115e29a56802c9b07e8 0 1599574176008 5 connected
de7e2df63cab77ebd431e425f058d380aa44cee9 172.19.0.15:6379@16379 myself,slave 3da7f792d1878a2434a6b6bb543d7b12837d1509 0 1599574173000 6 connected
2565c2f0f9fbeb06ed335115e29a56802c9b07e8 172.19.0.10:6379@16379 master - 0 1599574176000 1 connected 0-5460
54af7ff69f5c432bd35314ed5387be1e98a2a093 172.19.0.13:6379@16379 slave 6c6613503ce3076684afa34fb5891be8d2ba4e94 0 1599574175000 4 connected
3da7f792d1878a2434a6b6bb543d7b12837d1509 172.19.0.11:6379@16379 master - 0 1599574175000 2 connected 5461-10922
127.0.0.1:6379> set name zhangsan
-> Redirected to slot [5798] located at 172.19.0.11:6379
OK
172.19.0.11:6379> 
  • docker exec -it 2c2a8fdb47f7 redis-cli -c 連線一個節點
  • cluster nodes 檢視主從配對情況
  • set name zhangsan 儲存一個數據,由於我們連線時指定了 -c 引數,就可以自動分配到172.19.0.11節點

6.6 應用程式連線

由於這裡的叢集使用docker建立的,所以會出現連線不上叢集的問題。可以參考這裡。

6.6.1 使用RedisTemplate 連線redis 叢集

使用RedisTemplate來操作非常簡單,新增如下配置檔案,專案裡像使用單機redis服務操作即可

spring:
    redis:
      cluster:
       nodes: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
      timeout: 3000
package com.lucky.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

@SpringBootApplication
public class Application implements CommandLineRunner {


    @Autowired
    RedisTemplate redisTemplate;


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        
        opeByRedisTemplate();
    }

    private void opeByRedisTemplate() {
        redisTemplate.opsForValue().set("name", "張三");
        String name = (String) redisTemplate.opsForValue().get("name");
        System.out.println(name);
    }
}

6.6.2 使用Jedis連線redis叢集

spring:
    redis:
      cluster:
       nodes: 127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
      timeout: 3000
      jedis:
        pool:
#        最大活躍數
          max-active: 1000
#          能夠保持idle狀態的最大數量
          max-idle: 100
          min-idle: 0
          max-wait: 3000
package com.lucky.spring.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Created by zhangdd on 2020/9/9
 */
@Component
@Data
public class RedisProperties {

    @Value("${spring.redis.cluster.nodes}")
    private String[] nodes;

    @Value("${spring.redis.timeout}")
    private int connectionTimeout;
    
}

package com.lucky.spring.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by zhangdd on 2020/9/9
 */
@Configuration
public class JedisClusterFactory {

    @Autowired
    private RedisProperties redisProperties;


    @Bean
    public JedisCluster jedisCluster() {
        Set<HostAndPort> nodes = new HashSet<>();
        for (String ipPort : redisProperties.getNodes()) {
            String[] ipPortPair = ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(),
                    Integer.valueOf(ipPortPair[1].trim())));
        }
        // jedis 連線池的配置沒有使用
        return new JedisCluster(nodes,
                redisProperties.getConnectionTimeout(),
                1000,
                1,
                new GenericObjectPoolConfig());//需要密碼連線的建立物件方式
    }
}

package com.lucky.spring;

import com.lucky.spring.config.RedisProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

@SpringBootApplication
public class Application implements CommandLineRunner {


    @Autowired
    RedisTemplate redisTemplate;


    @Autowired
    private JedisCluster jedisCluster;


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        //opeByRedisTemplate();
        opeByJedisCluster();
    }

    private void opeByRedisTemplate() {
        redisTemplate.opsForValue().set("name", "張三");
        String name = (String) redisTemplate.opsForValue().get("name");
        System.out.println(name);
    }

    private void opeByJedisCluster() {
        jedisCluster.set("name", "李四");
        System.out.println(jedisCluster.get("name"));
    }
}