作者回复: 假设A是用户表,B是订单表,那么传统数据库做法,C用户订单表=A join B。 如果采用数据分发+实时聚合方法,可以先建一张C表和一个实时聚合服务D,每次B表有数据变化(添加/更新或者删除),通过事务性发件箱或者CDC机制,将B表的变化发送给D,D可以根据C和A+B的变更,直接计算出并更新C。后面需要查找用户订单的时候,可以直接查C,不需要再Join。 在拍拍贷系统拆分场景中,主要是为了避免数据迁移过程中的跨库join,所以把涉及迁移的相关数据分发一份给依赖的服务,这样依赖的服务可以在本地DB做join(当然也可以用实时聚合技术消除本地join),这样对涉及迁移的数据就不是强依赖了,降低迁移的复杂度。
作者回复: 理论上应该按照业务领域或者团队边界进行拆分。实际拆分的时候,没有所谓比较好的拆分手段,很多时候都是见招拆招+简单粗暴+计划执行最能解决问题。
作者回复: 采用高性能消息队列+流计算,例如kafka-stream,同时设计要支持和接收最终一致性。另外做好性能监控告警+优化。
作者回复: 我们当时的实现是采用job定期比对,job定期跑(例如30秒跑一次),先从源数据库获取增量时间范围内的数据,然后再去目标数据库获取增量数据,然后做两边数据的比对,比对有误则发出告警。这个job是基于xxl-job实现,xxl-job采用高可用部署,也有job监控日志和告警。所以健壮主要靠监控和告警。
作者回复: 拆分服务的时候,尽量避免出现分布式事务的情况,如果两个服务涉及分布式事务,那么在拆的时候尽量合并作为一个服务一起拆出来,涉及分布式事务的操作也封装在一个接口中。 只有在不得已情况下,才考虑引入分布式事务解决方案。
作者回复: 阿里的rocketmq支持你说的这种mq带confirm的机制,业界实践反馈也可以保证双写一致性,当然mq本身的设计和实现会比较复杂。
作者回复: 这个具体要看业务系统的情况,如果业务系统需要连多个DB,那么就需要支持多数据源。 不管需不需要多数据源,揭耦拆分的一般步骤都是类似的。
作者回复: 是的,数据同步分发(包括CDC)是重要的迁移手段。
作者回复: 这个新老DB如果要完全不停机的实时同步是比较难的,我们当时是可以停机的,在凌晨业务量小时公告停机,等没有了流量,DBA将老数据一把导入新DB,然后停机结束开始接入流量,这时候两边是双写,数据可以保证一致。