前言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
準備工具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實例運行在同一臺宿主機上
# 建立docker內部網絡 docker network create redis-cluster-net
# 建立 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
# 運行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
# 組裝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
# 建立docker-cluster docker run -it --rm --net redis-cluster-net redis-trib ruby redis-trib.rb create --replicas 1 $matches
2、redis實例運行在不一樣的宿主機上
這裏我將3個master實例運行在一臺機(10.82.12.95)上,3個slave實例運行在另外一臺機器(10.82.12.98)上
# 建立文件夾 for port in `seq 7000 7002`; do mkdir -p ./$port/ && mkdir -p ./$port/data \ && PORT=$port envsubst < ./redis-cluster.tmpl > ./$port/redis.conf; done
# 運行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
# 建立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
測試
執行命令: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操做工具,不知道朋友們有推薦嗎?另外,文章有任何不恰當的地方,歡迎各位留言指正