云数据库Redis版主从热备高可用方案-阿里云开发者社区

开发者社区> 阿里云数据库> 正文
登录阅读全文

云数据库Redis版主从热备高可用方案

简介: 高可用(High Available)是线上生产环境所必不可少的重要条件,阿里云数据库Redis版作为一款成熟稳定的数据库产品,针对Redis的特性也支持高可用,本文将介绍云Redis是如何实现这一方案。 目前云Redis有主从版和集群版两种架构,本次主要针对主从版。

引言

高可用(High Available)是线上生产环境所必不可少的重要条件,阿里云数据库Redis版作为一款成熟稳定的数据库产品,针对Redis的特性也支持高可用,本文将介绍云Redis是如何实现这一方案。

架构

目前云Redis有主从版和集群版两种架构,本次主要针对主从版做HA的解析。

下图为主从版架构:
HA.png
由图可知,云Redis实例有主备两个节点,平时只有Master提供服务,Slave只做热备不提供访问,Slave通过slaveof命令挂载到Master上,不断从Master接收数据,保证Master宕机时云Redis仍可提供服务。

每一个云Redis实例都会分配一个VIP并与DNS绑定,VIP经过SLB后直接访问Master不再有其他中间层,访问Redis的链路为DNS-->VIP-->SLB-->REDIS(MASTER)。

在底层原理上集群版HA与主从版基本相同,只是实现时稍有差异,因为链路上在VIP和后端REDIS之间多了一层proxy的路由转发,所以在做后端rs切换时无需更改VIP指向,而是去更新proxy的路由表。

HA模块

HA作为一个独立的系统模块,远程探测云Redis的健康状况,当发生实例不可用时及时主备切换以保证服务质量。

健康检查

健康检查的逻辑很简单,通过客户端连接Redis并发送PING命令,如果返回PONG则说明Redis健康,其他情况则说明Redis异常,检测逻辑用伪代码来说明:

try:
    client = Redis(ip, port, connection_timeout, socket_timeout)
    //指定要连接Redis的ip:port(这里的ip:port即可以是VIP:VPORT也可以是Master或Slave的物理ip:port,HA会有多维度的探测),并设置超时时间
    client.connect()
    //尝试连接Redis,如果连接失败或超时则会抛出异常
    res = client.ping()
    //向Redis发送ping命令,结果为PONG说明Redis健康,返回OK;结果非PONG或超时则会抛出异常
    if res == PONG:
        return OK
except:
    //处理异常情况,若异常在预先定义的错误内,说明Redis真的异常,返回ERROR,HA会做下一步切换动作
    if e.message in ERRORS:
        return ERROR
    else:
        return OK

需要HA真正做切换的异常情况有以下几种:

/* 指定ip地址的机器不能找到(也就是说从当前机器不存在到指定ip路由),或者是该ip存在,但找不到指定的端口进行监听,这时Redis所在主机可能宕机或是进程挂掉 */
"Connection refused"    
/* 服务器的并发连接数超过了其承载量,服务器会将其中一些连接主动Down掉 */
"Connection reset"
/* 连接超时 */
"connect timed out"
/* 读取数据超时 */
"Read timed out"
/* Redis正在加载数据 */
"LOADING Redis is loading the dataset in memory"
/* 访问的Redis是Slave */
"READONLY You can't write against a read only slave"

健康检查升级方案

Redis工作在单线程模式下,接收到的所有命令都会进入队列串行处理,当遇到一些耗时命令如flushall、keys * 等,很容易造成客户端等待超时。此时如果超时时间设置不准确的话,HA远程探测就容易误判Redis不健康,而且单单一个PING命令也不能完全获得Redis的进程状态。

Redis自带的HA方案Sentinel就是依赖PING来做健康检查,通过配置sentinel down-after-milliseconds mymaster,来决定当PING超时多久没有收到回复就认为Redis宕机,但是这样做有一定风险,比如一个64G的实例flushall清空数据大概为2分钟,如果超时时间设置为60s那么很容易造成误判。

为了解决这个问题,我们对Redis内核进行了改造,增加了一个状态线程来专门为HA提供健康检查的服务。同时也新增了一个状态端口,状态线程监听这个端口,HA探测时也通过这个端口与Redis进行交互,不会对Redis服务主线程造成影响。通过新增的状态线程也可以做很多额外的探测,例如读写性能、磁盘IO情况等。

我们把Redis主线程监听的端口叫做redis_port,状态线程监听的端口叫做status_port新的健康检查逻辑如下:

try:
    client = Redis(ip, status_port, connection_timeout, socket_timeout)
    //这里要连接的端口为状态端口status_port
    client.connect()
    //尝试连接Redis,如果连接失败或超时则会抛出异常
    res = client.health_check()
    //向Redis发送定制的健康检查命令,结果为True说明Redis健康,返回OK;否则抛出异常
    if res == True:
        return OK
except:
    //处理异常情况,若异常在预先定义的错误内,说明Redis真的异常,返回ERROR,HA会做下一步切换动作
    if e.message in ERRORS:
        return ERROR
    else:
        return OK

主备切换前准备工作

当健康检查发现Redis出现不可用情况时就要准备进行主备切换,在主备切换真正执行前需要额外做一些工作:

通过VIP检查Redis健康状态
if VIP不健康:
    检查Slave状态
    if Slave健康:
        再次检查VIP状态
        if VIP健康:
            无需主备切换
        else:
            执行主备切换
    else:
        Slave不健康无法切换
else:
    无需主备切换

在执行切换前要检查Slave状态以确保切换后实例是可服务的,否则即使切换也是无效的,比如两台主机都宕机这种极端情况。

同时对VPC类型的实例做了特殊处理,因为我们是没有办法访问用户自定义网络的VIP的,这时需要把对VIP的健康检查换成对Master的健康检查。

执行主备切换

当Redis出现不可用且满足切换条件时,真正开始执行主备切换动作。同时切换动作也支持主动的任务切换和被动的故障切换,两者主要区别在是否需要Slave等待Master达到同步状态,以下对主备切换做详细说明:

1. 额外再次检查一次Master状态
if Master健康:
    if 故障切换:
        无需切换,返回成功
    else:
        a. 设置Master为readONLY只读状态
        b. 通过info replication命令检查主备同步状态,也即master_repl_offset是否等于Slave的offset
        if 若超时仍未达到一致状态:
            重置Master为readwrite可读写状态,并返回异常
else:
    日志记录此时Master无法连接
2. 切换VIP指向Slave
if 切换失败:
    记录日志并返回异常
3. 更新主备元信息
4. 向Slave发送slaveof no one命令,使其升级为新的Master
5. 尝试向原Master发送slaveof命令,使其降级为新的Slave
    此时原Master可能已经宕机,故不做失败处理,仅记录日志

通过以上方案,云数据库Redis版SLA可以达到99.99%,仅在主从都发生宕机的极端情况无法服务。

切换场景

宕机或是进程异常退出是最为严重的情况,此时HA远程探测到redis无法连接会立即切换,实际测试整个过程可以实现秒级切换。

在主备切换后原来的Master变成了Slave,为了保障云Redis依旧高可用,会有另外的组件来探测Slave的可用性,当备库发生宕机时触发备库重搭功能,时刻保证主从双节点热备。

与Redis-Sentinel对比

Redis2.8版本自带Redis-Sentinel的高可用解决方案,通过一个或多个Sentinel实例组成的Sentinel系统来监测Master和Slave,具体方案有很多资料可以查阅不再赘述。
我们在生产环境中并没有采用自带的Sentinel,主要是出于以下几点考虑:

1. 虽然Sentinel本身也是一个Redis进程,但是运行在特殊模式下,实际维护Sentinel就需要额外配置一个角色,增加了系统的复杂度。
2. Sentinel自身的高可用问题,如果是单点Sentinel其本身也具有故障无法转移的风险,那么就要搭建Sentinel集群,这无形中也增加了管理成本。
3. Sentinel本身是有状态的,需要在启动时加载配置文件来获取Master信息,如果搭建分布式的Sentinel集群,动态增删改也会带来一致性问题,这对云上弹性资源并不适用,无法应对实例的创建、删除、变配、迁移等动作。
4. Sentinel的健康检查并不够灵活,上一节已经讲过单纯通过PING来检查无法应对flushall、keys * 等耗时命令,我们的健康检查升级方案会更好的应对云上复杂环境。

由于上述问题Sentinel不能作为一个统一的HA系统来管理所有云Redis资源,而为每个云Redis单独搭建一套Sentinel系统又会造成资源浪费和管理复杂度,基于此我们开发了这一套适用于云Redis的HA系统。

结束

本文介绍了云数据Redis版HA方案,通过主从双机热备来保证服务高可用,健康检查出现异常时及时进行主备切换,有效保障业务运行。

结尾顺便打个硬广,即日起购买阿里云数据库Redis版(首台)3年5折、1年6折、按月7折啦,赶快点击购买吧:https://m.aliyun.com/markets/aliyun/act/redissaleoff?spm=5176.8112568.483450.6.o85c4v

阿里云数据库Redis团队诚邀加入:
https://job.alibaba.com/zhaopin/position_detail.htm?spm=0.0.0.0.l7roxQ&positionId=26437

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
阿里云数据库
使用钉钉扫一扫加入圈子
+ 订阅

帮用户承担一切数据库风险,给您何止是安心!

官方博客
最新文章
相关文章
链接