查询时间范围_业务二三事——时间范围分页取数的坑

44491524bd9bf3bd0b4e1f1563160040.png

一场由时间戳范围取数引发的血案

背景

接手了一个系统,该系统需要对下游提供数据,因此在数据变化时,需要告知下游系统。原开发人员可能为了系统解耦,没有采用同步调用的方式进行通知,提供了一个按照最后变更时间范围的查询接口进行查询,接口契约大概如下:

{    "datachangeLasttimeFrom":1,    "datachangeLasttimeTo":2,    "pageIndex":1,    "pageSize":10}

取数据最后变更时间大于1 小于等于2的数据。

系统正常运行了一段时间,但是某一天突然下游说我们的系统有些数据没有正常同步过去,这就令人头大了。

事件分析

接到事件之后,捋了一遍接口逻辑,竟然一时没有发现什么问题。T^T

查看日志也没有找到问题,最后又过了一遍代码,才明白为什么了系统在平稳运行一段时间后,才出现上述的问题。

系统上线初期,用户量小,不存在并发读写的问题;当运行一段时间后,用户量变多,在下游调用接口进行数据同步的时候,出现并发的写请求,会出现数据丢失的情况。

具体情况如下图所示:

①分页查询:符合查询条件的有10条记录,分页取第1页,分页大小为5

c1e722a19fb6abed7b9559620b9c4b86.png

通过时间戳范围进行查询的SQL语句

36ac1b99e7d8d3b7e78540cefff955ba.png

通过时间戳范围进行查询的SQL语句

eb8bcde179dfeb5212d3661916963e21.png

分页查询,符合条件的有10条记录,取第1页,5条

②并发更新:已被取到的数据,在此时进行了更新,如图中记录5

375fa96d5c65d54136eb85f42a5554ba.png

已被取到的数据,在此时进行了更新,如图中记录5

③继续分页取数:此时继续根据时间戳范围进行取数,数据6丢失了

479f1127bd6809208b14e13d7c6a5731.png

此时继续根据时间戳范围进行取数,数据6丢失了

解决方案

定位到问题的原因,解决起来就简单多了。我们对接口增加一个偏移量,每次取数后将偏移量回传,每次都取第一页数据,这样就不会产生数据丢失的问题。

71ed1584a2ba563cef61cfdd39815893.png

将上次获取到的主键ID进行回传

058af4fe965efe7c4e25dc6cd627137e.png

此时,就能成功取到数据6了

问题复盘

原本的开发同学为了系统的解耦,提供了这样一个接口,想法是好的,但是没有考虑全面,因此造成了生产的事件。经过我们的优化后,加上偏移量,这个方法仍然不是一个很好的方法,因为下游仍需要定时轮询接口,当接口方增多时,对接口的访问压力会直线上升;同时,即使不存在数据变更,下游系统仍需要轮询接口,造成资源的浪费。

本质上这是一个多系统间数据同步的问题,系统间的解耦我们通常使用消息队列。大致的实现方法就是发生数据变更的时候进行抛出消息,下游系统自行监听消息,调用查询接口进行数据同步。

消息队列的功能:①应用解耦 ②流量削峰

we can do it better

如何用MQ进行数据同步呢?

方案①:在所有保存接口和审核接口的地方手动抛出消息

方案②:在Service层中所有调用DAO层的地方横切,添加发送数据消息的逻辑

方案③:监听Canal,抛出消息

方案①和方案②在本质上是没有区别的,但是方案①需要开发人员的自我约束,在新增接口时,容易遗漏消息的抛出;方案①和方案②都无法解决DBA直接操作数据库的场景,因此我们采用方案③进行消息的发送。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值