赞
踩
作者:极光高级工程师—包利
摘要
极光推送后台标签/别名系统存储超过百亿条数据, 高峰期QPS超过50万, 且随着业务的发展,存储容量和访问量还在不断增加。之前系统存在的一些瓶颈也逐渐显现,所以近一两年持续做了很多的优化工作,最终达到非常不错的效果。近期,经过积累和沉淀后,将这一部分的工作进行总结。
背景
当前的旧系统中主要存储标签/别名与注册ID的相互映射关系, 使用Key-Value结构存储, 考虑到一个注册ID可能有多个标签, 同时一个标签也存在多个不同的注册ID, 这部分数据使用Redis存储中的Set数据结构; 而一个注册ID只有一个别名, 同时一个别名也存在多个不同的注册ID, 这部分数据使用String/Set数据结构。由于此部分数据量过大, 考虑到存储成本, Redis使用的单Master模式, 而最终数据的落地使用Pika存储(一种类Redis的文件存储)。Pika与Redis中的数据由业务方保持一致, Redis正常可用时, 读Redis; 当Redis不可用时读Pika, Redis恢复可用后, 从Pika恢复数据到Redis, 重新读Redis。旧系统的存储架构如下:
从上面的架构图可以看到, Redis/Pika均采用主从模式, 其中Redis只有Master, 配置管理模块用来维护Redis/Pika集群的主从关系, 配置写入ZooKeeper中, 业务模块从ZooKeeper中读取配置, 不做配置变更。所有的配置变更由配置管理模块负责. 当需要迁移, 扩容, 缩容的时候, 必须通过配置管理模块操作。这个旧系统的优缺点如下:
优点:
缺点:
旧系统缺点分析
考虑到旧系统存在以上的缺点, 主要从以下几个方向解决:
分析: 旧系统中Redis与Pika数据不一致主要是Pika早期版本Set数据结构操作效率不高, String数据结构操作的效率比较高, 但获取标签/别名下的所有注册ID时需要遍历所有Pika实例, 这个操作非常耗时, 考虑到最新版本Pika已经优化Set数据结构, 提高了Set数据结构的读写性能, 应该保持Redis与Pika数据结构的一致性。
分析: Redis单Master模式风险极大。需要优化为主从模式, 这样能够在某个Master故障时能够进行主从切换, 不再从Pika中恢复数据, 减少故障恢复时间, 减少数据不一致的可能性。
分析: 这个系统恢复时间过长是由于Redis是单Master模式, 且没有持久化, 需要把Redis优化成主从模式且必须开启持久化, 从而几乎不需要从Pika恢复数据了, 除非Redis的主从实例全部同时不可用。不需要从Pika恢复数据后, 那么Redis中的数据在Redis主从实例发生故障时, 就和Pika中的数据一致了。
分析: 配置管理模块手动干预操作过多, 非常容易出错, 这部分应尽量减少手动操作, 考虑引入Redis哨兵, 能够替换大部分的手动操作步骤。
分析: 通过对Redis中的各个不同维度数据进行数据量和访问量以及访问来源分析(如下图)。外部请求量(估算) 这栏的数据反应了各个不同Key的单位时间内访问量情况。
Redis的存储数据主要分为标签/别名到注册ID和注册ID到标签/别名两部分数据. 通过分析得知, 标签/别名到注册ID的数据约占1/3左右的存储空间, 访问量占到80%; 注册ID到标签/别名的数据约占2/3左右的存储空间, 访问量占到20%。可以看到, 红色数字部分为访问的Pika, 黑色部分访问的Redis, 3.7%这项的数据可以优化成访问Redis, 那么可以得出结论, 红色的数据在Redis中是永远访问不到的。所以可以考虑将Redis中注册ID到标签/别名这部分数据删掉, 访问此部分数据请求到Pika, 能够节省约2/3的存储空间, 同时还能保证整个系统的读性能。
分析: 这部分主要由于其中一项服务为非高可用, 而且整个系统架构的复杂性较高, 以及数据一致性相对比较难保证, 导致故障恢复时间长, 考虑应将所有服务均优化为高可用, 同时简化整个系统的架构。
分析: 配置手动管理风险也非常大, Pika主从关系通过配置文件手动指定, 配错后将导致数据错乱, 产生脏数据. 需要使用Redis哨兵模式, 用哨兵管理Redis/Pika, 配置管理模块不再直接管理所有Redis/Pika节点, 而是通过哨兵管理, 同时再发生主从切换或者节点故障时通知配置管理模块, 自动更新配置到Zookeeper中, 迁移/扩容/缩容时也基本不用手动干预。
分析: 这部分手动操作, 应该优化为自动触发, 自动完成迁移, 减少人工干预, 节省人力成本。
Redis哨兵模式
Redis哨兵为Redis/Pika提供了高可用性, 可以在无需人工干预的情况下抵抗某些类型的故障, 还支持监视, 通知, 自动故障转移, 配置管理等功能:
同时, 哨兵还具有分布式性质, 哨兵本身被设计为可以多个哨兵进程协同工作, 当多个哨兵就给定的主机不再可用这一事实达成共识时, 将执行故障检测, 这降低了误报的可能性。 即使不是所有的哨兵进程都在工作, 哨兵仍能正常工作, 从而使系统能够应对故障。
Redis哨兵+主从模式能够在Redis/Pika发生故障时及时反馈实例的健康状态, 并在必要时进行自动主从切换, 同时会通过Redis的sub/pub机制通知到订阅此消息的应用程序。从而应用程序感知这个主从切换, 能够短时间将链接切换到健康的实例, 保障服务的正常运行。
没有采用Redis的集群模式, 主要有以下几点原因:
最终解决方案
综上, 为了保证整个存储集群的高可用, 减少故障恢复的时间, 甚至做到故障时对部分业务零影响, 我们采用了Redis哨兵+Redis/Pika主从的模式, Redis哨兵保证整个存储集群的高可用, Redis主从用来提供查询标签/别名到注册ID的数据, Pika主从用来存储全量数据和一些注册ID到标签/别名数据的查询。需要业务保证所有Redis与Pika数据的全量同步。新方案架构如下:
从上面架构图来看, 当前Redis/Pika都是多主从模式, 同时分别由不同的多个哨兵服务监视, 只要主从实例中任一个实例可用, 整个集群就是可用的。Redis/Pika集群内包含多个主从实例, 由业务方根据Key计算slot值, 每个slot根据配置管理模块指定的slot与实例映射关系。如果某个slot对应的Redis主从实例均不可用, 会查询对应的Pika, 这样就保证整个系统读请求的高可用。这个新方案的优缺点如下:
优点:
缺点:
其他优化
除了通过以上架构优化, 本次优化还包括以下方面:
展望
未来此系统还可以从以下几个方面继续改进和优化:
总结
本次系统优化在原有存储组件的基础上, 根据服务和数据的特点, 合理优化服务间调用方式, 优化数据存储的空间, 将Redis当作缓存, 只存储访问量较大的数据, 降低了资源使用率。Pika作为数据落地并承载访问量较小的请求, 根据不同存储组件的优缺点, 合理分配请求方式。同时将所有服务设计为高可用, 提高了系统可用性, 稳定性。最后通过增加缓存等设计, 提高了高峰期的查询QPS, 在不扩容的前提下, 保证系统高峰期的响应速度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。