所谓的高可用,也叫HA
(High Availability),是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间
。如果在实际生产中,如果redis只部署一个节点,当机器故障时,整改服务都不能提供服务了。这就是我们常说的单点故障
。
redis高可用的三种模式:主从模式,哨兵模式,集群模式
1 主从模式
1.1 概述
一般,系统的高可用都是通过部署多台机器实现的。redis为了避免单点故障,也需要部署多台机器,因此就会涉及到不同机器的的数据同步问题,redis提供了Redis提供了复制(replication)功能
,当一台redis数据库中的数据发生了变化,这个变化会被自动的同步到其他的redis机器上去
。
在主从模式下redis机器节点会被分成两类,一类是主节点(master节点),一类是从节点(slave节点)。一般主节点可以进行读、写
操作,而从节点只能进行读
操作。当主节点的数据发生变化时,会将变化的数据同步
给从节点,这样从节点的数据就可以和主节点的数据保持一致了。一个主节点可以有多个从节点,但是一个从节点会只会有一个主节点,也就是所谓的一主多从结构。
Redis 主从同步分为:主从模式和从从模式。
1.2 主从同步模式
主从模式
就是一个主节点和多个一级从节点:
1.3 从从同步模式
而从从模式
是指一级从节点下面还可以拥有更多的从节点,Slave同样可以接受其他Slaves的连接和同步请求,这样可以有效地分载Master的同步压力
:
1.4 主从模式配置
# 配置主节点的ip和端口
slaveof 192.168.1.110 6379
# 从redis2.6开始,从节点默认是只读的
slave-read-only yes
# 假设主节点有登录密码,是123456
masterauth 123456
1.5 主从模式特点
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
- 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务依然必须由Master来完成;
- Slave同样可以接受其他Slaves的连接和同步请求,这样可以有效地分载Master的同步压力;
- Master是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求;
- Slave同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
1.6 主从复制原理
-
Slave 启动成功连接到 master 后会发送一个 sync 命令;
-
Master 接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个数据文件到 slave,以完成一次完全同步。
-
全量复制:slave 服务器在接收到数据库文件数据后,将其存盘并加载到内存中。
-
增量复制:Master 继续将新的所有收集到的修改命令依次传给 slave,完成同步。
-
但是只要是重新连接 master,一次完全同步(全量复制) 将被自动执行。
1.7 主从模式缺点
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复;
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性;
- 如果多个Slave断线了,需要重启的时候,尽量不要在同一时间段进行重启。因为只要Slave启动,就会发送sync请求和主机全量同步,当多个Slave重启的时候,可能会导致Master IO剧增从而宕机。
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂;
- redis的主节点和从节点中的数据是一样的,降低的内存的可用性
- 原生复制的弊端在早期的版本也会比较突出,如:Redis复制中断后,Slave会发起psync,此时如果同步不成功,则会进行全量同步,主库执行全量备份的同时可能会造成毫秒或秒级的卡顿;又由于COW机制,导致极端情况下的主库内存溢出,程序异常退出或宕机;
2 哨兵模式
2.1 概述
主从模式下,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这种方式并不推荐,实际生产中,我们优先考虑哨兵模式
。这种模式下,master宕机,哨兵会自动选举master并将其他的slave指向新的master。
在主从模式下,redis同时提供了哨兵命令redis-sentinel
,哨兵是一个独立的进程
,作为进程,它会独立运行。其原理是哨兵进程向所有的redis机器发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵可以有多个,一般为了便于决策选举,使用奇数
个哨兵。哨兵可以和redis机器部署在一起,也可以部署在其他的机器上。多个哨兵构成一个哨兵集群,哨兵之间也会相互通信,检查哨兵是否正常运行,同时发现master宕机哨兵之间会进行决策选举新的master
哨兵模式的作用:
监控
(Monitoring):Sentinel不断的去检查你的主从实例是否按照预期在工作。通知
(Notification):Sentinel可以通过一个api来通知系统管理员或者另外的应用程序,被监控的Redis实例有一些问题。自动故障转移
(Automatic failover):如果一个主节点没有按照预期工作,Sentinel会开始故障转移过程,把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,使用Redis服务的应用程序在连接的时候也被通知新的地址。配置提供者
(Configuration provider):Sentinel给客户端的服务发现提供来源:对于一个给定的服务,客户端连接到Sentinels来寻找当前主节点的地址。当故障转移发生的时候,Sentinels将报告新的地址。
2.2 哨兵模式配置和启动
每台机器的哨兵进程都需要一个哨兵的配置文件sentinel.conf
,三台机器的哨兵配置是一样的。
# 禁止保护模式
protected-mode no
# 配置监听的主服务器,这里sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,
#192.168.1.10代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
sentinel monitor mymaster 192.168.1.110 6379 2
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
sentinel auth-pass mymaster 123456
首先启动主节点,然后一台一台启动从节点,redis集群启动完成后,分别启动哨兵集群所在机器的三个哨兵:
redis-sentinel /path/to/sentinel.conf
2.3 哨兵模式工作原理
假设master宕机,sentinel 1先检测到这个结果,系统并不会马上进行 failover(故障转移)选出新的master,仅仅是sentinel 1主观的认为master不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由sentinel 1发起,进行 failover 操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器
实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
-
每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器、Slave从服务器以及其他Sentinel(哨兵)进程发送一个
PING
命令。 -
如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过
down-after-milliseconds
选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线
(SDOWN) -
如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的
所有 Sentinel
(哨兵)进程要以每秒一次
的频率确认Master主服务器的确进入了主观下线状态 -
当有
足够数量
的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线
(ODOWN) -
在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
-
当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
-
若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
-
当Sentinel集群客观的认为master宕机,就会从所有的Sentinel节点中,选出一个Sentinel节点,来最终执行master的
故障转移
。
2.4 哨兵模式优缺点
优点:
- 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
- 主从可以自动切换,系统更健壮,可用性更高。
缺点:
- 部署相对Redis 主从模式要复杂一些,原理理解更繁琐
- 中心化的集群实现方案:始终只有一个Redis主机来接收和处理
写
请求,写操作受单机瓶颈影响。 - 具有主从模式的缺点,每台机器上的数据是一样的,内存的可用性较低。
- 由于所有的写操作都是先在 Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重。
2.5 Sentinel API
Sentinel提供了一个API,可以用来检查它的状态,检查主节点和从节点的健康,订阅具体的通知并在运行时改变Sentinel的配置。
默认情况下Sentinel使用TCP端口号26379。Sentinels接收使用Redis的协议命令,可以使用redis-cli或者其他的Redis客户端来使用Sentinel。
下面是可以接收的命令列表,没有覆盖到那些用来改变Sentinel配置的命令:
- PING 这个命令仅仅返回PONG。
- SENTINEL masters 展示监控的主节点和它们的状态列表
- SENTINEL master 展示指定的主节点的信息
- SENTINEL salves 展示这个主节点的从节点,以及它们的状态
- SENTINEL sentinels 展示这个主节点的sentinel实例,以及它们的状态
- SENTINEL get-master-addr-by-name 返回主节点的IP和端口号。如果这个主节点的一次故障转移正在进行,就返回提升的从节点的IP和端口号
- SENTINEL reset
<pattern> 这个命令将会根据匹配的名称重置主节点,pattern参数是通配符(glob-style)类型,重置进程清除主节点中之前的所有状态,并且移除主节点发现和关联的从节点和sentinel。
- SENTINEL failover
<master name> 如果主节点不可达,强制开始故障转移,不需要另外的Sentinels同意。
- SENTINEL ckquorum
<master name> 检查当前的Sentinel配置对于主节点的故障转移是否能达到仲裁人数,并且大多数是需要的来授权故障转移。这个命令应该在监控系统中使用来检查一个Sentinel部署是否正常。
- SENTINEL flushconfig 强制Sentinel重新写入它的配置到磁盘上,包括当前Sentinel状态。通常,每次当它状态里的一些东西改变,Sentinel就会重写配置信息。然而有时候配置文件会丢失,由于错误的操作、磁盘故障、包升级脚本、或配置管理。在那种情况下,强制Sentinel重写它的配置文件是容易的。甚至之前的配置文件完全丢失,这个命令也能很好的工作。
更过细节参考:Redis哨兵-实现Redis高可用
3 集群模式
3.1 概述
Redis在3.0
上加入了 Cluster
集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的数据。cluster模式为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS
不受限于单机,可受益于分布式集群高扩展性。
Redis 集群(包括很多小集群)实现了对 Redis 的水平扩容
,即启动 N
个 redis 节点,将整个数据库分布存储在这 N 个节点
中,每个节点存储总数据的 1/N
,即一个小集群存储 1/N 的数据,每个小集群里面维护好自己的 1/N 的数据。
Redis 集群通过分区(partition)
来提供一定程度的可用性(availability)
: 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。该模式的 redis 集群特点是:分治、分片。
Redis的集群模式本身没有使用一致性hash算法,而是使用slots插槽
3.2 集群Sharding
Redis Cluster是一种服务器Sharding技术(分片和路由都是在服务端实现),采用多主多从
,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是相互平行
的。Redis Cluster集群采用了P2P的模式,完全去中心化
。
官方推荐,集群部署至少要 3
台以上的master节点,好使用 3 主 3 从六个节点的模式。
对客户端来说,整个cluster被看做是一个整体,客户端可以连接任意一个node
进行操作,就像操作单一Redis实例一样,当客户端操作的key没有分配到该node上时,Redis会返回转发指令,指向正确的node,这有点儿像浏览器页面的302 redirect跳转。
3.3 集群配置启动
使用 3 主 3 从六个节点的模式
修改redis.conf
的配置文件:
# 开启redis的集群模式
cluster-enabled yes
# 配置集群模式下的配置文件名称和位置,redis-cluster.conf这个文件是集群启动后自动生成的,不需要手动配置。
cluster-config-file redis-cluster.conf
依次启动集群的服务器,这时虽然配置了集群开启,但是这六台机器还是独立的。使用集群管理命令将这6台机器添加到一个集群中。
redis-tri.rb
工具可以快速的部署集群:
redis-trib.rb create --replicas 1 192.168.1.11:6379 192.168.1.12:6379 192.168.1.13:6379 192.168.1.14:6379 192.168.1.15:6379 192.168.1.16:6379
该命令执行创建完成后会有响应的日志:
>>> 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.1.12:6379 to 192.168.1.11:6379
Adding replica 192.168.1.14:6379 to 192.168.1.13:6379
Adding replica 192.168.1.16:6379 to 192.168.1.15:6379
M: 80c80a3f3e33872c047a8328ad579b9bea001ad8 192.168.1.11:6379
slots:[0-5460] (5461 slots) master
S: b4d3eb411a7355d4767c6c23b4df69fa183ef8bc 192.168.1.21:6379
replicates 6788453ee9a8d7f72b1d45a9093838efd0e501f1
M: 4d74ec66e898bf09006dac86d4928f9fad81f373 192.168.1.12:6379
slots:[5461-10922] (5462 slots) master
S: b6331cbc986794237c83ed2d5c30777c1551546e 192.168.1.22:6379
replicates 80c80a3f3e33872c047a8328ad579b9bea001ad8
M: 6788453ee9a8d7f72b1d45a9093838efd0e501f1 192.168.1.13:6379
slots:[10923-16383] (5461 slots) master
S: 277daeb8660d5273b7c3e05c263f861ed5f17b92 192.168.1.23:6379
replicates 4d74ec66e898bf09006dac86d4928f9fad81f373
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
执行完成后自动生成配置的redis-cluster.conf文件。
3.4 什么是 slots
一个 Redis 集群包含 16384
个插槽(hash slot),数据库中的每个键都属于这 16384 个插槽的其中一个。集群使用公式 CRC16 (key) % 16384
来计算键 key 属于哪个槽, 其中 CRC16 (key) 语句用于计算键 key 的 CRC16 校验和 。
3.5 运行机制
- 在 Redis 的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383,可以从上面
redis-trib.rb
执行的结果看到这16383个slot在三个master上的分布。还有一个就是cluster,可以理解为是一个集群管理的插件,类似的哨兵。 - 当我们的存取的 Key到达的时候,Redis 会根据 crc16的算法对计算后得出一个结果,然后把结果和16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接
自动跳转到
这个对应的节点上进行存取操作。 - 当数据写入到对应的master节点后,这个数据会同步给这个master对应的所有slave节点。
- 为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点。当其它主节点ping主节点master 1时,如果半数以上的主节点与master 1通信超时,那么认为master 1宕机了,就会启用master 1的从节点slave 1,将slave 1变成主节点继续提供服务。
- 如果master 1和它的从节点slave 1都宕机了,整个集群就会进入fail状态,因为集群的slot映射不完整。如果集群超过半数以上的master挂掉,无论是否有slave,集群都会进入fail状态。
- redis-cluster采用去中心化的思想,没有中心节点的说法,客户端与Redis节点直连,不需要中间代理层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
3.6 集群扩缩容
对redis集群的扩容就是向集群中添加机器
,缩容就是从集群中删除机器
,并重新将16383个slots分配到集群中的节点上(数据迁移)。
扩缩容也是使用集群管理工具 redis-tri.rb
。
扩容时,先使用redis-tri.rb add-node
将新的机器加到集群中,这是新机器虽然已经在集群中了,但是没有分配slots,依然是不起做用的。在使用 redis-tri.rb reshard
进行分片重哈希(数据迁移),将旧节点上的slots分配到新节点上后,新节点才能起作用。
缩容时,先要使用 redis-tri.rb reshard
移除的机器上的slots,然后使用redis-tri.rb add-del
移除机器。
3.7 集群模式的优缺点
优点:
采用去中心化思想,数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布;
可扩展性:可线性扩展到多个节点,节点可动态添加或删除;
高可用性:部分节点不可用时,集群仍可用。
缺点:
部分客户端实现,多键操作性能问题。
多键的 Redis 事务是不被支持的,lua 脚本不被支持。
考虑使用 Redis Hashtags
解决,保证所有key在一个node节点
redis cluster主要是针对海量数据
+高并发
+高可用
的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster,数据量不是很大时,使用sentinel就够了。redis cluster的性能和高可用性均优于哨兵模式。