浅谈这些年做过的千万级系统重构项目

前言

当业务发展到一定程度,原有老系统出现瓶颈,或者公司技术栈出现变化(例如PHP转Java语言),需要重构,然而重构同时线上业务又必须稳定运行。那么如何平滑过渡,降低重构出现问题的风险,显得尤为重要。本文就来聊一聊这个问题。

回顾职业生涯,我做过的三次重构

第一次: 2016年6月  易到千万级订单系统重构

简介:PHP技术栈,订单表分1024个库, 10人耗时3个月完成,网上找到了一篇文章介绍 :https://www.admin5.com/article/20160705/673189.shtml

心得:这是参加工作第三年第一次接触重构,非常荣幸的跟着余老大(FastDFS和FastCFS作者)参与到这次重构项目之中。也是那个时候开始认识“架构”。
印象特别深刻的是用PHP封装Mysql 底层DB操作类库,我花了大概三天时间,写了一个支持各种链式操作,非常灵活的DB类库直接被老余Pass了。老大说了句:“只需要增删改查,越简单越好”。起初很不理解,后来花了半天时间重写了。后来上线之后,才慢慢知道,简单即是美,性能即是美。

第二次: 2018年6月 影像存储服务化重构(也就是图片存储服务)

简介: Java技术栈(SpringBoot/Dubbo/Redis),影像存储表分了512个库,3人耗时2个月完成

背景:1. 数据库一主多从模式,单一DB写入, 高峰时DB压力很大  2.图片处理服务和其他业务服务混在一起,比较换乱

目标:  存储独立,影像存储和其他存储分开   2、多主DB写入模式,数据分散到多台DB上,通过增加物理机器,可线性增加写入、读取速度  3、业务独立,边界清晰,只完成影像存储,与业务功能分开

心得: 本次影像重构是由我撰写的重构技术方案,并且主导开发。其中分库分表中间件是原生基于JDBC自研(没有使用开源的Sharding-JDBC等开源中间件主要原因是不满足我们业务场景需求)。

第三次: 2021年7月 订单分库分表重构

简介:Java技术栈(SpringBoot/Dubbo/Redis/Mango), 订单表分了8个库,256张表7人耗时1个月完成。

之前我也写了篇文章介绍:浅谈订单重构之路

心得: 主导技术方案设计和研发落地
在时间紧,任务重的情况下,有条不紊的推进,快速开发上线。从业务本身属性角度出发,解决订单性能问题。
该项目底层Dubbo服务目前线上高峰期支撑QPS 5W+,并且写RT<5ms, 读请求RT<2ms,可以说性能杠杠滴。

通过压测结果可知,目前一个数据库集群下单能支持1WTPS, 读支持 5W TPS,并且可以支持水平扩容,最多支持8个数据库集群扩展。

重构,需要做哪些事情。

正好最近有朋友公司PHP技术栈转Java,问我一些关于系统重构的问题。我总结下来如下三大点:

一、 做什么

首先要明确,要解决的问题是什么?做完重构能带来什么收益?做完是否能出现立竿见影的效果,投入产出比怎么样等等。

1、 第一要考虑组内成员的学习成本,虽然语言切换不是什么问题(个人亲身经历),但是至少得有个3个月左右缓冲期。2、要明确知道遇到的瓶颈是什么?要解决的核心问题是什么?3、模块划分,先确定哪些部分要重构成Java,先从一个点出发,解决核心问题。完善Java技术栈(注册中心,配置中心,分库分表中间件,监控,报警,全链路追踪)并且稳定运行之后,再迁移其它部分。

二、怎么做?

考虑清楚做什么之后,再去分析需要重构的模块,分析每一条SQL语句,分库分表怎么拆分,表结构是否需要修改。

分表shardkey是什么,当有非shardkey如何查询(建冗余表,还是汇总到ES+Hbase查询等)

分库分表如何做,是分库、分表,还是既分库又分表,分多少库,多少表。

考虑分库主要考虑是否有写入瓶颈,和方便以后水平扩展等问题。考虑分表主要是查询量比较大,个别表的量比较大。单表记录数量建议控制在1000W以下。

表结构修改了,是否需要双写。双写数据迁移方案怎么做。数据如何补仓,对比脚本编写等等。

灰度方案怎么做,怎么保证平滑迁移。

如果时间紧迫,可以先完成业务拆分,分库分表等核心部分。像监控、报警、全链路追踪这些辅助工具,可以等灰度上线之后再完善。

三、需要什么?

要初步估算预期目标

例如需要投入多少人力开发(一部分支持重构,一部分人还需要支持现有业务的正常运转),

我们要支撑下单多少TPS,重构后,需要多少docker服务资源,mysql数据库资源,Redis机器资源等。

重构,最重要的是什么?

答案: 都重要,环环相扣,每一个环节都不能少。

如果非要我给出一个。

那么是:“灰度方案”

历史经验告诉我,重构就没有不出问题的。那么核心问题就是怎么去把风险降到最低程度。那就是“灰度方案”解决的问题。

下面我重点说说灰度方案。

假如你只是重构一个接口,那很简单,加个开关就行。影响也不会太大。

但是如果重构的整个订单系统,而且表结构也修改了,直接上线能行吗?出现问题后果不敢想象。

我们常用的方案就是按流量去灰度。

阶段 流量比例 说明
阶段一 白名单 (一般就添加内部人员,只有这部分人访问到新系统,有问题也只影响到我添加的这部分人)
阶段二 万分之一 有问题只影响万分之一的人,比如我一分钟下单10W, 那有问题一分钟也就影响10个人。这个阶段基本上能发现一些问题。
阶段三 1% 流量逐步放大。
阶段四 10% 一般偶现问题在这个阶段会凸显出来,例如并发问题。
--- ---- ----
阶段N 100% 流量100%切换到新系统之后,老系统退出历史舞台。

以上分多少个阶段,可以由本公司的业务场景,请求量来决定。目的就是降低风险,让风险可控。

那么,按流量灰度怎么做呢?

关注我的人知道,我之前也写过文章,浅谈基于openresty(nginx+lua)开发轻量级,按流量控制的灰度模块,那这个什么时候会用呢。

这要看你重构系统的范围。假如你只是重构订单系统,对其它的组没有啥影响。那在网关层加一个灰度算法就能解决。

很简单,弄一个整型随机数。随机数 / 基数10000  < X 计算,当为true 走新系统,否则走老系统。例如 10%流量 , X = 10即可。

但是如果你重构的系统范围比较大,整个公司底层架构都要变,影响多个组重构,那可能就需要在nginx层开发lua灰度模块。

总结

以前余老大说过这样一句话:"重构这件事,做一次就够了",我却折腾了三次。但是不得不说,重构之后系统性能提升,解决没有遇到的问题是很愉快的。也许,这就是架构之美吧。

在这里,也感谢曾经一起奋斗的兄弟们。

最后,如果你有PHP转Java语言,或者重构方面有什么问题的朋友,可以私信我交流。

欢迎关注 “浅谈架构” 公众号,不定期分享原创文章。一起交流学习,进步,共勉!

猜你喜欢

转载自blog.csdn.net/weixin_38130500/article/details/122711225