美文网首页
腾讯开心鼠英语存储演进漫谈

腾讯开心鼠英语存储演进漫谈

作者: Java永远滴神 | 来源:发表于2020-11-03 19:22 被阅读0次

    今年腾讯开心鼠项目的用户量每天都在肉眼可见的急剧增长,某些周的复合增长率甚至达到了10%,随着用户量的增长和业务复杂性的增加,数据库的高峰性能压力和存储压力不断变大,下面整体介绍下我们进行的一系列存储架构的调整以及未来的规划。

    年初项目的整体架构如下,大部分模块都在以(ip+port)的方式使用同个DB实例。

    在量较小的情况下,核心DB的CPU和存储负载都没有太大压力,但量变大后整体风险逐步暴露,主要有:

    耦合度高:任何一个业务svr的SQL性能都会影响所有业务的性能,一旦某个svr没控制好,可能整体全挂

    扩展性差:整个存储的磁盘空间,都写性能都会受到单机限制。

    阶段1:一主多从

    结合高峰期数据库审计日志和对业务模块的梳理,发现数据库访问有以下特点:

    读写QPS比例大致在10 : 1;

    写主要集中在用户的物品数据,课程数据,学习数据等;

    读主要分布在账号体系,集训营,管理端,支付物流,学习记录等;

    慢查询主要集中在集训营和管理端的业务上。

    针对读写比例的特点,优先优化读请求。

    在一主一从的基础上扩充两个RO组,从数据实时性和业务重要性对读操作进行拆分。

    数据实时性

    针对实时性要求高的用户账号,物品数据读取主库;

    针对用户课程数据,学习数据读取从库;

    业务重要性

    APP主功能,支付等读取主库和从库1;集训营和管理端读取从库2;数据统计、分析读取从库3;

    进行读库的拆分后,线上运行稳定,主库CPU负载从40%下载到了20%。

    阶段2:横向拆分

    在整个读拆分过程发现,从业务划分来看,数据库数据主要分为APP用户数据,集训营数据,支付物流数据,运营活动数据;

    其中除了用户账号数据是多个业务模块所需的,其他的基本上是独立的,于是我们考虑将数据库进行拆分,拆分为4个数据库:

    公共数据库:用户APP账号数据,微信序账号数据,课程静态数据;

    集训营数据库:集训营分配数据,上课数据,老师数据;

    支付/物流数据库:支付数据,物流数据,运营活动数据;

    UGC数据库:用户课程数据,学习数据,活动数据。

    每个数据库对应一个modle模块,将各表的增删改查等操作封装,各自以RPC方式去调用其他库的数据库操作。

    横向拆分主要涉及代码的改造和数据的迁移,两个核心问题是:

    尽可能降低迁移的改造成本

    如何保障业务不中断平滑迁移

    以UGC数据库为例,该库数据主要分为两大类:

    用于数据分析的少量关系化查询的 用户活动数据 ;

    存在大量关系化查询的 用户课程数据 。

    在用户规模不大时,原有的UGC数据都存储在mysql中,但随着用户数增长,mysql的存储空间和写性能都无法满足诉求。

    用户课程数据

    该部分数据需要支持关系化查询,我们采用了腾讯云的mysql集群解决方案TDSQL,TDSQL主要优势在于:

    整体容量随着分片数的增加而增加,并且是动态扩容的,不影响业务;

    读写分离,拥有更好的读写性能;

    提供Proxy代理,业务像使用单机Mysql一样;

    SQL语句完全兼容,业务迁移成本低;

    完备的监控指标和告警支持,同时支持性能分析。

    数据表的平滑迁移

    选择合适的sharedkey在TDSQL库中创建新的表;

    使用mysqldump的数据导出服务,导出已有的全量数据,再导入到TDSQL;

    通过腾讯云的DTS(数据传输服务),接入在线教育的统一binlog notify服务,将数据增量变更写入到TDSQL;

    将项目中数据库配置进行读库和写库的改造;

    进行项目中的该表读操作改造,将其改造到TDSQL对应表;

    线上业务监控及观察一段时间,如有问题,及时回滚读库配置;

    读请求迁移平稳后,对项目中的该表写操作改造,将其改造到TDSQL对应表;

    线上业务及监控观察一段时间,如有问题,及时回滚写库配置;

    停止DTS服务和binlog notify服务,迁移完成。

    当然我们的UGC业务有一定的延时误差是被允许接受的;如果对延时的接受程度较低,可以采用Mysql,TDSQL的双写方案来进行改造;先迁移写再迁移读来进行迁移改造,这里不再赘述,欢迎随时讨论。

    用户活动数据

    以用户学习数据为例,主要为用户完成学习活动过程中,在各个环节的表现,该部分数据主要用于数据分析,基本全为写操作,我们最终选择mongdb来存储这部分数据,主要优势在于:

    mongdb面向集合存储,模式自由,可以方便地扩展学习数据字段;

    mongdb支持大数据量的存储,可以满足这种随时间膨胀的特厉害的存储诉求;

    mongdb支持一定程度的关系化查询,满足按用户ID,活动ID来查询数据;

    强大的聚合工具,完美配合MapReduce等数据分析工具;

    支持数据复制和恢复能力,便于分析数据的传输。

    数据表的平滑迁移

    在mongdb中建立对应的数据库表

    改造项目代码,将原有数据库表的写请求存储到Kafka队列中

    使用迁移服务,对原有数据表的全量数据进行迁移,写入到mongdb中

    步骤3完成后,启动Kafka对应topic的消费服务,开始将数据平滑写入到mongdb

    针对各库的每张表都可以采用类似的方案进行迁移,至此我们可以开始对单库进行优化。

    阶段3:单库优化

    以公共数据库为例,通过分析业务高峰期的的数据库审计日志,发现:

    50%的请求基本集中在用户账号表上,10%的请求集中在课程静态数据上;

    下面将讨论如何优化这两部分请求。

    用户账号表

    该表主要特点有:

    写请求占比大致为11:1;

    写请求主要集中在密码、login时间等少数字段上;

    大部分用户数据:像手机号,ID等基本不变,同时这些字段可接受一定的时延。

    于是将用户账号表拆解成两部分:

    对于时延不敏感数据拆成一张mysql表,同时将表数据缓存到redis中;

    写请求较多的拆解成为redis中的缓存。

    对比了业界主要的缓存更新方案,考虑对业务无入侵、实时性优、监控完善等特点;

    选用便于接入的在线教育统一的DTS更新服务。

    课程相关数据表

    该表数据特点:

    基本为静态数据表,不常变更;

    占用空间大致在10M左右,且可预见的数据都不会很大。

    可采用内存缓存的来进行读加速,在服务启动时初始化后定时更新。

    同时还对各库进行了一系列的慢查询优化,索引优化,尽量保证单库的可用性及性能。

    阶段4:整体优化

    在针对性对单库进行性能优化后,在实际开发和维护过程中还存在些痛点:

    业务方调用成本高,得理解不同数据库的差异;

    多数据库的安全防护,统计功能、监控等功能都很分散;

    UGC数据大表业务高峰写入QPS很高;

    UGC数据大表无法在线DDL操作。

    问题1/2:DataProxy统一代理

    除了针对各个svr合理调整连接数外,引入DB代理也是个较好的解决方案;于是采用Data Proxy的方案,由其代理各个数据库的访问,提供统一接口给业务方调用;同时在proxy可进行各种安全防护措施,比如过载保护,缓存崩塌保护,穿透保护等;另外还能对外提供数据统计、延时监控功能。

    问题3:Kafka平滑写入

    由于业务特点,高峰期用户数在平时的10倍以上,单纯的扩容数据库机器在大部分时间内都是极其浪费的;同时由于数据特点,少量数据的读延迟是可以接受的;于是引入KAFKA队列,先由PROXY统一写入到队列中,再由消费服务平滑写入TDSQL与MongoDB;这样就能较低成本扛住高峰期流量和突增流量,并且有很好的扩展性。

    问题4:在线DDL暂停消费服务

    对于大表的DDL一直是数据库优化过程中的一个老大难问题;数据库表的变更,不管是索引变更还是字段变更基本都会缩表从而引发业务中断;在引入队列平滑写入情况下,可在线随时停止消费服务后进行的DDL变更,但不会影响正常业务的运转。

    最终存储架构

    相关文章

      网友评论

          本文标题:腾讯开心鼠英语存储演进漫谈

          本文链接:https://www.haomeiwen.com/subject/hhyivktx.html