在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如腾讯、美团、阿里、拼多多、极兔、有赞、希音的面试资格,遇到一几个很重要的面试题:
其实,答案不是一成不变的。
参考答案其实千千万万,在这里,尼恩一直结合行业案例,梳理一个最为全面、最为系统化的答案,
这里有一个新的行业案例《菜鸟积分系统稳定性建设 - 分库分表&百亿级数据迁移》,尼恩从 面试维度,对这个方案,进行二次重构和梳理,现在把其作为参考答案,收入咱们的《尼恩Java面试宝典 PDF》 V82版本
供后面的小伙伴参考,大家一定好好看看这个生产级别的答案。
本文原文:《菜鸟积分系统稳定性建设 - 分库分表&百亿级数据迁移》 原始方案的作者是 星花 ,原文来自于 公号,阿里开发者。
下面的内容,是尼恩是结合自己的3高架构笔记,以及尼恩的3高架构知识体系(3高架构宇宙),在原文的基础上,做的二次架构分析和创作。
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】取
分库分表&数据迁移,不仅仅是一个技术难题,考验的一个人的技术功底。
分库分表&数据迁移,也是一个协调难题,需要协调开发、运维,而是一个人就能搞定的。考验的一个人的协调功底。
所以,分库分表&数据迁移是大厂面试、架构面试的核心问题。
伟大的系统,都是迭代出来的。
在早期,为了快速试错,菜鸟积分系统单体系统,数据库是单库多表。
随着业务快速增长,菜鸟C端用户已经过3亿+,消费者从查、取、寄快件开始慢慢扩展到玩、购。
玩、购主要是商城以及各个业务线多种多样的活动,这些活动包含了停留、任务、开奖、分享、签到、助力、兑换、抽奖等多种多样的互动手段。
菜鸟的积分代表用户虚拟权益,在其中起到了钩子的作用。
菜鸟的积分为互动产品本身提供了某些“价值”,使得消费者在平台停留时间增加。
从这个维度来说,菜鸟积分系统一直扮演着一个底层核心角色,承载用户核心资产。
总体的 功能架构,如上图所示。
在大促期间需要支持大流量的活动,整个积分系统在大促期间面临挑战是非常大的。
菜鸟C端用户已经过3亿+,单体应用不可能支撑,存储层的单库多表也是不可能支撑的。
为了支持菜鸟C端营销业务的持续爆炸式增长,菜鸟积分系统需要升级。
问题是:如何在业务不暂停的情况下,完成积分从单库单表到分库分表的数据架构升级?
还有就是:这一高风险操作是如何逐步分阶段完成的?
在开始设计迁移方案之前,菜鸟积分团队认真进行了问题分析,发现了本项目面临以下几个主要的挑战:
由于涉及到数据的重构,项目风险极大,没处理好可能就要背包走人了。
为啥呢?
然而,既然风险这么大,那能不干这个分库分表迁移项目吗?
不能!为啥呢:
正所谓:箭在弦上,不得不发。
表的情况:积分系统主要2张核心的表,积分总表和积分明细表。
数据的情况:2个库中的数据达百亿,积分明细的增量数据规模大,日新增数据也在千万级。
积分系统对外提供的服务接口主要有:
为了临时解决大促期间系统性能瓶颈问题,读积分会通过缓存tair(类似redis)做查询,击穿缓存才会到达数据库,写积分会直接更新数据库(缓存是)。
数据库的压力,在写不在读。
通过观察,大促期间,数据库瓶颈是在写积分对数据库的压力上。
如果把数据库纵向扩展,升级最高配置,也不能彻底解决问题:
40岁老架构师提升:作为架构师,一定要提供多个候选方案,可选方案。
解决100亿级库表性能瓶颈的可选方案,主要有三个方案:
方案二、方案三指标不治本, 只是延迟了问题,并没有解决问题。延迟的结果是, 越拖成本越高。
通过综合考虑, 选择方案一进行优化,彻底解决 解决100亿级库表性能瓶颈。
(1) 分库分表的分片键设计:
由于是积分总表和明细表,所以从用户维度进行分表
(2) 分库分表的规模设计:
分库分表是分8个库,1024张表
具体的分库分表的方法论,请参见尼恩秒杀视频。或者参考尼恩的推送中台视频。
(3)主键ID 的方案设计
在迁移数据的过程中特别要注意的是主键ID,主键ID需要程序生产的分布式主键.
也就是说,需要在程序中,手动的去指定主键。
而不能使用DB自增主键,防止ID生成顺序错误
具体的主键ID 的方案设计,请参见尼恩秒杀视频。或者参考尼恩的推送中台视频。
分库分表肯定要涉及数据迁移,数据迁移必定涉及一个全量和增量的数据,
数据迁移的关键是:如何保证数据不会重复,不会丢失,而且保证唯一性
数据迁移方案包括:全量迁移,增量迁移。
使用阿里数据迁移工具 精卫,这个工具既可以进行 全量迁移,也可以进行增量迁移。
精卫工具 会在全量任务的时候相当于记录数据库的一个副本,然后增量的时候可以进行任务回溯,
如何进行数据唯一性保证?该迁移工具可以保证数据的唯一性,对于已经存在的记录可以进行更新操作。
尼恩提示:
如果不是阿里,可以使用开源的数据同步工具。
比如阿里开源的DTS,就是是一件非常不错的工具。
DTS工具可以实现不同数据源之间的数据迁移、数据同步,只需要配置好两端的数据源就可以自动实现,不在需要人为的操作,非常的方便。
当然,如果熟悉kettle的,也可以使用kettle进行数据同步。
总之,有很多类似的中间件,或者自己编写迁移脚本
由于是动态迁移,不停服迁移,肯定不能通过发布程序来切换数据源,
所以,在程序层面进行改造,进行动态读写切换改造。
大致的思路:在程序里面手动去指定双数据源,预先在程序里面应该加载两个db的数据源,通过配置预先设定开关,然后动态进行读写切换。
为了实现可监控、可灰度、可回滚,还需要进行灰度。
从配置的维度来说,不仅仅是 切换的开关需要配置化,而且 需要保证灰度过程中切换比例,可以通过配置进行调控
数据迁移执行流程,大概有10个步骤:
userId%x
,进行验证,逐步流量打开,持续观察线上库配置完成,并且找到 业务低峰时段,进行迁移操作
1)配置工作
有关多数据源配置,可以参考尼恩推送中台中的多数据源配置。
2)通过监控查看业务低峰时段
全量数据迁移周期很长。
“全量数据迁移”是指是 老库的数据。这是真正的数据的迁移,它迁移的是老数据库表里已经存在的数据(这些数据可能是历史数据,早已经写入,也可能刚刚写入不久的数据,非未来新增的数据),一般来说, 会通过Select 获取源端数据库里的表的数据。然后通过Insert、Replace into、Update、Delete 的方式,写入到新库。
数据迁移的时间,有可能是一周,有可能是1个月
每一次数据迁移都需要一段漫长的时间,不是一天两天就搞定了的。
通常来说我们迁移数据的过程基本如下图:
开启全量同步
gmt_modified
作为条件字段无论是全量还是校验,其实都会对源端备库,目标端的主库造成压力。所以这里需要注意一下,以免对线上服务造成影响。
update
执行增量同步:全量迁移完成后开启增量(自动回溯全量开始时间,消息多次消费会进行幂等)
完成全量的迁移后,然后需要处理新增的这部分数据。
需要实时的增量数据在写完原本的数据库之后然后写到我们的新的存储,在这一过程中我们需要不断的进行数据校验。
当我们校验基本问题不大的时候,然后进行切流操作,直到完全切流之后,我们就可以不用再进行数据校验和增量数据迁移。
在数据迁移工具(精卫)中,开启增量任务, 增量同步需要注意的地方:
INSERT
改成UPDATE
事件。用户无需担心主键冲突产生异常。增量同步涉及到同步位点说明:增量同步主要是参照原库的binlog位点开始的,这个同步位点,也叫做消费位点。
具体来说, 消费位点是指当前已经成功消费的Binlog队列的位置,位点是一个 ‘yyyy-MM-dd HH:mm:ss’ 格式的时间戳。
全量数据校验,查看数据是否一致
全量同步之后,我们需要不断的进行数据校验。
增量同步之后,我们也需要不断的进行数据校验。
当我们校验基本问题不大的时候,然后进行切流操作,直到完全切流之后,我们就可以不用再进行数据校验和增量数据迁移。
数据校验包括:
下面使用的工具是阿里内部的,原理都类似,可以参考阿里对外开源的数据传输服务DTS。
通过校验,找到 数据的差异,进行数据的修正,或者叫做订正
业务校验主要是进行数据的一致性校验。
需要注意:业务校验任务注意不要影响线上运行的服务,通常校验任务会写很多批查询的语句,会出现批量扫表的情况,如果代码没有写好很容易导致数据库挂掉。
对账标准:target数据库和source数据库中数据保持一致(所有字段)
对账梳理:可以从积分总表和积分明细两个方面来处理
对账流程:通过定时任务轮询执行已经完成迁移的用户在新老库的数据一致性。需要注意的是由于读取新老库有先后顺序,所以产生瞬时的数据不一致,对于这种问题可以采用对账重试,只要保证最终一致即可。
1)抽样数据校验
按业务类型或者用户id,对最新增量数据进行抽样校验(下面校验工具为阿里内部工具,外部可以参考阿里数据传输服务DTS),然后需要对有问题数据进行订正
2)Odps离线数据校验
使用odps的小时表来进行对账。思路很简单,利用odps数据同步能力,离线数据的处理能力,加上动态脚本的编写快速实现多系统间对账。
不需要进行应用的改造,稳定性上也有保障。对于实时性要求不高的场景,可以推荐尝试使用。
改造代码预发测试(采集线上流量进行回放,多种case跑一下,切流开关等校验),没问题发布上线
确保安全,在正式切流前,再次全量进行校验&订正(数据追平)
整体上分为下面4个步骤,通过配置动态进行切换,切换期间需要注意的问题如下:
找准时间阶段操作,在低流量阶段(凌晨过后) 进行操作
操作的时候,进行灰度处理,逐步推进。
进行灰度切流userId%x
,进行验证,逐步流量打开,持续观察
读切流的流程:
xxProxyDAO.class
注意:对于没有路由字段userId,需要进行代码改造
当我们数据校验基本没有报错了之后,说明我们的迁移程序是比较稳定的了,那么我们就可以直接使用我们新的数据了吗?当然是不可以的,如果我们一把切换了,顺利的话当然是很好的,如果出现问题了,那么就会影响所有的用户。所以我们接下来就需要进行灰度,也就是切流。
本次切流方案是基于用户id取模的方式去进行切流,这个切流需要制定好一个切流计划,在什么时间段,放出多少的流量,并且切流的时候一定要选择流量比较少的时候进行切流,每一次切流都需要对日志做详细的观察,出现问题尽早修复,流量的一个放出过程是一个由慢到快的过程,比如最开始是以1%的量去不断叠加的,到后面的时候我们直接以10%,20%的量去快速放量。因为如果出现问题的话往往在小流量的时候就会发现,如果小流量没有问题那么后续就可以快速放量。
切换过程采用逐步放量的形式,灰度方式很多我们采用的是先白名单验证,然后用户ID取模10000逐步放量的方式。
灰度切流验证:万分之1-1%-5%-10%-50%-100%切流
灰度读切流完成之后, 读流量,全部落入到 新库。
双写开关切到新库,保证只写新库,完成数据迁移方案
前面的第7步的双写,已经变成了单写。
直到切流到100%,迁移已经完成。
但是,老库还不能立即下线, 还得备用一段时间,以防万一出问题还能切回老库
并且,需要保证老库的数据,能是最新的。
所以,开启精卫新库到老库同步任务。
然后观察各个业务后续工单反馈情况和各个系统预警&日志;对新库进行性能压测,确保新库的稳定性
最后简单来总结下这个套路,总结起来,其实就是四个步骤:
第1步:存量同步,
第2步:增量同步,
第3步:数据校验,
第4步:灰度切流
更细致一点,就是10个步骤,具体如上。
周期很长:整个迁移过程从方案制定到最终的迁移完成持续约一个多月时间,最终完成迁移。
方案可靠:无论是利用数据库工具还是利用服务对数据进行迁移,目标都是一致的那就是数据无差异,用户无感知,异常可监控,方案可回滚。
充分演练:在迁移前尽可能进行演练,通过一些测试编写的自动化脚本能否高效发现一些潜在的问题。
尽早迁移:同时存储是有状态的,迁移难度比较大,开发者需要具备前瞻性,尽量在选型的时候慎重,选择合适的数据库,避免进行数据库迁移。发现数据库选型有潜在的问题时,需要当机立断,尽早迁移。不要以为出现问题的概率不大,就拖延了。否则一旦出现问题,就是重大故障,造成的损失难以估量。
https://baijiahao.baidu.com/s?id=1711398612204958365&wfr=spider&for=pc
https://github.com/alibaba/tb_tddl
https://github.com/alibaba/yugong
https://www.aliyun.com/product/dts
以上的方案,可以作为大家的一个参考答案。保证面试官非常满意。
后续尼恩会给大家结合行业案例,分析出更多,更加劲爆的答案。
当然,如果大家遇到这类高并发的面试难题,可以找来尼恩的 【技术自由圈】 聊聊。
《腾讯太狠:40亿QQ号,给1G内存,怎么去重?》
《1000亿数据、30W级qps如何架构?来一个天花板案例》
《100亿级订单怎么调度,来一个大厂的极品方案》
《2个大厂 100亿级 超大流量 红包 架构方案》
《千万级、亿级数据,如何性能优化?教科书级 答案来了》
尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓