Redis 高可用 Docker 化的简单部署

一、Docker安装Redis

获取Redis镜像

$ docker search  redis
$ docker pull  redis
$ docker images redis 

Redis 的配置文件可以从Redis官方站点获取

$ wget -c http://download.redis.io/redis-stable/redis.conf

使用Redis镜像

$ docker run -d --name redis -p 6379:6379 -v $PWD/data:/data -v $PWD/redis:/usr/local/etc/redis redis redis-server --appendonly yes

命令说明:
--name reids :将容器的名字设置为redis
-p 6379:6379 : 将容器的6379端口映射到主机的6379端口
-v $PWD/data:/data : 将主机中当前目录下的data挂载到容器的/data
-v $PWD/redis/redis.conf:/usr/local/etc/redis/redis.conf :将主机中当前目录下的redis/redis.conf挂载到容器的/usr/local/etc/redis/redis.conf
redis-server --appendonly yes : 在容器执行redis-server启动命令,并打开redis持久化配置

$PWD/data 与 $PWD/redis 两个目录会在创建容器执行挂载数据卷时创建

Redis 的配置文件可以从Redis官方站点获取

$ wget -c http://download.redis.io/redis-stable/redis.conf
$ mv ./redis.conf $PWD/redis/redis.conf

进入Reids容器

$ docker exec -it redis bash
$ cat /usr/local/etc/redis/redis.conf  
# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

# Note on units: when memory size is needed, it is possible to specify
...

或

$ docker exec -it 604030a2282c redis-cli
127.0.0.1:6379> info
# Server
redis_version:5.0.3
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:9e58cc62e6e78bea
redis_mode:standalone
os:Linux 4.14.98-boot2docker x86_64
arch_bits:64
...

Redis数据库内查看Redis配置

127.0.0.1:6379> config get *
1) "dbfilename"
2) "dump.rdb"
3) "requirepass"
4) ""
5) "masterauth"
6) ""
7) "cluster-announce-ip"
8) ""
...

你可以通过修改 redis.conf 文件或使用 CONFIG set 命令来修改配置。

CONFIG SET 命令基本语法:

redis 127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE

redis 127.0.0.1:6379> CONFIG SET loglevel "notice"
OK
redis 127.0.0.1:6379> CONFIG GET loglevel

1) "loglevel"
2) "notice"

二、Redis持续化

Redis 提供了不同级别的持久化方式:

1. RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
3. 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
4. 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.

Redis的持久化存储提供两种方式:RDB与AOF。RDB是默认配置。AOF需要手动开启。

RBD配置需要修改redis.conf文件中 SNAPSHOTTING 标题下的信息

save 900 1                              # 指定在多长时间内,有多少次更新操作,就将数据同步到磁盘,可以多个条件配合
save 300 10                             # 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改
save 60 10000
stop-writes-on-bgsave-error yes         
rdbcompression yes                      # 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩
rdbchecksum yes
dbfilename dump.rdb                     # 指定本地数据库文件名,默认值为dump.rdb
dir ./                                  # 指定本地数据库存放目录

AOF配置需要修改redis.conf文件中 APPEND ONLY MODE 标题下的信息

appendonly no                           # 是否开启AOF模式
appendfilename "appendonly.aof"         # AOF模式的文件名

# appendfsync always                    # AOF写入磁盘的间隔:always:有写入就写入磁盘
appendfsync everysec                    # everysec:每秒同步一次
# appendfsync no                        # 不设置同步,由操作系统执行写入磁盘
no-appendfsync-on-rewrite no            # 是否开启延写入,针对磁盘I/O占用问题
auto-aof-rewrite-percentage 100         # 指定触发AOF后台重写的百分比参数,设置0则禁用AOF重写功能
auto-aof-rewrite-min-size 64mb          # 指定要重写的AOF文件的最小大小
aof-load-truncated yes
aof-use-rdb-preamble yes

三、Redis主从复制

实现主从复制(Master-Slave Replication)的工作原理:

Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC命令。
Master服务主节点收到同步命令后将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。
而Slave从节点服务在接收到数据库文件数据之后将其存盘并加载到内存中。
此后,Master主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。

主从复制配置:

主从复制的配置很简单,主要操作从节点的配置文件,主节点不需要任何改动。
1. 修改从节点的配置文件:slaveof <masterip> <masterport>
2. 如果设置了密码,就要设置:masterauth <master-password>
我们可以使用 info Replication 命令查看主服务或从服务。

主从复制特点:

1. 同一个Master可以同步多个Slaves。
2. Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
3. Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
4. Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
5. 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
6. Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
7. 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

四、Reids哨兵

Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用。

Sentinel(哨兵)的配置文件可以从Redis官方站点获取

$ wget -c http://download.redis.io/redis-stable/sentinel.conf

Sentinel(哨兵)进程的作用:

1. 监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
2. 自动故障转移(Automatic Failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。
3. 配置提供者(Configuration Provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址。
4. 通知(Notification):哨兵可以将故障转移的结果发送给客户端。

Sentinel(哨兵)进程的工作方式:

1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。
3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态。
4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)。
5. 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

Sentinel(哨兵)所需的最少配置如下所示:

port 26379                                          # 哨兵端口号保持不变,可以修改
dir /root/application/program/redis/sentinel/       # 哨兵程序的日志路径

sentinel monitor mymaster 127.0.0.1 6379 2          # 指定了 Sentinel 监视这个master,并且只有在足够数量的 Sentinel 同意的情况下,才会将Master主服务器会被标记为客观下线
sentinel down-after-milliseconds mymaster 60000     # 指定了 Sentinel 检测服务器宕机的间隔的毫秒数
sentinel failover-timeout mymaster 180000           # 制定了指定了故障转移超时的毫秒数
sentinel parallel-syncs mymaster 1                  # 指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步

Sentinel(哨兵)启动

对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:

$ redis-sentinel /path/to/sentinel.conf

对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:

$ redis-server /path/to/sentinel.conf --sentinel

五、Reids集群

基本概念

每个Redis集群中的节点都需要打开两个TCP连接。

一个连接用于正常的给Client提供服务,比如6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,比如16379。
第二个端口(本例中就是16379)用于集群总线,这是一个用二进制协议的点对点通信信道。

这个集群总线(Cluster bus)用于节点的失败侦测、配置更新、故障转移授权,等等。
客户端从来都不应该尝试和这些集群总线端口通信,它们只应该和正常的Redis命令端口进行通信。

注意,确保在你的防火墙中开放着两个端口,否则,Redis集群节点之间将无法通信。

在某些部署中,Redis集群节点地址发现失败,因为地址是NAT-ted或因为端口被转发(典型的情况是Docker和其他容器)。
为了使Redis集群在这样的环境中工作,需要一个静态配置,其中每个节点都知道它的公共地址。此范围使用以下两个选项,分别是:

# * cluster-announce-ip
# * cluster-announce-port
# * cluster-announce-bus-port

每个节点指示其地址、客户端端口和集群消息总线端口。然后在总线包的报头中发布信息,以便其他节点能够正确映射发布信息的节点的地址。如果没有使用上面的选项,将使用普通的Redis集群自动检测。

注意,当重新映射时,总线端口可能不处于客户端端口+10000的固定偏移量,因此您可以根据重新映射的方式指定任何端口和总线端口。如果总线端口没有设置,则通常使用10000的固定偏移量。

例子:

# cluster-announce-ip 10.1.1.5
# cluster-announce-port 6379
# cluster-announce-bus-port 6380

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

应用部署

找到一份原始的redis.conf文件,将其重命名为:redis-cluster.tmpl,并配置如下几个参数,此文件的目的是生成每一个redis实例的redis.conf:

$ vim redis-cluster.tmpl
    # 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
    cluster-announce-ip 192.168.99.100
    cluster-announce-port ${PORT}
    cluster-announce-bus-port 1${PORT}

创建用于存放配置文件redis.conf以及redis数据的目录,这里修改了redis-cluster.tmpl的 ${PORT} 和使用了 envsubst 命令

$ vim mkdir-redisdir
    for port in `seq 7000 7005`; do
        mkdir -p ./$port/ && mkdir -p ./$port/data \
        && PORT=$port envsubst < ./redis-cluster.tmpl > ./$port/redis.conf;
    done
$ chmod +x mkdir-redisdir 
$ ./mkdir-redisdir 

运行docker redis容器

$ vim docker-run-redis.sh
    for port in `seq 7000 7005`; do
        docker run -d -p $port:$port -p 1$port:1$port \
        -v $PWD/$port/redis.conf:/data/redis.conf \
        -v $PWD/$port/data:/data/redis \
        --restart always --name redis-$port \
        redis redis-server /data/redis.conf;
    done
$ chmod +x docker-run-redis.sh
$ ./docker-run-redis.sh    

创建集群

实验使用的Redis版本为server v=5.0.3 ,以前的版本可能需要使用Ruby命令创建。

# redis-cli --cluster create 192.168.99.100:7000 192.168.99.100:7001 192.168.99.100:7002 192.168.99.100:7003 192.168.99.100:7004 192.168.99.100:7005 --cluster-replicas 1

>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.99.100:7003 to 192.168.99.100:7000
Adding replica 192.168.99.100:7004 to 192.168.99.100:7001
Adding replica 192.168.99.100:7005 to 192.168.99.100:7002
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: c3fdccf4e6f27c17fd6244df069c883607461e62 192.168.99.100:7000
   slots:[0-5460] (5461 slots) master
M: 879d41edefa930dba2d1b603df853d328fc0b613 192.168.99.100:7001
   slots:[5461-10922] (5462 slots) master
M: ce892407f64be9dd9dbcb00a6ea29094867b919d 192.168.99.100:7002
   slots:[10923-16383] (5461 slots) master
S: 767cfcc95d4472a445e0d321d20e5d52c5c3f9b9 192.168.99.100:7003
   replicates ce892407f64be9dd9dbcb00a6ea29094867b919d
S: 3d8f722c67d392b078351c347dfedf5403a5c9c4 192.168.99.100:7004
   replicates c3fdccf4e6f27c17fd6244df069c883607461e62
S: 0a355529fbeaa4d5164c917b8e0f35a0d95f1695 192.168.99.100:7005
   replicates 879d41edefa930dba2d1b603df853d328fc0b613
Can I set the above configuration? (type 'yes' to accept): 

确认配置信息后输出yes完成创建。

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 192.168.99.100:7000)
M: c3fdccf4e6f27c17fd6244df069c883607461e62 192.168.99.100:7000
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: ce892407f64be9dd9dbcb00a6ea29094867b919d 192.168.99.100:7002
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 3d8f722c67d392b078351c347dfedf5403a5c9c4 192.168.99.100:7004
   slots: (0 slots) slave
   replicates ce892407f64be9dd9dbcb00a6ea29094867b919d
M: 879d41edefa930dba2d1b603df853d328fc0b613 192.168.99.100:7001
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 0a355529fbeaa4d5164c917b8e0f35a0d95f1695 192.168.99.100:7005
   slots: (0 slots) slave
   replicates c3fdccf4e6f27c17fd6244df069c883607461e62
S: 767cfcc95d4472a445e0d321d20e5d52c5c3f9b9 192.168.99.100:7003
   slots: (0 slots) slave
   replicates 879d41edefa930dba2d1b603df853d328fc0b613
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

测试集群

登陆集群

$ redis-cli -c -h 192.168.99.100 -p 7000
# 需要 -c 表示登陆集群 -h 指定登陆地址 -p 指定登陆端口

使用Cluster Nodes命令和Cluster Info命令来看看集群效果

192.168.99.100:7000> cluster nodes
ce892407f64be9dd9dbcb00a6ea29094867b919d 192.168.99.100:7002@17002 master - 0 1551324638000 3 connected 10923-16383
3d8f722c67d392b078351c347dfedf5403a5c9c4 192.168.99.100:7004@17004 slave ce892407f64be9dd9dbcb00a6ea29094867b919d 0 1551324637000 5 connected
879d41edefa930dba2d1b603df853d328fc0b613 192.168.99.100:7001@17001 master - 0 1551324637796 2 connected 5461-10922
c3fdccf4e6f27c17fd6244df069c883607461e62 192.168.99.100:7000@17000 myself,master - 0 1551324639000 1 connected 0-5460
0a355529fbeaa4d5164c917b8e0f35a0d95f1695 192.168.99.100:7005@17005 slave c3fdccf4e6f27c17fd6244df069c883607461e62 0 1551324639807 6 connected
767cfcc95d4472a445e0d321d20e5d52c5c3f9b9 192.168.99.100:7003@17003 slave 879d41edefa930dba2d1b603df853d328fc0b613 0 1551324638803 4 connected

192.168.99.100:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:999
cluster_stats_messages_pong_sent:1007
cluster_stats_messages_sent:2006
cluster_stats_messages_ping_received:1002
cluster_stats_messages_pong_received:999
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:2006
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值