数据量太大的时候,单个存储节点存不下,就只能把数据分片存储。
- 数据分片之后,我们对数据的查询就没有这么自由了。比如订单表如果按照用户ID作为sharding key来分片,那就只能按照用户维度来查询。如果商家想查自己店铺的全部订单就做不到(当然,可以强行把所有分片查一遍,然后聚合起来,但是实际意义不大)
- 对于这样的需求,普遍的解决方法是空间换时间,毕竟现在存储越来越便宜,再存一份订单数据到商家订单库,然后以店铺ID作为sharding key分片,专门供商家查询订单。
- 另外,同样一份商品数据,如果如果是按照关键字搜索,放在ES中就比放在MySQL中快几个数量级。原因是,数据组装方式、物理存储结构和查询方式,对查询性能的影响是巨大的,而且海量数据还会指数级的放大这个性能差距
所以,在大厂中,对于海量数据的处理原则,都是根据业务对数据查询的需求,反过来确定选择什么数据库、如何组织数据、如何分片数据,这样才能达到最优的查询性能。同样一份订单数据,除了在订单库保存一份用于在线交易以外,还会在各种数据库中,以各种各样的组织方式存储,用于满足不同业务系统的查询需求。
那么,问题来了,如何能够做到这么多份数据实时保持同步呢?
不能用分布式事务,你可以用本地消息表,把一份数据实时同步给另外两三个数据库还是可以接收的,太多就不行了,并且分布式事务对在线业务交易还有侵入性,所以分布式事务是解决不了这个问题的。
所以,如何把订单数据实时、准确无误的同步到这么多异构的数据中呢
早期大数据刚刚兴起的时候,大多数系统还做不到异构数据库实时同步,那个时候普遍的做法是,使用 ETL 工具定时同步数据,在 T+1 时刻去同步上一个周期的数据,然后再做后续的计算和分析。定时 ETL 对于一些需要实时查询数据的业务需求就无能为力了。所以,这种定时同步的方式,基本上都被实时同步的方式给取代了。
如果想要同步mysql到redis中,可以利用canal把自己伪装成一个mysql的从库,从mysl中实时接收binlog然后写入redis中。把这个方法稍微改进一下,就可以用来做异构数据库的同步了
为了能够支撑下游众多的数据库,从canal出来的binlog数据肯定不能直接去写下游那么多数据库,一是写不过来,二是对于每个下游数据库,它可能还有一些数据转换和过滤的工作要做,所以需要增加一个MQ来解耦上下游。
canal从MySQL收到binlog并解析成结构化数据之后,直接写入到MQ的一个订单binlog主题中,然后每一个需要同步订单数据的业务方,都去订阅这个MQ中的订单binlog主题,消费解析后的binlog数据。在每个消费者自己的同步程序中,它既可以直接入库,也可以做一些数据转换、过滤或者计算之后再入库,这样就比较灵活了
这个方法看起来不难,但是非常容易出现性能问题。有的接收binlog消息的下游业务,对数据的实时性要求比较高,不能容忍太高的同步时延。比如说,每个电商在大促的时候,都会有一个大屏幕,实时显示现在有多少笔交易,交易额是多少。这个东西都是给老板们看的,如果说大促的时候,你让老板们半小时之后才看到数字,那估计你就得走人了。
大促的时候,数据量大、并发高、数据库中的数据变动频繁,同步的binlog流量也非常大。为了保证这个同步的实时性,整个数据同步链条上的任何一个环节,它的处理速度都必须跟得上才行。我们一步一步分析可能会出现性能瓶颈的环节。
源头的订单库,如果它出现繁忙,对业务的影响就不只是大屏延迟了,那就影响到用户下单了,这个问题是数据库本身要解决的,这里我们不考虑。再顺着数据流往下看,canal和MQ这两个环节,由于没什么业务逻辑,性能都非常好。所以,一般容易成为性能瓶颈的是消费MQ的同步程序,因为这些同步程序里面一般会有一些业务逻辑,而且如果下游的数据库写性能跟不上,表象也是这个同步程序处理性能上不来,消息积压在MQ里面。
那我们能不能多加一些同步程序的实例数,或者增加线程数,通过增加并发来提升处理能力呢?不行。这个地方的并发数,不是随便说扩容就可以扩容的
- MySQL主从同步binlog,是一个单线程的同步过程。
- 为什么是单线程?原因很简单,在从库执行binlog的时候,必须按照顺序执行,才能保证数据和主库是一样的。为了保证数据一致性,binlog的顺序很重要,是绝对不能乱序的
- 严格来说,对于每一个MySQL实例,整个处理链条都必须是单线程串行执行,MQ的主体也必须设置为只有1个分区(队列),这样才能保证数据同步过程中binlog是严格有序的,写到目标数据库的数据才能是正确的。
那单线程处理速度上不去,消息越积压越多,这不是无解了吗?其实办法还是有的,但是必须和业务结合起来。
- 以订单库为例,其实我们并不需要对订单库所有的更新操作都严格有序的执行,比如说A和B两个订单号不同的订单,这两个订单谁先更新谁后更新并不影响数据的一致性,因为这两个订单完全没有任何关系。但是同一个订单,如果更新的binlog执行顺序错了,那同步出来的订单数据就真的错了
- 也就是说,我们只要保证每个订单的更新操作日志的顺序别乱就可以了。这种一致性要求称为因果一致性(Causal Consistency),有因果关系的数据之间必须要严格地保证顺序,没有因果关系的数据之间的顺序是无所谓的。
- 基于这个理论基础,我们就可以并行地来进行数据同步,具体的做法是这样的:
- 首先根据下游同步程序的消费能力,计算出需要多少并发
- 然后设置MQ中主题的分区(队列)数量和并发数一致。因为MQ是可以保证同一分区内,消息不乱序,所以我们需要把具有因果关系的binlog都放到相同的分区内,就可以保证同步数据的因果一致性。
- 对应到订单库就是,相同订单号的 Binlog 必须发到同一个分区上。
- 这是不是和之前讲过的数据库分片有点儿像呢?那分片算法就可以拿过来复用了,比如我们可以用最简单的哈希算法,Binlog 中订单号除以 MQ 分区总数,余数就是这条 Binlog 消息发往的分区号。
以上就是本篇文章【电商:跨系统实时同步数据,分布式事务是唯一的解决方案吗?】的全部内容了,欢迎阅览 ! 文章地址:http://dgaty.xhstdz.com/quote/70886.html 栏目首页 相关文章 动态 同类文章 热门文章 网站地图 返回首页 物流园资讯移动站 http://dgaty.xhstdz.com/mobile/ , 查看更多