系统重构、优化实战

一、背景:

  目前正在负责XX公司的退款系统;此系统经过N多人迭代,N多个兼容版本、N多种代码风格,目前已经无法维护下去了;借此机会,将整个系统推倒重来、彻底重构了一遍;
  经压测,重构后性能(吞吐量)提升了12倍,其他指标提升如下:

在这里插入图片描述

为什么要重构?
在这里插入图片描述

二、 重构前场景调研:

三、重构前后架构对比:

之前系统架构图:

在这里插入图片描述

大体介绍下这个系统是干什么的,都做了些什么事:

  1. 这是一个退款系统,由上游系统发起退款申请(相当于底层服务)
  2. 多场景:退款的场景有N多种,现在每一种退款都维护一套单独逻辑(需要抽象)
  3. 退款单组装:接收到退款请求后,做了一些基本的校验,校验通过后去组装退款单实体,组装实体的时候有些属性需要调用外部接口获取(这一步网络开销很耗时)
  4. 持久化:待退款单组装完毕后,将退款单入库;入库前又做了一些规则校验
  5. 库存扣减:通过dubbo接口调用支付系统扣减库存
  6. 推送外部系统:推送mq给财务系统
  7. 发票红冲:调用发票系统进行发票红冲
  8. 退费发起:定时任务捞取退款单,调用网关系统,请求三方退费
  9. 数据同步:大数据系统会T+1日同步退款单表

嗯,这么多步骤尽然在一个事务当中;得回之前并发量不大,不然数据库早挂了!

我们来分享下这个系统有哪些问题,基于这些问题我们改如何改造:
1、这里最大的问题就是:这么多操作都在同步线程处理显然是不合理的,系统要改成异步处理;规则校验+库存扣减完毕后,快速返回,其余逻辑异步处理
2、数据一致性问题;第4、5、6、7步的数据一致性无法保证
3、每一种退费场景都需要维护一套,代码大量冗余,维护成本相当之高
4、目前退费单表近1亿数据量,需要支持APP和WEB端各种维度、各种条件查询,响应已经很慢
5、事务力度太大,需要减小或弃用事务
6、没有对入口限流,如发生大量请求系统会瘫痪
7、系统模块耦合严重
8、非实时退款
9、处理链路过长
10、无挡板、无限流

改造后系统架构图
在这里插入图片描述

优化点如下:
1、架构异步化改造(提高并发)

按之前所说,同步线程里之做
1、基本规则校验:
2、退款单组装:这里只组装基本属性,需要调外部接口填充的属性在异步里做
3、退款单持久化+消息表持久化+远程余额扣减:这里引用了seata组件AT模式,保证了这三部的强一致性(消息表的目的第4部与第3部的最终一致性)
4、发送统一消息:此时就可以返回给上游

2、校验规则前置、快速失败(提高并发)

3、非核心属性填充后置、异步处理(提高并发)

这里说的就是退费单表需要调用外部接口填充的属性,在异步的mq里去做

4、减少调用链路(提高并发)
5、本地二级缓存(提高并发)

城市字典表缓存在了redis的,value值过大,在高并发场景下,会将带宽打满;做了本地三级缓存解决

6、OLAP数据库切换(查询性能优化)

退款单表存在于mysql中,近1亿数据量访问会很耗时;所以将mysql中数据通过DTS实时同步到ADB(阿里的分析性数据库,查询性能非常高)中,那么以后查询全部切到ADB

7、使用seate+消息表设计保证了数据强一致性及最终一致性(一致性)

seata组件保证了退款单持久化+消息表持久化+远程余额扣减的强一致性,消息表的作用是 如果seata这一步成功了,消息发送失败了,可以基于消息表补偿;(seata要比本地事务性能低3倍左右,后续还要优化)

8、使用消息驱动、事件分发完成周边业务逻辑的结耦(结耦、削峰填谷)

消息中间件会增加系统的灵活性,当退款事件完成后,会发送一个统一消息,需要感知这个事件的服务 只需要订阅消息即可,从而达到系统结耦的目的

9、精炼代码、使用工厂、模板、责任链、建造者、过滤器、策略、外观、适配器、装饰器设计模式抽象设计退款框架(可维护性、扩展性)
10、映射码系统搭建(配置化、扩展性)

映射码系统是基于三方各种返回码、对我们系统订单的状态及事件映射,更直观的观察各个状态码及其统计,在不改变代码的前提下,通过配置即可映射不同状码触发的事件

11、非核心业务剥离(稳定性)

我们将退款系统中涉及的查询接口、导出接口等相关业务进行剥离;因为在高并发场景下,查询接口会占据大量的系统线程,从而导致cpu频繁调动,增加系统开销,剥离后的另一个好处就是 如果需求上有查询接口的改动,那么只发查询服务器即可

12、入口限流(稳定性)

在入口处我们使用了sentinel进行了接口tps限流,保证系统最后一道防线

13、灰度切换流量(安全性)

我们设计了一个开关,在接口入口处(filter),可按百分比、地区、userId进行流量灰度;如果新接口有问题话,也可快速回滚

14、使用redission+gauva+sentinel进行调用三方限流(减少无效请求)

我们调用微信、支付宝等三放的退款接口时,同样也会遭到三放的限流,所以在调用三方前 我们会对系统订单限流,从而减少无效调用

15、mock挡板开发(场景模拟)

在开发环境,有些异常返回码是无法模拟的,从而导致测试场景覆盖不全;所以需要一个mock挡板系统来模拟与三方交互

16、链路追踪(快速定位)

这个非常重要,能帮助我们快速定位问题,我们的链路追踪不进能在http请求中串通、在mq、rpc交互下及多线程模式下也全部打通,具体参考我的另一篇博客,专门来讲全链路追踪,点击这里

17、减少事务力度、参数调优

将事务粒度最小化,尽量把事务中的查询、接口调用、复杂计算放在事物外提前做好,用参数的形式传到事物中,保证事务中仅有简单的更新、删除操作

18、Log4j升级为Log4j2

这点也非常重要,Log4j采用的是日志同步刷盘,会阻塞住线程,而Log4j采用了异步刷盘策略,必要时可以丢弃日志,在我的另一篇系统优化博客中会介绍,点击这里

19、数据库连接调优

数据库连接池设置为系统cpu*2+1为最佳,过多的连接会导致cpu平凡切换,具体看这里

20、tomcat线程数调优

根据系统的业务类型来进行tomcat线程数调优,距离拿4核8G物理机来说,如果是io型业务,maxThread=1000即可,如果是cpu密级型,可减少maxThread的数量;jvm的内存分配调优同样也是这个道理


四、核心代码

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值