docker redis 集羣(cluster)搭建

前言html

        在開發環境中,你們應該都用的是redis單點吧,可是在生產環境中我相信沒有人敢用單點的,應該都是用的cluster,由於萬一單點掛掉的話,咱們的應用也就天然而然的ConnectionException。那麼,接下來我就記錄一下我本身用docker搭建redis-cluster吧!node

基本概念linux

        每一個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節點和A一、B一、C1三個slave節點組成,這個時候若是B失敗了,系統仍然可用。節點B1是B的副本,若是B失敗了,集羣會將B1提高爲新的master,從而繼續提供服務。然而,若是B和B1同時失敗了,那麼整個集羣將不可用。
        Redis集羣不能保證強一致性。換句話說,Redis集羣可能會丟失一些寫操做,緣由是由於它用異步複製。爲了使用redis-cluster,須要配置如下幾個參數:redis

  • 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

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

# 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

4、利用ruby鏡像構建一個redis-trib鏡像,由於搭建redis-cluster的時候須要用到redis-trib工具。redis-trib鏡像的Dockerfile以下(tips:我下載的ruby版本是:2.5-slim):網絡

FROM ruby:2.5-slim
MAINTAINER dongsilin<dslzc@foxmail.com>
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的時候須要用到。app

搭建異步

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

1、全部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的搭建,以下圖:

2、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)搭建

相關文章
相關標籤/搜索