千千梦丶琪 发表于 2024-9-5 10:06:53

转转回收的持久层架构演进

1 前言

我们在大部分开发场景下,对持久层的建立基于单库单表实在就可以实现当前的产品需求。但是随着业务发展越来越久,数据量、哀求量也在不断的增加,只是单库单表大概不足以支持系统的稳定运行,本文重要给各人分享一下笔者在项目现实迭代过程中对持久层稳定性的建立过程。
2 项目简介

https://img-blog.csdnimg.cn/img_convert/e536fba6d852d40d3f57e0385e5dd006.png
简单来讲就是用户在一些活动场景下获取优惠券信息,领取并绑定到关系表里,后续用户去售卖一些商品的时候可以从领取的优惠券列表里选择一个符合的优惠券来使用。
3 面临的问题

3.1 数据越来越多

项目初期,单表完全可以hold住系统的稳定运行,但是由于优惠券的发放门槛特殊低,导致优惠券的数量随着业务的发展激增,用户领券的关系表数量也越来越多,为了避免以后单表数据量过大带来的不须要的麻烦,我们对绑定关系表进行分表处置惩罚。
https://img-blog.csdnimg.cn/img_convert/6dd508dca2bc60e84b41bb7a41d93e62.png
3.1.1 技能选型

目前市面上对于分库分表的方案大要分为三类:
1.基于JDBC进行代理:该方案不需要运维等人员的介入,技能内部即可进行开发优化。
https://img-blog.csdnimg.cn/img_convert/f5337d6983e30e054876b3e523313c9a.png
2.基于数据库进行代理:该方案需要DBA或者运维的介入,维护起来不方便。
https://img-blog.csdnimg.cn/img_convert/a51a9ac695483a930c752f6ada7d76c3.png
3.TiDB数据库:支持无穷的水平扩展,具备强一致性和高可用性,编码层面的使用跟MYSQL无异。
最终选型
以上三种方案,笔者这边最终选择了基于JDBC进行代理,因为这种方案可以纯内部进行消化,不需要外部部分介入,对于开发本钱、时间周期来讲都是比力轻易弹性调解的,后续有改造也不需要外部介入。
至于框架的选择选择了ShardingJDBC,原因以下几点:
1.社区活跃,遇到问题可以快速收到反馈。
2.框架颠末多年演进,已经是很稳定且成熟的产品。
3.公司内部应用广泛,可以协助共建。
分库分表怎样设计?
分库分表扩容涉及到重新hash分片的问题,极其麻烦,以是最好一步到位,短期内不进行扩容操作。
我们基于数据当前的增长速率,简单盘算下未来十年大概带来的数据量,盘算出8库8表即可满意该场景。
查询场景都是基于用户维度,以是拿uid作为分片键即可。
增长速率远超预期怎么办?
及时增长速率远超预期也不打算进行扩容操作,因为本钱过高。优惠券逾期时间很短,用户在优惠券逾期肯定时间后就可以思量将优惠券进行归档操作,如许即可包管数据量稳定在我们预期之内。
为什么不消TiDB?
由于笔者对TiDB相识不深,思量到遇到问题不易快速定位、办理,且该表对于业务流程至关重要,以是暂不思量使用TiDB来存储。
3.1.2 数据迁移流程

迁移流程大要如下:
1 延迟双写
我们先插入或修改旧表数据,成功之后再去写入或修改新表,然后发送一个延迟消息,消息触达之后进行新老数据查对,假如数据存在异常则进行修正,令其保持一致。
2 数据清洗
设置一个时间节点,将该时间点前的主键id全部跑出来,然后在脚本任务里,实时去查询该主键id对应的最新数据,写入到新表中。
3 异步纠错
迁移后的肯定时间内,查询的时候对新老数据进行校验,如有不一致数据进行异步修复。
详细流程如图:
https://img-blog.csdnimg.cn/img_convert/a5532c32ee15bd4e50eb1d896e826c84.png
3.2 查询越来越复杂

3.2.1 初期方案

优惠券由于查询条件比力复杂(涉及到数组查询、模糊查询),且随着业务发展不断追加新的查询条件,导致不太得当每个查询条件作为单独的字段存储,故而放到了一个json里同一维护,但是这种存储方式查询的时候就无法直接利用mysql进行过滤。
比方:
小明想查询一个条件为:iPhone13非全新机、代价满1000元可用、以旧换新场景下、邮寄售卖可用的优惠券。
最初数据量不多的时候直接把配置表全部拿出来机型内存过滤,拿着满意条件的配置id去绑定关系表里进行查找。
https://img-blog.csdnimg.cn/img_convert/02d52da1425c9f9b12594fed19d39042.png
3.2.2 暂时改进方案

随着产品不断创建优惠券进行精细化投放,热门机型都会有对应的优惠券,库里的券大概有几百条。如许每次都要从库里全量拉出几百条进行处置惩罚的话显然99.9%的数据都是不须要的,因为用户只需要一张券,以是思量本钱最小的暂时改进方案就是将优惠券放到内存中进行缓存,通过内存过滤减少每个哀求过来造成的不须要的额外查询,降低gc频率。
这里借鉴了一些中心件同步缓存数据的方案,进行推拉联合的方式,一方面实时广播推送包管时效性,另一方面定时去拉数据来进行兜底处置惩罚。
https://img-blog.csdnimg.cn/img_convert/47372d4fca1b8e7a06ce62d166614b54.png
但是本方案也不是长久之计,随着券的不断创建,内存中过滤的id大概会掷中的特殊多,如许查询的时候性能也会很糟糕,以是在时间充裕的时候思量介入其他更得当的中心件,固然本钱高,但是能从根本上是办理问题。
https://img-blog.csdnimg.cn/img_convert/8fd9ee6e942143acc8d0e01786df4019.png
3.2.3 接入ElasticSearch中心件

通过调研发现公司内部比力得当的查询中心件只有ElasticSearch,市面上也大概有其他得当的中心件,但还需要思量额外的搭建、运维维护的本钱,使用ElasticSearch就足够办理该问题。
这里现实接入流程不做多赘述,有兴趣的可以参考相关的文章。
不外使用ElasticSearch也有一个缺点,就是数据写入到查询存在肯定的延迟,并且我们这边有的场景还对时效性要求很高,比方:系统在哀求的开始阶段给用户发一张券,用户拿到后还会再去获取最优券,这张券直接查大概会获取不到。
原来的兼容方案是写入成功后业务内部把id带到上下文在内存中进行过滤,如许需要兼容的地方许多,且每个场景都要单独处置惩罚。
那我是怎样办理的?
我这边通过Redis+ElasticSearch 联动查询来包管时效性,在写入成功之后将配置id同步保存到Redis的zset结构中,设置个10s的逾期时间。
https://img-blog.csdnimg.cn/img_convert/3e68672fd9a9325d2c1f1b7974c14101.png
当有查询过来的时候,同时查询ElasticSearch与redis中的数据,然后合并过滤获取出最符合的券。
https://img-blog.csdnimg.cn/img_convert/6fb448540ab08b6b2b239e068c5c6169.png
一些性能优化手段:
1.查询只返回需要的字段信息。
2.定义索引的时候使用符合的字段。
3.限制数据总量,根据现实场景做数据归档。
4.减少索引范围,逼迫根据uid进行分片路由。
https://img-blog.csdnimg.cn/img_convert/e429c65e3eebeb92d6dab351119ea6d2.png
3.3 哀求量越来越大

3.3.1 读写分离

随着业务qps越来越高,每逢大促写入、查询的流量都会激增,以是常常收到关于主库流量太高的数据库告警,为了应对各种带来的尖刺流量,包管主库的稳定,进行了读写分离,减缓主库写入的压力。
主从延迟怎么办理?
有一种最简单粗暴的方案,单独提供主库的查询接口,但是这种对于调用方改造本钱极大, 何况提供了主库接口之后大概许多人都不会去再使用从库了,从而无法到达读写分离的效果。
Object getByInfoFromMater(Long id);
抱负中的方案
我这边调研了下是否有中心件能帮我实现主从选取的本领,即在主从同步成功之后才进行从库的读取,否则都是读取主库。
优点:服务方无感知
缺点:大概对性能造成影响
https://img-blog.csdnimg.cn/img_convert/505fce16bf94354155c042f45c215394.png
不外没找到这种中心件,以是我这边针对于这种方案用redis做了个一个简化版:
https://img-blog.csdnimg.cn/img_convert/6238742e4c2d8b80c9b3a4fd54e68be4.png
通过定义注解来控制是否实行该组件:
设置了写入注解的方法:内部全部使用主库进行读操作,包管一致性,且设置2s左右逾期时间的TAG。
设置读注解的方法:内部判断TAG是否存在,存在则走主库,否则从库。
这种方案也会带来负面影响:
带有注解的方法都要查询一次redis,耗时会增高, 且假如2s内主从同步失败,还是会存在查询不一致的环境,当然思量现实场景,这种概率微乎其微,我们业务是可以接受的。
4 总结

在从0到1做一个项目标时候,没须要过分设计,应该快速上线,包管系统正常运行即可。
项目初期可以先遇到问题再去办理问题,但是项目具备肯定的流量之后,需要提前发现项目痛点并规划怎样办理,否则等到真正遇到问题,再去办理大概已经来不及了,留给我们办理的时间已经不多了。
以上都是笔者在现实工作中的总结、归纳,各位假如有更好的方案或是不同的见解,接待批评区留言,共同讨论、进步。
   关于作者
王锐刚,转转线上回收业务后端开发工程师
   转转研发中央及业界小伙伴们的技能学习交流平台,定期分享一线的实战经验及业界前沿的技能话题。
关注公众号「转转技能」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,接待交流分享~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 转转回收的持久层架构演进