docker redis 集羣(cluster)搭建 原 薦

前言

        在開發環境中,大家應該都用的是redis單點吧,但是在生產環境中我相信沒有人敢用單點的,應該都是用的cluster,因爲萬一單點掛掉的話,我們的應用也就自然而然的ConnectionException。那麼,接下來我就記錄一下我自己用docker搭建redis-cluster吧!

基本概念

        每個Redis集羣中的節點都需要打開兩個TCP連接。一個連接用於正常的給Client提供服務,比如6379,還有一個額外的端口(通過在這個端口號上加10000)作爲數據端口,比如16379。第二個端口(本例中就是16379)用於集羣總線,這是一個用二進制協議的點對點通信信道。這個集羣總線(Cluster bus)用於節點的失敗偵測、配置更新、故障轉移授權,等等。客戶端從來都不應該嘗試和這些集羣總線端口通信,它們只應該和正常的Redis命令端口進行通信。注意,確保在你的防火牆中開放着兩個端口,否則,Redis集羣節點之間將無法通信。命令端口和集羣總線端口的偏移量總是10000。
        Redis集羣不同一致性哈希,它用一種不同的分片形式,在這種形式中,每個key都是一個概念性(hash slot)的一部分。Redis集羣中的每個節點負責一部分hash slots,並允許添加和刪除集羣節點。比如,如果你想增加一個新的節點D,那麼久需要從A、B、C節點上刪除一些hash slot給到D。同樣地,如果你想從集羣中刪除節點A,那麼會將A上面的hash slots移動到B和C,當節點A上是空的時候就可以將其從集羣中完全刪除。因爲將hash slots從一個節點移動到另一個節點並不需要停止其它的操作,添加、刪除節點以及更改節點所維護的hash slots的百分比都不需要任何停機時間。也就是說,移動hash slots是並行的,移動hash slots不會影響其它操作。
        爲了保持可用,Redis集羣用一個master-slave模式,這樣的話每個hash slot就有1到N個副本。而redis-cluster規定,至少需要3個master和3個slave,即3個master-slave對。當我們給每個master節點添加一個slave節點以後,我們的集羣最終會變成由A、B、C三個master節點和A1、B1、C1三個slave節點組成,這個時候如果B失敗了,系統仍然可用。節點B1是B的副本,如果B失敗了,集羣會將B1提升爲新的master,從而繼續提供服務。然而,如果B和B1同時失敗了,那麼整個集羣將不可用。
        Redis集羣不能保證強一致性。換句話說,Redis集羣可能會丟失一些寫操作,原因是因爲它用異步複製。爲了使用redis-cluster,需要配置以下幾個參數:

  • cluster-enabled <yes/no>: 如果是yes,表示啓用集羣,否則以單例模式啓動
  • cluster-config-file <filename>: 可選,這不是一個用戶可編輯的配置文件,這個文件是Redis集羣節點自動持久化每次配置的改變,爲了在啓動的時候重新讀取它。
  • cluster-node-timeout <milliseconds>: 超時時間,集羣節點不可用的最大時間。如果一個master節點不可到達超過了指定時間,則認爲它失敗了。注意,每一個在指定時間內不能到達大多數master節點的節點將停止接受查詢請求。
  • cluster-slave-validity-factor <factor>: 如果設置爲0,則一個slave將總是嘗試故障轉移一個master。如果設置爲一個正數,那麼最大失去連接的時間是node timeout乘以這個factor。
  • cluster-migration-barrier <count>: 一個master和slave保持連接的最小數量(即:最少與多少個slave保持連接),也就是說至少與其它多少slave保持連接的slave纔有資格成爲master。
  • cluster-require-full-coverage <yes/no>: 如果設置爲yes,這也是默認值,如果key space沒有達到百分之多少時停止接受寫請求。如果設置爲no,將仍然接受查詢請求,即使它只是請求部分key。 

準備工具

一、安裝docker
二、在docker庫獲取鏡像:redis,ruby;下載redis-trib.rb(命令:wget http://download.redis.io/redis-stable/src/redis-trib.rb)
三、找到一份原始的redis.conf文件,將其重命名爲:redis-cluster.tmpl,並配置如下幾個參數,此文件的目的是生成每一個redis實例的redis.conf:

# bind 127.0.0.1
protected-mode no
port ${PORT}
daemonize no
dir /data/redis
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000

四、利用ruby鏡像構建一個redis-trib鏡像,因爲搭建redis-cluster的時候需要用到redis-trib工具。redis-trib鏡像的Dockerfile如下(tips:我下載的ruby版本是:2.5-slim):

FROM ruby:2.5-slim
MAINTAINER dongsilin<[email protected]>
RUN gem install redis
RUN mkdir /redis
WORKDIR /redis
ADD ./redis-trib.rb /redis/redis-trib.rb

通過命令(docker build -t redis-trib .),即可構建出redis-trib鏡像,後續搭建redis-cluster的時候需要用到。

搭建

        這裏我準備的是2套環境:所有redis實例運行在同一臺宿主機上;redis實例運行在不同的宿主機上。相信大家在生產環境中都應該是部署在不同的機器上,下面我將分別講述:

一、所有redis實例運行在同一臺宿主機上

  1. 由於此處所有redis實例運行在同一臺宿主機,而redis-cluster之間需要通信,所以需要創建docker network
    # 創建docker內部網絡
    docker network create redis-cluster-net
  2. 創建 master 和 slave 文件夾並生成配置文件,用於存放配置文件redis.conf以及redis數據
    # 創建 master 和 slave 文件夾
    for port in `seq 7000 7005`; do
        ms="master"
        if [ $port -ge 7003 ]; then
            ms="slave"
        fi
        mkdir -p ./$ms/$port/ && mkdir -p ./$ms/$port/data \
        && PORT=$port envsubst < ./redis-cluster.tmpl > ./$ms/$port/redis.conf;
    done
  3. 運行docker redis 的 master 和 slave 實例
    # 運行docker redis 的 master 和 slave 實例
    for port in `seq 7000 7005`; do
        ms="master"
        if [ $port -ge 7003 ]; then
            ms="slave"
        fi
        docker run -d -p $port:$port -p 1$port:1$port \
        -v $PWD/$ms/$port/redis.conf:/data/redis.conf \
        -v $PWD/$ms/$port/data:/data/redis \
        --restart always --name redis-$ms-$port --net redis-cluster-net \
        redis redis-server /data/redis.conf;
    done
  4. 組裝masters : slaves 節點參數
    # 組裝masters : slaves 節點參數
    matches=""
    for port in `seq 7000 7005`; do
        ms="master"
        if [ $port -ge 7003 ]; then
            ms="slave"
        fi
        matches=$matches$(docker inspect --format '{{(index .NetworkSettings.Networks "redis-cluster-net").IPAddress}}' "redis-$ms-${port}"):${port}" ";
    done
  5. 創建docker-cluster,這裏就用到了上面的redis-trib鏡像
    # 創建docker-cluster
    docker run -it --rm --net redis-cluster-net redis-trib ruby redis-trib.rb create --replicas 1 $matches
  6. 執行第5步的命令後,需要在接下來的console中輸入“yes”,即可完成docker-cluster的搭建,如下圖:

二、redis實例運行在不同的宿主機上
        這裏我將3個master實例運行在一臺機(10.82.12.95)上,3個slave實例運行在另一臺機器(10.82.12.98)上

  1. 在兩臺機器上分別創建文件夾
    # 創建文件夾
    for port in `seq 7000 7002`; do
        mkdir -p ./$port/ && mkdir -p ./$port/data \
        && PORT=$port envsubst < ./redis-cluster.tmpl > ./$port/redis.conf;
    done
  2. 在兩臺機器上分別運行docker redis 實例,注意這裏就沒有使用docker network了,直接使用的是宿主機的host,原因是要在不同機器的docker容器中通信是很麻煩的,有興趣的朋友可以看下相關文章
    # 運行docker redis 實例
    for port in `seq 7000 7002`; do
        docker run -d \
        -v $PWD/$port/redis.conf:/data/redis.conf \
        -v $PWD/$port/data:/data/redis \
        --restart always --name redis-$port --net host \
        redis redis-server /data/redis.conf;
    done
  3. 在任意一臺機器上創建docker-cluster
    # 創建docker-cluster
    docker run -it --rm redis-trib ruby redis-trib.rb create --replicas 1 10.82.12.95:7000 10.82.12.95:7001 10.82.12.95:7002 10.82.12.98:7000 10.82.12.98:7001 10.82.12.98:7002
  4. 執行第3步的命令後,需要在接下來的console中輸入“yes”,即可完成docker-cluster的搭建

測試

執行命令:docker exec -it redis-7000 redis-cli -c -h 10.82.12.95 -p 7000,就進入了redi-cli界面,可以進行任何騷操作,比如:

注意Redirected to slot [xxxx] located at xxxx,證明了每個節點負責一部分hash slots。

結語

這篇文章需要有一定的linux、redis和docker基礎的朋友才能看懂,不然看起來有些概念懵懵懂懂。現在docker越來越流行,相信不少的朋友都有涉足吧!我在搭建的工程中,開始使用的是RedisDesktopManager-v0.8.8.384,連接和get命令沒問題,就是不能執行set命令,升級到0.9.3.817後倒是呢能夠執行get和set命令,但是出現可以重複的現象,懵逼了好久。
經過測試,用程序代碼操作是沒有任何問題的,估計是RedisDesktopManager-0.9.3.817有bug,而RedisDesktopManager-v0.8.8.384不支持redis-cluster。最後,我想求一款好用的支持redis-cluster的redis操作工具,不知道朋友們有推薦嗎?另外,文章有任何不恰當的地方,歡迎各位留言指正

 

參考:
Redis集羣
docker redis4.0 集羣(cluster)搭建

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章