0%

分布式系统实例之redis集群之集群搭建

[TOC]

主从模式(master/slaver)

redis的主从模式,使用异步复制,slave节点异步从master节点复制数据,master节点提供读写服务,slave节点只提供读服务(这个是默认配置,可以通过修改配置文件 slave-read-only 控制)。master节点可以有多个从节点。配置一个slave节点只需要在redis.conf文件中指定 slaveof master-ip master-port 即可。

从节点开启主从复制,有3种方式:

slaveof 192.168.81.135 6379

  • 配置文件
    • 在从服务器的配置文件中加入:slaveof
  • 启动命令
    • redis-server启动命令后加入:slaveof
  • 客户端命令
    • Redis服务器启动后直接通过客户端执行命令:slaveof,则该Redis实例成为从节点。

实例

配置

vi master-6739.conf

1
2
3
4
5
6
bind 0.0.0.0
port 6379
logfile "6379.log"
dbfilename "dump-6379.rdb"
daemonize yes
rdbcompression yes

vi slave-6380.conf

1
2
3
4
5
6
7
bind 0.0.0.0
port 6380
logfile "6380.log"
dbfilename "dump-6380.rdb"
daemonize yes
rdbcompression yes
slaveof 192.168.81.135 6379

master-6739.conf,为主节点配置文件,slave-6380.conf,slave-6381.conf为从节点配置文件
在从节点的配置文件中使用:slaveof 指定master节点

docker 部署

参看: go-mod/k8s/docker/redis

效果

1
2
3
4
5
6
7
8
9
10
11
12
|root@zjk-qa-k8s-node010 /data/percy/redis-5.0.9
|># src/redis-cli -p 7379
127.0.0.1:7379> set name percy
OK
127.0.0.1:7379> exit
|root@zjk-qa-k8s-node010 /data/percy/redis-5.0.9
|># src/redis-cli -p 7380
127.0.0.1:7380> get name
"percy"
127.0.0.1:7380> set name2 percy2
(error) READONLY You can't write against a read only replica.
127.0.0.1:7380>
  • 主节点写入的数据,从节点可以读取
  • 从节点默认不能写数据

问题分析

数据丢失

master服务挂了之后,重启服务后,slave节点会与master节点进行一次完整的重同步操作,所以由于master节点没有持久化,就导致slave节点上的数据也会丢失掉。所以在配置了Redis的主从模式的时候,应该打开主服务器的持久化功能。到这,redis的主从模式就已经完成了。

谈谈我认为主从模式的必要性:

主从模式的一个作用是备份数据,这样当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。
另一个作用是负载均衡,所有客户端都访问一个节点肯定会影响Redis工作效率,有了主从以后,查询操作就可以通过查询从节点来完成。

总结

  • 一个Master可以有多个Slaves

  • 默认配置下,master节点可以进行读和写,slave节点只能进行读操作,写操作被禁止 不要修改配置让slave节点支持写操作,没有意义,

    • 原因一,写入的数据不会被同步到其他节点;

    • 原因二,当master节点修改同一条数据后,slave节点的数据会被覆盖掉

  • slave节点挂了不影响其他slave节点的读和master节点的读和写,重新启动后会将数据从master节点同步过来

  • master节点挂了以后,不影响slave节点的读,Redis将不再提供写服务,master节点启动后Redis将重新对外提供写服务。

  • master节点挂了以后,不会将slave节点重新选一个master

主从节点的缺点

master节点挂了以后,redis就不能对外提供写服务了,因为剩下的slave不能成为master
这个缺点影响是很大的,尤其是对生产环境来说,是一刻都不能停止服务的,所以一般的生产坏境是不会单单只有主从模式的。所以有了下面的sentinel模式。

sentinel模式 (哨兵模式)

Redis哨兵模式,用现在流行的话可以说就是一个“哨兵机器人”,给“哨兵机器人”进行相应的配置之后,这个”机器人”可以7*24小时工作,它能能够自动帮助你做一些事情,如监控,提醒,自动处理故障等。

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance),Redis 的 Sentinel 为Redis提供了高可用性。使用哨兵模式创建一个可以不用人为干预而应对各种故障的Redis部署。

该系统执行以下三个任务:

  • 监控(Monitoring):Sentinel会不断地检查你的主服务器和从服务器是否允许正常。
  • 提醒(Notification):当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。
  • 自动故障迁移(Automatic failover):
    • (1)当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移操作,他会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器
    • (2)客户端试图连接失败的主服务器时,集群也会向客服端返回新主服务器的地址,集群可以使用新主服务器代替失效服务器。

sentinel的分布式特性

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群,一个健壮的部署至少需要三个哨兵实例。

docker 部署

参看: go-mod/k8s/docker/redis

效果

1
2
3
4
5
6
7
8
|># redis-cli -h 127.0.0.1 -p 27379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:7379,slaves=2,sentinels=1

故障转移

1
2
3
4
5
6
7
8
# shutdown 主节点
|># redis-cli -p 7379
127.0.0.1:7379> shutdown
not connected> exit

# 7380 切换为了主节点, 可以写入数据
|># redis-cli -p 7380
127.0.0.1:7380> set age 12

cluster模式

Redis Cluster是Redis官方的一个高可用分布式解决方案。Redis Cluster中共有2 ^ 14(16384)个槽,创建集群后,需要将这些槽均分给各个节点。

cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。

因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容这种模式适合数据量巨大的缓存要求,当数据量不是很大使用sentinel即可。

节点配置

节点名称 端口号 主/从节点 复制的节点
redis-7005 7005 主节点
redis-7004 7004 主节点
redis-7003 7003 主节点
redis-7002 7002 从节点 redis-7003
redis-7001 7001 从节点 redis-7005
redis-7000 7000 从节点 redis-7004

docker 部署

参看: go-mod/k8s/docker/redis/cluster/v2

查看启动

1
2
3
4
5
|># docker logs 026b1864a49c
1:C 18 Aug 2020 03:37:00.175 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 18 Aug 2020 03:37:00.175 # Redis version=6.0.6, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 18 Aug 2020 03:37:00.175 # Configuration loaded
1:M 18 Aug 2020 03:37:00.176 * No cluster configuration found, I'm 4efdfb5b0dadeec44d23f97038e5d29a01e000b0

可以看到Redis在集群模式下启动,因为初始的时候没有集群配置,所以自动创建了配置(文件名就是在redis-6379.conf中指定的)。

然后来看一下自动创建的及集群配置。这个文件记录了集群的初始状态,前面那个很长的字符串就是节点ID。

cluster 模式下的 smart client

可以看到 set name 时, 不管你在哪个节点, cluster 都会告诉你,正确的节点是哪一个,并且不会帮你执行这个操作, client 必须 聪明的拿到正确节点的地址,然后连接上正确的节点上去执行 set get.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|root@zjk-qa-k8s-node010 /tmp/percy/v2
|># redis-cli -p 7000
127.0.0.1:7000> set name percy
(error) MOVED 5798 127.0.0.1:7001
127.0.0.1:7000>
|root@zjk-qa-k8s-node010 /tmp/percy/v2
|># redis-cli -p 7001
127.0.0.1:7001> set name percy
OK
127.0.0.1:7001>
|root@zjk-qa-k8s-node010 /tmp/percy/v2
|># redis-cli -p 7002
127.0.0.1:7002> get name
(error) MOVED 5798 127.0.0.1:7001
127.0.0.1:7002>
|root@zjk-qa-k8s-node010 /tmp/percy/v2
|># redis-cli -p 7001
127.0.0.1:7001> get name
"percy"
127.0.0.1:7001>

参考

redis主从及哨兵

docker搭建redis集群