Docker 搭建 Redis Cluster 集群環境

2021-02-20 哈嘍沃德先生

使用 Docker 搭建 Redis Cluster,最重要的環節就是容器通信的問題,這一塊我們在之前的文章中已經給大家解決了《Docker 網絡模式詳解及容器間網絡通信》,本篇文章主要練習使用多個容器完成 Redis Cluster 集群環境的搭建,順便為學習 Docker Compose 鋪鋪路。俗話說沒有對比就沒有傷害,通過對比才能感受到 Docker Compose 的好處😄。

關於 Redis Cluster 集群更多的內容請閱讀《最通俗易懂的 Redis 架構模式詳解》。


環境


本文所使用的基礎設施環境如下:


搭建


整體搭建步驟主要分為以下幾步:

下載 Redis 鏡像(其實這步可以省略,因為創建容器時,如果本地鏡像不存在,就會去遠程拉取);


創建網絡


為什麼需要創建網絡?因為:默認的 bridge 網絡是無法使用 DNS 的,所以我們就需要自定義網絡。說簡單點就是為了讓容器可以直接通過容器名稱進行通信。

從 Docker 1.10 版本開始,docker daemon 實現了一個內嵌的 DNS server,使容器可以直接通過容器名稱進行通信。方法很簡單,只要在創建容器時使用 --name 為容器命名即可。

但是使用 Docker DNS 有個限制:「只能在 user-defined 網絡中使用」。也就是說,默認的 bridge 網絡是無法使用 DNS 的,所以我們就需要自定義網絡。


通過 docker network create 命令可以創建自定義網絡模式,默認為 bridge 網橋/橋接模式,完整命令如下:

docker network create redis-net


通過 docker network ls 查看網絡模式:


我們還可以通過 docker network inspect redis-net 查看 redis-net 網絡的詳細信息:


編寫 Redis 配置文件


創建目錄及文件


# 創建目錄
mkdir -p /usr/local/docker-redis/redis-cluster
# 切換至指定目錄
cd /usr/local/docker-redis/redis-cluster/
# 編寫 redis-cluster.tmpl 文件
vi redis-cluster.tmpl


編寫配置文件


redis-cluster.tmpl 文件內容如下:

port ${PORT}
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port ${PORT}
cluster-announce-bus-port 1${PORT}

masterauth:如果主節點開啟了訪問認證,從節點訪問主節點需要認證;protected-mode:保護模式,默認值 yes,即開啟。開啟保護模式以後,需配置 bind ip 或者設置訪問密碼;關閉保護模式,外部網絡可以直接訪問;daemonize:是否以守護線程的方式啟動(後臺啟動),默認 no;appendonly:是否開啟 AOF 持久化模式,默認 no;cluster-enabled:是否開啟集群模式,默認 no;cluster-config-file:集群節點信息文件;cluster-node-timeout:集群節點連接超時時間;cluster-announce-ip:集群節點 IP,這裡需要特別注意一下,如果要對外提供訪問功能,需要填寫宿主機的 IP,如果填寫 Docker 分配的 IP(172.x.x.x),可能會導致外部無法正常訪問集群;cluster-announce-port:集群節點映射埠;cluster-announce-bus-port:集群節點總線埠。❝

每個 Redis 集群節點都需要打開「兩個 TCP 連接」。一個用於為客戶端提供服務的正常 Redis TCP 埠,例如 6379。還有一個基於 6379 埠加 10000 的埠,比如 16379。

第二個埠用於集群總線,這是一個使用二進位協議的節點到節點通信通道。節點使用集群總線進行故障檢測、配置更新、故障轉移授權等等。客戶端永遠不要嘗試與集群總線埠通信,與正常的 Redis 命令埠通信即可,但是請確保防火牆中的這兩個埠都已經打開,否則 Redis 集群節點將無法通信。


在 redis-cluster 目錄下執行以下命令:

for port in `seq 6371 6376`; do \
  mkdir -p ${port}/conf \
  && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \
  && mkdir -p ${port}/data;\
done

上面是一段 shell for 語句,意思就是循環創建 6371 ~ 6376 相關的目錄及文件。


查看命令執行結果,如果沒有 tree 命令先安裝 yum install -y tree。


以下內容為每個節點的配置文件詳細信息。

[root@localhost redis-cluster]# cat /usr/local/docker-redis/redis-cluster/637{1..6}/conf/redis.conf
port 6371
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6371
cluster-announce-bus-port 16371

port 6372
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6372
cluster-announce-bus-port 16372

port 6373
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6373
cluster-announce-bus-port 16373

port 6374
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6374
cluster-announce-bus-port 16374

port 6375
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6375
cluster-announce-bus-port 16375

port 6376
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.10.10
cluster-announce-port 6376
cluster-announce-bus-port 16376


創建 Redis 容器


創建容器


將宿主機的 6371 ~ 6376 之間的埠與 6 個 Redis 容器映射,並將宿主機的目錄與容器內的目錄進行映射(目錄掛載)。記得指定網絡模式,使用我們自己創建的 redis-net 網絡。

for port in $(seq 6371 6376); do \
  docker run -di -p ${port}:${port} -p 1${port}:1${port} \
  --restart always --name redis-${port} --net redis-net \
  -v /usr/local/docker-redis/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \
  -v /usr/local/docker-redis/redis-cluster/${port}/data:/data \
  redis redis-server /usr/local/etc/redis/redis.conf; \
done


docker ps -n 6 查看容器是否創建成功。


docker network inspect redis-net | grep -i -E "name|ipv4address" 查看給每個節點分配的IP信息。


創建 Redis Cluster 集群


隨便進入一個容器節點,並進入 /usr/local/bin/ 目錄:

# 進入容器
docker exec -it redis-6371 bash
# 切換至指定目錄
cd /usr/local/bin/


接下來我們就可以通過以下命令實現 Redis Cluster 集群的創建。

redis-cli -a 1234 --cluster create 172.18.0.2:6371 172.18.0.3:6372 172.18.0.4:6373 172.18.0.5:6374 172.18.0.6:6375 172.18.0.7:6376 --cluster-replicas 1


出現選擇提示信息,輸入 「yes」,結果如下所示:

集群創建成功如下:


以下內容是創建集群時返回的詳細信息,也就是上兩幅圖中的所有內容。

root@705a5ec95a2e:/usr/local/bin# redis-cli -a 1234 --cluster create 172.18.0.2:6371 172.18.0.3:6372 172.18.0.4:6373 172.18.0.5:6374 172.18.0.6:6375 172.18.0.7:6376 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> 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.18.0.6:6375 to 172.18.0.2:6371
Adding replica 172.18.0.7:6376 to 172.18.0.3:6372
Adding replica 172.18.0.5:6374 to 172.18.0.4:6373
M: 4dbede8f79c98a8cf63556387ce8c2a793d20089 172.18.0.2:6371
   slots:[0-5460] (5461 slots) master
M: c2117d59666f20be5a29485b2e22753991a2dcb9 172.18.0.3:6372
   slots:[5461-10922] (5462 slots) master
M: a5a8fdda426785c54a0e557b753ef571d22581a7 172.18.0.4:6373
   slots:[10923-16383] (5461 slots) master
S: 4aca662dbc0d40498592c11c8dcb94b62c39b15c 172.18.0.5:6374
   replicates a5a8fdda426785c54a0e557b753ef571d22581a7
S: 55fe2da8fe4fb1acdf950a6030a6304713eb613b 172.18.0.6:6375
   replicates 4dbede8f79c98a8cf63556387ce8c2a793d20089
S: be84c1e8600986d5ebfbd2e18611dc4d1ace41a7 172.18.0.7:6376
   replicates c2117d59666f20be5a29485b2e22753991a2dcb9
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.18.0.2:6371)
M: 4dbede8f79c98a8cf63556387ce8c2a793d20089 172.18.0.2:6371
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: be84c1e8600986d5ebfbd2e18611dc4d1ace41a7 192.168.10.10:6376
   slots: (0 slots) slave
   replicates c2117d59666f20be5a29485b2e22753991a2dcb9
M: c2117d59666f20be5a29485b2e22753991a2dcb9 192.168.10.10:6372
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: a5a8fdda426785c54a0e557b753ef571d22581a7 192.168.10.10:6373
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 4aca662dbc0d40498592c11c8dcb94b62c39b15c 192.168.10.10:6374
   slots: (0 slots) slave
   replicates a5a8fdda426785c54a0e557b753ef571d22581a7
S: 55fe2da8fe4fb1acdf950a6030a6304713eb613b 192.168.10.10:6375
   slots: (0 slots) slave
   replicates 4dbede8f79c98a8cf63556387ce8c2a793d20089
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.


至此一個高可用的 Redis Cluster 集群搭建完成,如下圖所示,該集群中包含 6 個 Redis 節點,3 主 3 從。三個主節點會分配槽,處理客戶端的命令請求,而從節點可用在主節點故障後,頂替主節點。


查看集群狀態


我們先進入容器,然後通過一些集群常用的命令查看一下集群的狀態。

# 進入容器
docker exec -it redis-6371 bash
# 切換至指定目錄
cd /usr/local/bin/


檢查集群狀態


因為我們使用了自定義的網絡進行容器管理,這樣可以使容器直接通過容器名稱通信。推薦使用這種方式。

# 使用 IP
redis-cli -a 1234 --cluster check 192.168.10.10:6371
# 使用容器名稱
redis-cli -a 1234 --cluster check redis-6372:6372


查看集群信息和節點信息


# 連接至集群某個節點
redis-cli -c -a 1234 -h redis-6373 -p 6373
# 查看集群信息
cluster info
# 查看集群結點信息
cluster nodes


SET/GET


在 6371 節點中執行寫入和讀取,命令如下:

# 進入容器並連接至集群某個節點
docker exec -it redis-6371 /usr/local/bin/redis-cli -c -a 1234 -h redis-6371 -p 6371
# 寫入數據
set name mrhelloworld
set aaa 111
set bbb 222
# 讀取數據
get name
get aaa
get bbb

別著急,讓我來解釋一下上圖中的操作過程:

然後執行「第一個」 set 命令 set name mrhelloworld,name 鍵根據哈希函數運算以後得到的值為 [5798]。當前集群環境的槽分配情況為:[0-5460] 6371節點,[5461-10922] 6372節點,[10923-16383] 6373節點,所以該鍵的存儲就被分配到了 「6372」 節點上;再來看「第二個」 set 命令 set aaa,這裡大家可能會有一些疑問,為什麼看不到 aaa 鍵根據哈希函數運算以後得到的值?因為剛才重定向至 「6372」 節點插入了數據,此時如果還有數據插入,正好鍵根據哈希函數運算以後得到的值也還在該節點的範圍內,那麼直接插入數據即可;接著是「第三個」 set 命令 set bbb,bbb 鍵根據哈希函數運算以後得到的值為 [5287],所以該鍵的存儲就被分配到了 「6371」 節點上;然後是讀取操作,「第四個」命令 get name,name 鍵根據哈希函數運算以後得到的值為 [5798],被重定向至 「6372」 節點讀取;「第五個」命令 get aaa,aaa 鍵根據哈希函數運算以後得到的值也在 「6372」 節點,直接讀取;「第六個」命令 get bbb,bbb 鍵根據哈希函數運算以後得到的值為 [5287],被重定向至 「6371」 節點讀取。


通過以上操作我們得知 name 鍵的存儲被分配到了 6372 節點,如果直接連接 6372 節點並獲取該值會怎麼樣?沒錯,不需要重定向節點,因為數據就在該節點,所以直接讀取返回。

總結下來就是,在 「Redis Cluster 集群模式」中,「無論連接哪個節點」,每次我們「執行寫入或者讀取」操作的時候,所有的「鍵會根據哈希函數運算並映射到 0 ~ 16383 整數槽內」,如果恰好對應的「槽」就在你「當前連接的節點」中,則「直接執行」命令,「否則重定向」至對應節點執行命令。


客戶端連接


最後來一波客戶端連接操作,隨便哪個節點,看看可否通過外部訪問 Redis Cluster 集群。

至此使用多個容器搭建 Redis Cluster 集群環境就到這裡,其實整體搭建過程不算特別麻煩,因為:

創建 Redis 集群需要用到 Ruby,否則就得自己關聯節點構建集群,自己分配槽;如果使用 Ruby 構建 Redis 集群,就需要安裝 Ruby 環境;而 Redis 從 5 版本開始可以直接使用 redis-cli 命令創建集群了,就省去了很多麻煩事;我們還使用了 shell for 循環語句簡化了構建過程,否則那些語句一條條執行也夠你鬧心的。

綜上所述,有沒有更簡單的辦法呢?當然有了,不然我在這跟你賣什麼關子。

Docker Compose 就可以解決這個問題。後面我們先學習一下什麼是 Docker Compose,然後使用 Docker Compose 再來搭建一遍 Redis Cluster 集群環境,感受感受這前後的區別。

相關焦點

  • Redis的集群搭建,原來這麼簡單
    回歸正題,上篇主要說了下Redis的主從複製是如何做的,高可用集群有幾種方式部署(傳送門《原來你是這樣的高可用呀》)。其中針對Redis高可用cluster集群說明時,有一些遺漏的東西,會在本篇前半部分進行說明,後面的內容主要是說怎麼來搭建cluster集群。
  • Redis服務​之Redis Cluster
    所謂無中心架構的cluster意思是集群中的每一個成員都是中心節點,每個成員擁有整個集群的狀態元數據,但各自又只存儲整個集群的部分數據;對於redis cluster這種架構來講,所有redis節點使用(ping機制)互聯,如果集群中某個節點的失敗,是需要整個集群中超過半數的節點監測都失效才算真正的失效;客戶端不需要 proxy 即可直接連接
  • Kind + Docker 一鍵部署K8s集群
    時下網際網路最火的技術無非是容器雲和AI,而虛擬雲技術方面最火則是docker和K8S。docker學習和實踐都很容易,但是K8S的由於集群化,部署需要較多的機器,環境搭建學習實踐比較費勁這一度影響了K8S技術的普及。
  • Docker集群管理之Docker Compose
    redis服務通過鏡像redis啟動。Docker Compose是由python語言實現的,它通過調用docker-py庫(可參考https://github.com/docker/docker-py)與docker engine通信實現構建docker鏡像,啟動停止docker容器等。
  • 開源 | Overlord:嗶哩嗶哩基於 Go 語言編寫的 memcache 和 redis&cluster 代理及集群管理組件
    點擊連結或圖片即可閱讀喜歡請分享到朋友圈哦Overlord 是嗶哩嗶哩基於 Go 語言編寫的 memcache 和 redis
  • 認識Redis集群——Redis Cluster
    之前沒有好好的全面理解Redis集群,特別是Redis Cluster,以為這就是redis集群的英文表達啊,故寫本篇博文來儘可能全面加深理解Redis Cluster。主要參考資料《Redis設計與實現》,主要是PDF電子版,有需要的朋友評論或者私聊! 一、Redis Cluster簡單概述1.
  • acl 框架中的 Redis 庫已經支持集群版 Redis 3.0
    redis 進行分庫了,之前人們為了使單機版的 redis 能支持集群方式,往往是在客戶端或通過加一個中間的代理層(比如使用 tweaproxy)做很多工作,現在有了集群版的 redis3.0 ,這些額外的操作都不再需要。
  • 現代程式設計師必須掌握的:Dockerfile 與 Compose 環境搭建學習筆記(二)
    ENV用來設置環境變量,例如:定義一些系統版本、路徑的環境變量,在後續RUN中可以使用(當然不僅僅是RUN中可用),也可以用改寫原有的環境變量,例如:PATH。RUN這是一個非常重要的命令,它是用來執行命令行的命令。就像上面看到的用 yum 安裝更新軟體,make編譯代碼等。
  • Redis Sentinel-深入淺出原理和實戰
    redis-sentinel-successquorum&majority❝大部分?大哥這可是要上生產環境,大部分這個數量未免也太敷衍了,咱就不能專業一點?硬核教程❝硬核教程旨在用最快速的方法,讓你在本地體驗Redis主從架構和Sentinel集群的搭建,並體驗整個故障轉移的過程。❞前置要求準備compose文件首先需要準備一個目錄,然後分別建立兩個子目錄。如下。$ tree ..
  • 雲計算核心技術Docker教程: Docker 安裝 Redis
    本文介紹通過docker安裝redis。1.我們用 docker search redis 命令來查看可用版本:2.取最新版的 Redis 鏡像,這裡我們拉取官方的最新版本的鏡像:$ docker pull redis:latest
  • 面試官:Redis有哪幾種集群方案?原理和優缺點是什麼?
    在開發測試環境中,我們一般搭建Redis的單實例來應對開發測試需求,但是在生產環境,如果對可用性、可靠性要求較高,則需要引入Redis的集群方案
  • 用 Docker 構建 MySQL 主從環境
    前言本篇文章記錄我使用 docker-compose 以及 dockerfile 來構建基於 binlog 的 MySQL 主從環境。如果你嚴格按照文中的步驟進行配置,相信很快就可以搭建好一個基礎的 MySQL 主從環境。
  • MacOS上使用K3d和Rancher管理本地K8S集群環境
    現在很多同學都是用MacBook進行開發,但是由於MacOS對docker支持不是很好,創建基於容器的環境也比較費勁。在本文中,我們介紹基於K3D在macOS上本地運行Rancher以進行Kubernetes集群開發和測試。概述K3D是輕量級包裝,可在Docker中運行Rancher Labs的K3S。
  • redis 槽是什麼專題及常見問題 - CSDN
    keyslot hello (integer) 866槽不命中:moved異常[root@mysql ~]# redis-cli -p 9002 cluster keyslot php (integer) 9244[root@mysql ~]# redis-cli -c -p 9002 127.0.0.1:9002> cluster keyslot
  • 用Docker 搭建Web服務環境
    開發環境只需要安裝配置一次,之後搭建相同的開發環境很簡單,只需要一條命令即可完成!這就是本文的目的,介紹 Docker 下安裝配置 Web 的服務環境,實現一次安裝配置,多次重用、跨平臺重用的功能。搭建 Web 服務環境本文的重點是使用 Docker 搭建一套 Web 服務環境,如果在你的環境中還沒有安裝 Docker,可以參考這裡自行安裝。
  • 【實戰】基於Nginx、Node.js和Redis的Docker工作流
    所以你只要默認配置ok就不需要修改任何配置,直接創建並運行Redis容器鏡像:docker run -d --name redis -p 6379:6379 redis如果你想從基於Ubuntu的鏡像構建Redis鏡像,Dockerfile會是這樣:
  • Docker Network—Bridge 模式
    none 模式不適用於集群服務。通過在 Docker 上安裝和使用第三方網絡插件可以算作額外的擴展方式。對比自定義 bridge(my-net)與默認 bridge(docker0)自定義 bridge 提供更好的隔離性和容器間的互操作性連接到同一個自定義 bridge 網絡的容器會自動將所有埠相互暴露,並且無法連接到容器之外的網絡。這使得容器化的應用能輕鬆地相互通信,並且與外部環境產生了良好的隔離性。例如一個包含了 web 應用,資料庫,redis 等組件的應用程式。
  • 開源電商系統mall-swarm後端docker搭建過程記錄
    背景1、基於docker進行本地後端的搭建,docker未建私服,直接使用docker-hub;2、部分基礎組件在虛已經擬機上面通過非docker鏡像方式安裝:具體涉及MySQL、Redis、Mongo、Elasticsearch3、下載源碼:
  • 雲計算核心技術Docker教程:Docker 守護進程dockerd節點發現
    dockerd --cluster-advertise選項指定 此特定守護程序實例在向集群發布自身時應使用的host:port或interface:port組合。遠程主機通過該值訪問守護程序。如果指定接口,請確保它包含實際Docker主機的IP位址。
  • 搭建前端開發環境――docker篇
    推廣 | 令人窒息的獎品等你―2016最權威的全球開發者調研 一、解決痛點 免搭建前端靜態環境 分支切換,無需重新啟動編譯(package.json或gulpfile.js文件改變除外) nginx