关于服务器:Redis-在-vivo-推送平台的应用与优化实践-转至元数据结尾-由

3次阅读

共计 6015 个字符,预计需要花费 16 分钟才能阅读完成。

一、推送平台特点

vivo 推送平台是 vivo 公司向开发者提供的音讯推送服务,通过在云端与客户端之间建设一条稳固、牢靠的长连贯,为开发者提供向客户端利用实时推送音讯的服务,反对百亿级的告诉 / 音讯推送,秒级触达移动用户。

推送平台的特点是并发高、音讯量大、送达及时性较高。目前现状最高推送速度 140w/s,单日最大音讯量 150 亿,端到端秒级在线送达率 99.9%。

二、推送平台 Redis 应用介绍

基于 vivo 推送平台的特点,对并发和时效性要求较高,并且音讯数量多,音讯有效期短。所以,推送平台抉择应用 Redis 中间件作为音讯存储和直达,以及 token 信息存储。之前次要应用两个 Redis 集群,采纳 Redis Cluster 集群模式。两个集群如下:

对 Redis 的操作,次要包含如下几方面:

1)推送环节,在接入层存储音讯体到 msg Redis 集群,音讯过期工夫为 msg Redis 存储音讯的过期工夫。

2)推送服务层通过一系列逻辑后,从 msg Redis 集群查出音讯体,查问 client Redis 集群 client 信息,如果 client 在线,间接推送。如果 client 不在线,将音讯 id 写到期待队列。

3)如果连贯上来,推送服务层,读取期待队列音讯,进行推送。

4)存储管理服务,会定期扫描 cii 索引,依据 cii 存储的最初更新工夫,如果 14 天都没更新,阐明是不沉闷用户,会清理该 token 信息,同时清理该 token 对应的期待队列音讯。

推送环节操作 Redis 流程图如下:

三、推送平台线上问题

如下面介绍,推送平台应用 Redis 次要 msg 集群和 client 集群,随着业务的倒退,系统对性能要求越来越高,Redis 呈现一些瓶颈问题,其中 msg Redis 集群在优化前,规模已达到 220 个 master,4400G 容量。随着集群规模变大,保护难度减少,事故率变高。特地是 4 月份,某某明星离婚事件,实时并发音讯量 5.2 亿,msg Redis 集群呈现单节点连接数、内存暴增问题,其中一个节点连接数达到 24674,内存达到 23.46G,继续 30 分钟左右。期间 msg Redis 集群读写响应较慢,均匀响应工夫 500ms 左右,影响到整体零碎的稳定性和可用性,可用性降到 85%。

四、推送平台 Redis 优化

Redis 个别从以下几方面优化:

1)容量:Redis 属于内存型存储,相较于磁盘存储型数据库,存储老本较低廉,正是因为内存型存储这个个性使得它读写性能较高,然而存储空间无限。因而,业务在应用时,应留神存储内容尽量是热数据,并且容量是可事后评估的,最好设置过期工夫。在存储设计时,正当应用对应数据结构,对于一些绝对大的 value,能够压缩后存储。

2)热 key 歪斜:Redis-Cluster 把所有的物理节点映射到[0-16383]slot(槽)上,每个节点负责一部分 slot。当有申请调用时,依据 CRC16(key) mod 16384 的值,决定将 key 申请到哪个 slot 中。因为 Redis-cluster 这个个性,每个节点只负责一部分 slot,因而,在设计 key 的时候应保障 key 的随机性,特地是应用一些 hash 算法映射 key 时,应保障 hash 值的随机散布。另外,管制热点 key 并发问题,能够采纳限流降级或者本地缓存形式,避免热点 key 并发申请过高导致 Redis 热点歪斜。

3)集群过大:Redis-Cluster 采纳无核心构造,每个节点保留数据和整个集群状态,每个节点都和其余所有节点连贯。每个节点都保留所有节点与 slot 映射关系。当节点较多时,每个节点保留的映射关系也会变多。各节点之间心跳包的音讯体内携带的数据越多。在扩缩容时,集群从新进行 clusterSlots 工夫绝对较长。集群会存在阻塞危险,稳定性受影响。因而,在应用集群时,应该尽量避免集群节点过多,最初依据业务对集群进行拆分。

这里有个问题:为什么 Redis-Cluster 应用 16384 个 slot,而不是更多,最多能够有多少个节点?

官网作者给出了解释,并且在解释中阐明,Redis-Cluster 不倡议超过 1000 个主节点。

基于以上一些优化方向,和本身业务个性,推送平台从以下几方面开启 Redis 优化之路。

  • msg Redis 集群容量优化;
  • msg Redis 大集群依据业务属性拆分;
  • Redis 热点 key 排查;
  • client Redis 集群并发调用优化。

4.1 msg Redis 集群容量优化

前文提及,msg Redis 集群规模达到 220 个 master、4400G 容量,高峰期已应用容量达到 3650G,应用了 83% 左右,如果后续推送提量,还需扩容,老本太高。于是对 msg Redis 集群存储内容进行剖析,应用的剖析工具是雪球开源 RDB 剖析工具 RDR。github 网址:这里不多介绍,大家能够去 github 网址下载相应的工具应用。这个工具能够剖析 Redis 快照状况,包含:Redis 不同构造类型容量、key 数量、top 100 largest keys、前缀 key 数量和容量。

剖析后的论断:msg Redis 集群中,mi:结尾的构造占比 80% 左右,其中单推音讯占比 80%。阐明:

  • 单推:1 条音讯推送 1 个用户
  • 群推:1 条音讯能够反复推送多个用户,音讯能够复用。

单推的特点是一对一推送,推送完或者推送失败(被管控、有效用户等)音讯体就不再应用。

优化计划

  • 及时清理单推音讯,如果用户曾经收到单推音讯,收到 puback 回执,间接删除 Redis 音讯。如果单推音讯被管控等起因限度发送,间接删除单推音讯体。
  • 对于雷同内容的音讯,进行聚合存储,雷同内容音讯存储一条,音讯 id 做标识推送时屡次应用。

通过这个优化后,缩容成果较显著。全量上线后容量放大了 2090G,原最高容量为 3650G,容量放大了 58%

4.2 msg Redis 大集群依据业务属性拆分

尽管进行了集群容量优化,然而高峰期 msg Redis 压力仍然很大。

次要起因

1)连贯 msg Redis 的节点很多,导致高峰期连接数较高。

2)音讯体还有期待队列都存储在一个集群,推送时都须要操作,导致 Redis 并发很大,高峰期 cpu 负载较高,达到 90% 以上。

3)老集群 Redis 版本是 3.x,拆分后,新集群应用 4.x 版本。相较于 3.x 版本有如下劣势:

  • PSYNC2.0:优化了之前版本中,主从节点切换必然引起全量复制的问题。
  • 提供了新的缓存剔除算法:LFU(Least Frequently Used),并对已有算法进行了优化。
  • 提供了非阻塞 del 和 flushall/flushdb 性能,无效解决删除了 bigkey 可能造成的 Redis 阻塞。
  • 提供了 memory 命令,实现对内存更为全面的监控统计。
  •  更节约内存,存储同样多的数据,须要更少的内存空间。
  • 能够做内存碎片整顿,逐渐回收内存。当应用 Jemalloc 内存调配计划的时候,Redis 能够应用在线内存整理。

拆分计划依据业务属性对 msg Redis 存储信息进行拆分,把音讯体和期待队列拆分进去,放到独立的两个集群中去。这样就有两种拆分计划。

计划一 把期待队列从老集群拆分进去

只需推送节点进行批改,然而发送期待队列间断的,有状态,与 clientId 在线状态相干,对应的 value 会实时更新,切换会导致数据失落。

计划二 把音讯体从老集群拆分进去

所有连贯 msg Redis 的节点替换新地址重启,推送节点进行双读,等到老集群命中率为 0 时,间接切换读新集群。因为音讯体的特点是只有写和读两个操作,没有更新,切换不必思考状态问题,只有保障能够写入读取没问题。并且音讯体容量具备增量属性,须要能不便疾速的扩容,新集群采纳 4.0 版本,不便动静扩缩容。

思考到对业务的影响及服务可用性,保障音讯不失落,最终咱们抉择计划二。采纳双读单写方案设计:

因为将音讯体切换到新集群,那在切换期间一段时间(最多 30 天),新的音讯体写到新集群,老集群存储老音讯体内容。这期间推送节点须要双读,保证数据不失落。为了保障双读的高效性,须要反对不批改代码,不重启服务的动静规定调整措施。

大抵规定分为 4 个:只读老、只读新、先读老后读新、先读新后读老。

设计思路:服务端反对 4 种策略,通过配置核心的配置决定走哪个规定。

规定的判断根据:依据老集群的命中数和命中率决定。上线初期规定配置“先读老再读新”;当老集群命中率低于 50%,切换成 ” 先读新后读老 ”;当老集群命中数为 0 后,切换成“只读新”。

老集群的命中率和命中数通过通用监控减少埋点。

计划二流程图如下:

拆分后成果:

  • 拆分前,老 msg Redis 集群同期间高峰期负载 95% 以上。
  • 拆分后,同期间高峰期负载升高到 70%,降落 15%。

拆分前,msg Redis 集群同期间高峰期均匀响应工夫 1.2ms,高峰期存在调用 Redis 响应慢状况。拆分后,均匀响应工夫升高到 0.5ms,高峰期无响应慢问题。

4.3 Redis 热点 key 排查

后面有说过,4 月某某明星热点事件,呈现 msg Redis 单节点连接数、内存飙升问题,单节点节点连接数达到 24674,内存达到 23.46G。

因为 Redis 集群应用的虚拟机,起初狐疑是虚拟机所在宿主机存在压力问题,因为依据排查发现呈现问题的节点所在宿主机上挂载 Redis 主节点很多,大略 10 个左右,而其余宿主机挂载 2 - 4 个左右主节点,于是对 master 进行了一轮均衡化优化,使每台宿主机调配的主节点都比拟平衡。均衡化之后,整体有肯定改善。然而,在推送高峰期,尤其是全速全量推送时,还是会偶然呈现单节点连接数、内存飙升问题。察看宿主机网卡出入流量,都没呈现瓶颈问题,同时也排除了宿主机上其余业务节点的影响。因而狐疑还是业务应用 Redis 存在热点歪斜问题。

通过高峰期抓取调用链监控,从下图能够看到,咱们 11:49 到 12:59 这期间调用 msg Redis 的 hexists 命令耗时很高,该命令次要是查问音讯是否在 mii 索引中,链路剖析耗时的 key 大都为 mii:0。同时对问题节点 Redis 内存快照进行剖析,发现 mii:0 容量占比很高,存在读取 mii:0 热点问题。

通过剖析排查,发现生成音讯 id 的雪花算法生成的 messageId,存在歪斜问题,因为同一毫秒的序列值都是从 0 开始,并且序列长度为 12 位,所以对于并发不是很高的治理后盾及 api 节点,生成的 messageId 根本都是最初 12 位为 0。因为 mii 索引 key 是 mi:${messageId%1024},messageId 最初 12 位为 0,messageId%1024 即为 0,这样就导致 msg Redis 中 mii:0 这个 key 很大,查问时命中率高,因而导致了 Redis 的热 key 问题。

优化措施

1)雪花算法革新,生成音讯 id 时应用的 sequence 初始值不再是 0,而是从 0~1023 随机取一个数,避免热点歪斜问题。

2)通过 msg 音讯体中音讯类型及音讯体是否存在来替换调 hexists 命令。

最终成果:优化后,mii 索引已散布平均,Redis 连接数很安稳,内存增长也较安稳,不再呈现 Redis 单节点内存、连接数暴增问题。

4.4 client Redis 集群并发调用优化

上游节点调用推送节点是通过 clientId 进行一致性 hash 调用的,推送节点会缓存 clientInfo 信息到本地,缓存工夫 7 天,推送时,优先查问本地缓存,判断该 client 是否无效。对于重要且常常变更的信息,间接查问 client Redis 获取,这样导致推送高峰期,client Redis 集群压力很大,并发高,cpu 负载高。

优化前推送节点操作缓存和 client Redis 流程图:

优化计划:对原有 clientInfo 缓存进行拆分,拆分成三个缓存,采取分级计划。

  • cache 还是保留原来 clientInfo 一些信息,这些信息是不常常变更的,缓存工夫还是 7 天。
  • cache1 缓存 clientInfo 常常变更的信息,如:在线状态、cn 地址等。
  • cache2 缓存 ci 加密局部参数,这部分缓存只在须要加密时应用,变更频率没那么高,只有连贯时才会变更。

因为新增了缓存,需思考缓存一致性问题,于是新增一下措施:

1)推送缓存校验,调用 broker 节点,依据 broker 的返回信息,更新和清理本地缓存信息。broker 新增不在线、aes 不匹配错误码。下次推送或者重试时,会从新从 Redis 中加载,获取最新的 client 信息。

2)依据手机端上行事件,connect 和 disconnect 时,更新和清理本地缓存信息,下次推送或者重试时,会从新从 Redis 中加载,获取最新的 client 信息。

整体流程:音讯推送时,优先查问本地缓存,缓存不存在或者已过期,才从 client Redis 中加载。推送到 broker 时,依据 broker 返回信息,更新或生效缓存。上行,收到 disconnect、connect 事件,及时更新或生效缓存,再次推送时从新从 client Redis 加载。

优化后推送节点操作缓存和 client Redis 流程图:

优化后成果

1)新增 cache1 缓存命中率 52%,cache2 缓存命中率 30%。

2)client Redis 并发调用量减少了近 20%。

3)高峰期 Redis 负载升高 15% 左右。

五、总结

Redis 因为其高并发性能和反对丰盛的数据结构,在高并发零碎中作为缓存中间件是较好的抉择。当然,Redis 是否能施展高性能,还依赖业务是否真的了解和正确应用 Redis。有如下几点须要留神:

1)因为 Redis 集群模式,每个主节点只负责一部分 slot,业务在设计 Redis key 时要充分考虑 key 的随机性,平均扩散在 Redis 各节点上,同时应防止大 key 呈现。另外,业务上应防止 Redis 申请热点问题,同一时刻申请打到少部分节点。

2)Redis 理论吞吐量还与申请 Redis 的包数据大小,网卡无关,官网文档有相干阐明,单个包大小超过 1000bytes 时,性能会急剧下降。所以在应用 Redis 时应尽量避免大 key。另外,最好依据理论业务场景和理论网络环境,带宽和网卡状况进行性能压测,对集群理论吞吐量做摸底。

以咱们 client Redis 集群为例:(仅供参考)

  • Network:10000Mb;
  • Redis Version:3.x;
  • Payload size:250bytes avg;
  • 命令:hset(25%)、hmset(10%)、hget(60%)、hmget(5%);
  • 性能状况:连接数 5500、48000/s、cpu 95% 左右。

Redis 在实时剖析这块反对较少,除了根本指标监控外,实时内存数据分析暂不反对。在理论业务场景下如果呈现 Redis 瓶颈,往往监控数据也会缺失,定位问题较难。对 Redis 的数据分析只能依赖剖析工具对 Redis 快照文件进行剖析。因而,对 Redis 的应用依赖业务对 Redis 的充沛认知,方案设计的时候充分考虑。同时依据业务场景对 Redis 做好性能压测,理解瓶颈在哪,做好监控和扩缩容筹备。

作者:vivo 互联网服务器团队 -Yu Quan

正文完
 0