Redis挂了,怎么补救?谈谈如何实现redis的高可用
Redis挂了,怎么补救?谈谈如何实现redis的高可用!
Redis实现高可用主要有三种部署模式:主从模式、哨兵模式和集群模式。
分区
分区(Partitioning)是一种最为简单的拓展方式。
-
在我们面临单机的存储空间瓶颈时,第一点就能想到像传统的关系型数据库一样,进行数据分区。
-
或者假设手中有N台机器可以作为Redis服务器,所有机器内存总和有256G, 而客户端正好也需要一个大内存的存储空间。
-
我们除了可以把内存条都拆下来焊到一个机器上,也可以选择分区使用,这样又拓展了计算能力。
-
单指分区来讲,即将全部数据分散在多个Redis实例中,每个实例不需要关联,可以是完全独立的。
使用方式
-
客户端处理和传统的数据库分库分表一样,可以从key入手,先进行计算,找到对应数据存储的实例在进行操作。范围角度,比如orderId:1orderId:1000放入实例1,orderId:1001orderId:2000放入实例2...哈希计算,就像我们hashmap一样,用hash函数加上位运算或者取模,高级玩法还有一致性Hash等操作,找到对应的实例进行操作
-
使用代理中间件 我们可以开发独立的代理中间件,屏蔽掉处理数据分片的逻辑,独立运行。当然也有他人已经造好的轮子,Redis也有优秀的代理中间件,譬如Twemproxy或者codis,可以结合场景选择是否使用。
缺点
-
无缘多key操作,key都不一定在一个实例上,那么多key操作或者多key事务自然是不支持。
-
维护成本,由于每个实例在物理和逻辑上,都属于单独的一个节点,缺乏统一管理。
-
灵活性有限,范围分片还好,比如hash+MOD这种方式,如果想动态调整Redis实例的数量,就要考虑大量数据迁移,这就非常麻烦了。
同为开发者,深知我们虽然总能“曲线救国”的完成一些当前环境不支持的功能,但是总归要麻烦一些。
一,主从模式
同上面的分区一样,也是Redis高可用架构的基础,新手可能会误以为这类基础模式即是“高可用”,这并不是十分正确的。
分区暂时能解决单点无法容纳的数据量问题,但是一个Key还是只在一个实例上,在大流量时代显得不那么可靠。
主从就是另一个纬度的拓展,节点将数据同步到从节点,就像将实例“分身”了一样,可靠性又提高了不少。
主从模式中,Redis部署了多台机器,由主节点负责读写操作,而从节点只负责读操作;
从节点的数据来自于主节点,其背后的原理就是主从复制机制。
主从机制包括全量复制和增量复制两种方式。
1、全量复制
一般当slave第一次启动连接master的时候,或者被认为是第一次连接,就采用全量复制:
1.slave发送sync命令到master。
2.master接收到SYNC命令后,执行bgsave命令,生成RDB全量文件。
3.master使用缓冲区,记录RDB快照生成期间的所有写命令。
4.master执行完bgsave后,向所有slave发送RDB快照文件。
5.slave收到RDB快照文件后,载入、解析收到的快照。
6.master使用缓冲区,记录RDB同步期间生成的所有写的命令。
7.master快照发送完毕后,开始向slave发送缓冲区中的写命令;
8.salve接受命令请求,并执行来自master缓冲区的写命令
redis在2.8版本之后,就是用psync来代替sync请求,因为sync命令非常消耗系统资源,psync的效率更高。
2、增量复制
-
在slave和master全量同步之后,master上的数据,如果再次发生更新,就会触发增量复制。
-
当master节点发生数据增减时,就会触发replicationFeedSalves()函数,接下来在 Master节点上调用的每一个命令会使用replicationFeedSlaves()来同步到Slave节点。
-
执行此函数之前呢,master节点会判断用户执行的命令是否有数据更新,如果有数据更新的话,并且slave节点不为空,就会执行此函数。
-
这个函数作用就是:把用户执行的命令发送到所有的slave节点,让slave节点执行。
流程如下:
使用方式:
-
作为主节点的Redis实例,并不要求配置任何参数,只需要正常启动
-
作为从节点的实例,使用配置文件或命令方式REPLICAOF 主节点Host主节点port即可完成主从配置
缺点:
-
slave节点都是只读的,如果写流量大的场景,就有些力不从心了。那我把slave节点只读关掉不就行了?当然不行,数据复制是由主到从,从节点独有数据同步不到主节点,数据就不一致了。
-
故障转移不友好,主节点挂掉后,写处理就无处安放,需要手工设定新的主节点,如使用REPLICAOF(谁大腿我都不抱了) 晋升为主节点,再梳理其他slave节点的新主配置,相对来说比较麻烦。
二,哨兵模式
主从模式中,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点,同时还要通知应用方更新主节点地址。显然,多数业务场景都不能接受这种故障处理方式。
Redis从2.8开始正式提供了Redis Sentinel(哨兵)架构来解决这个问题。并且还能够充当配置提供者,提供主节点的信息,就算发生了故障转移,也能提供正确的地址。
1、哨兵模式
由一个或多个Sentinel实例组成的Sentinel系统,它可以监视所有的Redis主节点和从节点,并在被监视的主节点进入下线状态时,自动将下线主服务器属下的某个从节点升级为新的主节点。但是呢,一个哨兵进程对Redis节点进行监控,就可能会出现问题(单点问题),因此,可以使用多个哨兵来进行监控Redis节点,并且各个哨兵之间还会进行监控。如下图所示:
简单来说,哨兵模式就三个作用:
-
发送命令,等待redis服务器(包括主服务器和从服务器)返回监控其运行状态。
-
哨兵检测到主节点宕机,会自动将从节点切换成主节点,然后通过发布订阅模式通知其他的从节点,修改配置文件,让他们切换主机。
-
哨兵之间还会相互监控,从而达到高可用。
2、故障切换的过程是怎么样的呢?
-
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行 failover(故障切换),仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。
-
当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行 failover 操作。
-
故障切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
-
这样对于客户端而言,一切都是透明的。
哨兵的工作模式如下:
- 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他Sentinel实例发送一个 PING命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel标记为主观下线。
- 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
- 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线。
- 在一般情况下, 每个 Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。
- 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
- 若没有足够数量的 Sentinel同意Master已经下线, Master的客观下线状态就会被移除;若Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
哨兵本身也是Redis实例的一种,但不作为数据存储方使用,启动命令也是不一样的。
使用方式
Sentinel的最小配置,一行即可:
sentinel monitor <主节点别名> <主节点host> <主节点端口> <票数>
只需要配置master即可,然后用redis-sentinel <配置文件>,命令即可启用。
Redis官网提到的“最小配置”是如下所示,除了上面提到的一行,还有其它的一些配置:
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
正如该例所示,设置主节点别名就是为了监控多主的时候,与其额外配置项能够与其对应, 以及sentinel一些命令,如sentinel get-master-addr-by-name 就要用到别名了。
哨兵数量建议在三个以上且为奇数,在Redis官网也提到了各种情况的“布阵”方式,非常值得参考。
既然是高可用方案,并非有严格意义上的“缺点”,还需配合使用场景进行考量。
-
故障转移期间短暂的不可用,但其实官网的例子也给出了parallel-syncs参数来指定并行的同步实例数量,以免全部实例都在同步出现整体不可用的情况,相对来说要比手工的故障转移更加方便。
-
分区逻辑需要自定义处理,虽然解决了主从下的高可用问题,但是Sentinel并没有提供分区解决方案,还需开发者考虑如何建设。
-
既然是还是主从,如果异常的写流量搞垮了主节点,那么自动的“故障转移”会不会变成自动“灾难传递”,即slave提升为Master之后挂掉,又进行提升又被挂掉。不过最后这点也是笔者猜测,并没有听说过出现这种案例,可不必深究。
三,集群模式
哨兵模式基于主从模式,实现读写分离,它还可以自动切换,系统可用性更高。
但是它每个节点存储的数据是一样的,浪费内存,并且不好在线扩容。
因此,Cluster集群应运而生,它在Redis3.0加入的,实现了Redis的分布式存储。对数据进行分片,也就是说每台Redis节点上存储不同的内容,来解决在线扩容的问题。并且,它也提供复制和故障转移的功能。
-
对开发者而言,“官方支持”一词是大概率非常美好的,小到issue,大到feature。自定义去解决问题,成本总是要高一些。
-
有了官方的正式集群方案,从请求路由、故障转移、弹性伸缩几个纬度的使用上,将更为容易。
-
Cluster不同于哨兵,是支持分区的。有说法Cluster是哨兵的升级,这是不严谨的。 二者纬度不一样,如果因为Cluster也有故障转移的功能,就说它是哨兵的升级款,略显牵强。
-
Cluster在分区管理上,使用了“哈希槽”(hash slot)这么一个概念,一共有16384个槽位,每个实例负责一部分槽,通过CRC16(key)&16383,计算出来key所对应的槽位。
-
虽然在节点和key二者中又引入了槽的概念,看起来不易理解,实际上因为颗粒度更细了,减少了节点的扩容和收缩难度,相比传统策略还是很有优势。
-
当然,“槽”是虚拟的概念,节点自身去维护“槽”的关系,并不是要真正下载启动个“槽服务”在跑。
使用方式
Redis的各种玩法,都是从配置文件着手,集群也不例外。
cluster-enabled yes
cluster-config-file "redis-node.conf"
关键配置简洁明了,有两步
-
开启集群
-
指定集群配置文件
集群配置文件(cluster-config-file)为内部使用,可以不去指定,Redis会帮助创建一个。
启动还是普通的方式redis-server redis.conf
首先以集群方式启动了N台Redis实例,这当然还没完事。
接下来的步骤笔者称为“牵线搭桥分配槽”,听起来还算顺口。
“牵线搭桥分配槽”的方式也在不断升级,从直接用原始命令来处理,到使用脚本,以及现在的Redis-cli官方支持,使用哪种方式都可以。
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
上方的命令即是Redis官网给出的redis-cli的方式用法,一行命令完成“三主三从”以及自动分配槽的操作。
这样集群就搭建完成了,当然,使用官方提供的check命令检查一下,也是有必要的。
redis-cli --cluster check 127.0.0.1:7001
注意:
-
虽然是对分区良好支持,但也有一些分区的老问题,譬如:如果不在同一个“槽”的数据,是没法使用类似mset的多键操作。
-
在select命令页有提到, 集群模式下只能使用一个库,虽然平时一般也是这么用的,但是要了解一下。
-
运维上也要谨慎,俗话说得好,“使用越简单底层越复杂”,启动搭建是很方便,使用时面对带宽消耗,数据倾斜等等具体问题时,还需人工介入,或者研究合适的配置参数。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步