网站怎么做关键字,建设一个网站需要哪些功能,上海 网站制作,请被人做网站本文主要讨论四个问题#xff1a; #xff08;1#xff09;为什么会有冗余表的需求 #xff08;2#xff09;如何实现冗余表 #xff08;3#xff09;正反冗余表谁先执行 #xff08;4#xff09;冗余表如何保证数据的一致性 一、需求缘起 互联网很多业务场景的数据量…本文主要讨论四个问题 1为什么会有冗余表的需求 2如何实现冗余表 3正反冗余表谁先执行 4冗余表如何保证数据的一致性 一、需求缘起 互联网很多业务场景的数据量很大此时数据库架构要进行水平切分水平切分会有一个patition key通过patition key的查询能够直接定位到库但是非patition key上的查询可能就需要扫描多个库了。 例如订单表业务上对用户和商家都有订单查询需求 Order(oid, info_detail) T(buyer_id, seller_id, oid) 如果用buyer_id来分库seller_id的查询就需要扫描多库。 如果用seller_id来分库buyer_id的查询就需要扫描多库。 这类需求为了做到高吞吐量低延时的查询往往使用“数据冗余”的方式来实现就是文章标题里说的“冗余表” T1(buyer_id, seller_id, oid) T2(seller_id, buyer_id, oid) 同一个数据冗余两份一份以buyer_id来分库满足买家的查询需求 一份以seller_id来分库满足卖家的查询需求。 二、冗余表的实现方案 【方法一服务同步写】 顾名思义由服务层同步写冗余数据如上图1-4流程 1业务方调用服务新增数据 2服务先插入T1数据 3服务再插入T2数据 4服务返回业务方新增数据成功 优点 1不复杂服务层由单次写变两次写 2数据一致性相对较高因为双写成功才返回 缺点 1请求的处理时间增加要插入次时间加倍 2数据仍可能不一致例如第二步写入T1完成后服务重启则数据不会写入T2 如果系统对处理时间比较敏感引出常用的第二种方案 【方法二服务异步写】 数据的双写并不再由服务来完成服务层异步发出一个消息通过消息总线发送给一个专门的数据复制服务来写入冗余数据如上图1-6流程 1业务方调用服务新增数据 2服务先插入T1数据 3服务向消息总线发送一个异步消息发出即可不用等返回通常很快就能完成 4服务返回业务方新增数据成功 5消息总线将消息投递给数据同步中心 6数据同步中心插入T2数据 优点 1请求处理时间短只插入1次 缺点 1系统的复杂性增加了多引入了一个组件消息总线和一个服务专用的数据复制服务 2因为返回业务线数据插入成功时数据还不一定插入到T2中因此数据有一个不一致时间窗口这个窗口很短最终是一致的 3在消息总线丢失消息时冗余表数据会不一致 如果想解除“数据冗余”对系统的耦合引出常用的第三种方案 【方法三线下异步写】 数据的双写不再由服务层来完成而是由线下的一个服务或者任务来完成如上图1-6流程 1业务方调用服务新增数据 2服务先插入T1数据 3服务返回业务方新增数据成功 4数据会被写入到数据库的log中 5线下服务或者任务读取数据库的log 6线下服务或者任务插入T2数据 优点 1数据双写与业务完全解耦 2请求处理时间短只插入1次 缺点 1返回业务线数据插入成功时数据还不一定插入到T2中因此数据有一个不一致时间窗口这个窗口很短最终是一致的 2数据的一致性依赖于线下服务或者任务的可靠性 上述三种方案各有优缺点但不管哪种方案都会面临“究竟先写T1还是先写T2”的问题这该怎么办呢 三、究竟先写正表还是反表 对于一个不能保证事务性的操作一定涉及“哪个任务先做哪个任务后做”的问题解决这个问题的方向是 【如果出现不一致】谁先做对业务的影响较小就谁先执行。 以上文的订单生成业务为例buyer和seller冗余表都需要插入数据 T1(buyer_id, seller_id, oid) T2(seller_id, buyer_id, oid) 用户下单时如果“先插入buyer表T1再插入seller冗余表T2”当第一步成功、第二步失败时出现的业务影响是“买家能看到自己的订单卖家看不到推送的订单” 相反如果“先插入seller表T2再插入buyer冗余表T1”当第一步成功、第二步失败时出现的业务影响是“卖家能看到推送的订单卖家看不到自己的订单” 由于这个生成订单的动作是买家发起的买家如果看不到订单会觉得非常奇怪并且无法支付以推动订单状态的流转此时即使卖家看到有人下单也是没有意义的。 因此在此例中应该先插入buyer表T1再插入seller表T2。 however记住结论【如果出现不一致】谁先做对业务的影响较小就谁先执行。 四、如何保证数据的一致性 从二节和第三节的讨论可以看到不管哪种方案因为两步操作不能保证原子性总有出现数据不一致的可能那如何解决呢 【方法一线下扫面正反冗余表全部数据】 如上图所示线下启动一个离线的扫描工具不停的比对正表T1和反表T2如果发现数据不一致就进行补偿修复。 优点 1比较简单开发代价小 2线上服务无需修改修复工具与线上服务解耦 缺点 1扫描效率低会扫描大量的“已经能够保证一致”的数据 2由于扫描的数据量大扫描一轮的时间比较长即数据如果不一致不一致的时间窗口比较长 有没有只扫描“可能存在不一致可能性”的数据而不是每次扫描全部数据以提高效率的优化方法呢 【方法二线下扫描增量数据】 每次只扫描增量的日志数据就能够极大提高效率缩短数据不一致的时间窗口如上图1-4流程所示 1写入正表T1 2第一步成功后写入日志log1 3写入反表T2 4第二步成功后写入日志log2 当然我们还是需要一个离线的扫描工具不停的比对日志log1和日志log2如果发现数据不一致就进行补偿修复 优点 1虽比方法一复杂但仍然是比较简单的 2数据扫描效率高只扫描增量数据 缺点 1线上服务略有修改代价不高多写了2条日志 2虽然比方法一更实时但时效性还是不高不一致窗口取决于扫描的周期 有没有实时检测一致性并进行修复的方法呢 【方法三实时线上“消息对”检测】 这次不是写日志了而是向消息总线发送消息如上图1-4流程所示 1写入正表T1 2第一步成功后发送消息msg1 3写入反表T2 4第二步成功后发送消息msg2 这次不是需要一个周期扫描的离线工具了而是一个实时订阅消息的服务不停的收消息。 假设正常情况下msg1和msg2的接收时间应该在3s以内如果检测服务在收到msg1后没有收到msg2就尝试检测数据的一致性不一致时进行补偿修复 优点 1效率高 2实时性高 缺点 1方案比较复杂上线引入了消息总线这个组件 2线下多了一个订阅总线的检测服务 however技术方案本身就是一个投入产出比的折衷可以根据业务对一致性的需求程度决定使用哪一种方法。我这边有过好友数据正反表的业务使用的就是方法二。 【完】 【转自】58沈剑 架构师之路转载于:https://www.cnblogs.com/bad-man/p/7866312.html