一、推送平台特点
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