基于Redis的低成本高可用排行榜服务构建

引言

业务运营活动中排行榜的使用很广泛,因此在三年前组内已经将排行榜服务组件化。整个服务是基于Redis的zset数据结构实现的。

限于当时Redis的发展,这套服务在高可用性方面有所欠缺。近年来,公司内外团队在实现高可用Redis方面做了很多工作,也有很多部门提供现成的接入方案。但由于我们的Redis是定制过的(修改过源码),一方面是现有方案不支持接入,开源项目往往也需要修改源码进行适配,即便如此也不完全如意;另一方面我们自己也希望在升级迭代上能灵活掌控,所以权衡后还是决定自行部署和运维。

架构方案

早期的架构

在此之前,排行榜服务部署情况如下图所示。此时,无状态的接入层通过内部协议对外提供服务,各业务无需关注Redis的连接和调用方式。但是当redis master停止服务时,需要人工将slave提升为master,并发布配置将接入层的指向切换到slave。此方案虽然能在大多数情况下做到数据安全,但是在出现故障后人工介入之前,服务处于不可用状态。

早期的架构

高可用架构

关于Redis的高可用部署方案,常见的有twemproxy、codis等,这些第三方方案往往需要引入额外组件,增加了运维成本。Redis本身提供了哨兵做HA,官方文档就哨兵的不同部署方案做了详细介绍。本着低成本的原则,本文亦采用哨兵作高可用保障。改进的排行榜服务架构如下图所示。

高可用架构

整个服务由以下部分组成:

  • 排行榜CGI及业务模块:即服务使用方。排行榜CGI是一个通用化的供H5前端拉取排行榜数据的组件,业务无关。当业务有特殊逻辑时,亦可直接调用接入层接口。
  • 服务接入层: 1. 对业务提供惯用的内部协议接口,供业务调用 2. 对单个原生命令无法完成的操作,如插入元素并返回排名操作,使用pipelining或lua优化查询,细节对业务透明 3. 对业务隐藏从哨兵处获取redis实例地址、master实例切换后地址更新等复杂逻辑 4. 当读并发量较大时,可通过增加redis slave实现读操作水平扩容,增加的slave可通过哨兵自动发现,对业务透明 5. 提供黑名单、周期榜单等业务通用能力支持
  • Redis实例:即Redis主从实例对。可以有多个slave以实现读操作水平扩容。
  • 哨兵集群:提供高可用保证以及名服务。由3个哨兵组成,不与任何Redis实例混布。
  • 监控与告警:借助公司内部指标监控平台实现指标监控以及异常告警。下一节详述。

监控告警与自动运维

Redis存活监控与master自动切换。由哨兵负责。当实例进程终止或不可达时,哨兵会检测到该实例的sdownodown状态(主观下线与客观下线),并在客观下线后自动切换主实例。通过配置哨兵的notification-script脚本,在状态变化时哨兵可以调用运维接口发送短信和邮件通知。而配置reconfig-script,能在新的master切换成功后触发通知。

同时,接入层需要根据哨兵sentinel slaves命令返回的数据自动发现slave,并根据状态识别slave是否可用。几种情况下的master和slave可用性如下表所示。

情形

master状态

slave状态

master与slave正常

正常

正常。flagsslavemaster-link-statusok

master不可达

不可读写,等待恢复或切换

正常。flagsslavemaster-link-statusok

master切换后slave同步中

新master正常。

暂不可用。与新master成功建立连接前flags包含disconnected;与新master连接后完成同步前master-link-status不为ok

新slave上线同步中

正常

暂不可用。与新master成功建立连接前flags包含disconnected;与新master连接后完成同步前master-link-status不为ok

slave不可达

正常

不可读。flags包含sdownodown

Redis指标监控。在Redis实例机器上部署监控脚本,通过crontab定时采样,数据上报到监控平台,方便查看实时和历史数据。监控的指标项可包含CPU使用率、内存使用率、key数量等,根据业务需要确定。

哨兵间相互监控。同样由哨兵负责。但需要注意的是,当某个哨兵不可达时,其他哨兵只会触发sdown状态变化,并发送通知告警。

扩展能力

功能可扩展性。除了现有的黑名单、周期榜的能力,接入层还可以扩展丰富的业务功能,对业务屏蔽复杂的redis调用逻辑。比如,借助LUA实现一个定时消息队列(参考此文)、接口流控等。

标准组件兼容。接入层同时支持切换到其他符合Redis协议的组件,比如360 pika等。对于上层业务来说,不管是调用标准redis实例,还是其他组件,都没有差别。

安装包与配置管理

Redis安装包与配置管理

业务的线上Redis使用相同的配置,统一使用内部服务包发布系统管理Redis的安装包和配置,以后台server方式打包和部署。好处是:

  • 便于版本管理,能跟踪每一次变更情况。
  • 跟踪现网部署情况,可以看到部署了哪些实例,分别是哪个版本。当发现问题时可以方便评估受影响的范围。
  • 能将部署工作流程化。安装包内包含了监控脚本和工具,并且会自动添加指标监控的crontab。

哨兵安装包与配置管理

业务同样使用内部包发布系统管理哨兵安装包。但在配置管理方面与redis包有些不同,因为哨兵的配置文件,同时也是哨兵的状态存储,故每个哨兵的线上配置是有差异的。我们将哨兵配置项区分为以下几类:

分类

内容

特征

每实例独有

哨兵ID

配置变更后要保持不变,否则其他哨兵会认为有新哨兵加入且原哨兵不可用,将影响到故障恢复时多数派选举leader过程。哨兵之所以不清除不可用的哨兵状态,是为了防止当网络故障导致脑裂时错误的选举局部leader。

公共静态配置

端口、工作目录、日志文件等

每个实例一样,且日常运维中无需变更。

公共动态配置

监控的Redis实例及纪元信息。

这部分配置随着监控实例的增删会变化。值得注意的是,如果某个哨兵的纪元信息被重置,其可以从别的哨兵处恢复。

故可以采用如下策略管理哨兵配置:

  1. 静态配置放在sentinel-base.conf文件中,随哨兵安装包发布。
  2. 指定配置文件sentinel.conf启动哨兵,首次部署启动后会在配置sentinel.conf中生成哨兵唯一idsentinel myid,利用包部署服务等启动后脚本将其备份到myid.conf中。脚本如下:cd $install_path/conf grep -E '^sentinel myid' sentinel.conf > myid.conf
  3. 最后利用配置系统下发实例监控配置文件sentinel.conf,在配置文件开头用include方式包含sentinel-base.confmyid.conf,且实例监控配置不需要包括epoch信息。这样,就能在每次下发新的配置后,保留哨兵ID和每个被监控实例的epoch信息了。_不过需要注意的是,相比起使用配置中心动态存储配置的方式,当线上故障导致master变更后,需要手动修改配置。_include "/usr/local/services/redis_sentinel_qzmall-1.0/conf/sentinel-base.conf" include "/usr/local/services/redis_sentinel_qzmall-1.0/conf/myid.conf"
# 实例1
sentinel monitor my_redis 100.66.82.X 6479 2
sentinel down-after-milliseconds my_redis 10000
sentinel auth-pass my_redis mypasswd
sentinel parallel-syncs my_redis 1
sentinel notification-script my_redis /usr/local/services/redis_sentinel_qzmall-1.0/bin/notification-script.sh
sentinel client-reconfig-script my_redis /usr/local/services/redis_sentinel_qzmall-1.0/bin/reconfig-script.sh

结语

与大多数公共组建一样,本文的Redis部署方案也由接入层、哨兵(名服务)、Redis实例(核心服务)、监控服务等部分组成。除哨兵与Redis是官方开源组件外,其他部分均选择公司已有技术和运维平台完成。方案整体既能满足日常业务需求,也能满足日常运维与监控要求,在可用性与维护成本上取得了一个平衡。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 zhuanlan_guanli@qq.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

Java开发的几个注意点

将一些需要变动的配置写在属性文件中 比如,没有把一些需要并发执行时使用的线程数设置成可在属性文件中配置。那么你的程序无论在DEV环境中,还是TEST环境中,都可...

1656
来自专栏CSDN技术头条

亿级Web系统搭建:单机到分布式集群

当一个Web系统从日访问量10万逐步增长到1000万,甚至超过1亿的过程中,Web系统承受的压力会越来越大,在这个过程中,我们会遇到很多的问题。为了解决这些性能...

1996
来自专栏逸鹏说道

亿级Web系统搭建:单机到分布式集群

当一个Web系统从日访问量10万逐步增长到1000万,甚至超过1亿的过程中,Web系统承受的压力会越来越大,在这个过程中,我们会遇到很多的问题。为了解决这些性能...

3277
来自专栏CSDN技术头条

MongoDB开发版本3.1.8发布

MongoDB 3.1.8版本已发布。值得注意的是此次3.1.8作为开发版本,并不适用于生产环境中使用。接来下的3.2系列版本将供广大用户作为生产环境中使用,敬...

2006
来自专栏IT技术精选文摘

负载均衡详解

面对大量用户访问、高并发请求,海量数据,可以使用高性能的服务器、大型数据库,存储设备,高性能Web服务器,采用高效率的编程语言比如(Go,Scala)等,当单机...

2027
来自专栏吴裕超

浅析前端渲染与服务端渲染

背景知识:   「后端渲染」指传统的 ASP、Java 或 PHP 的渲染机制;   「前端渲染」指使用 JS 来渲染页面大部分内容,代表是现在流行的 SPA ...

4274
来自专栏java一日一条

Java开发的几个注意点

比如,没有把一些需要并发执行时使用的线程数设置成可在属性文件中配置。那么你的程序无论在DEV环境中,还是TEST环境中,都可以顺畅无阻地运行,但是一旦部署在PR...

451
来自专栏xingoo, 一个梦想做发明家的程序员

Nodejs·进程

之前对这部分的内容很感兴趣,没想到读起来有点晦涩,还是因为对服务器的知识不是很了解。   说道服务器一般人都会想到tomcat或者Jboss或者weblo...

16410
来自专栏ThoughtWorks

聊一聊契约测试 | 洞见

如果从契约产生的阶段来说,现有资料表明最早要追溯到西周时期的《周恭王三年裘卫典田契》,将契约文字刻写在器皿上,就是为了使契文中规定的内容得到多方承认、信守,“万...

885
来自专栏Java成神之路

一个java高级工程师的进阶之路

一、 JAVA。要想成为JAVA(高级)工程师肯定要学习JAVA。一般的程序员或许只需知道一些JAVA的语法结构就可以应付了。但要成为JAVA(高级) 工程...

351

扫描关注云+社区