近期一名同事发现了一个业务接口存在插入重复数据的问题,让我帮忙一起解决下,解决完了后感觉此问题有点意义,分享给大家。

接口功能

从OA系统下载报销单(报销单+报销明细+发票明细),存入ERP系统的费用模块

问题现象

出现重复记录(比如下载了1000条,到了费用模块变成了多于1000条,有记录重复的现象,没有固定的规律,重复的条数也不固定,记录里有插入的时间戳,时间差在毫秒级别),业务服务日志中没有错误。

业务逻辑

从OA系统下载数据,根据单据号查询本地数据库中已经存在的单据,将去重后的剩余单据插入数据库

解决过程

1、因为重复记录的插入时间很接近(毫秒级别差异),我首先排除了Dubbo的重试机制,感觉肯定是代码并发问题

2、看业务代码,结果并没有发现可疑代码,压根没有并发的代码

3、陷入僵局

4、测试环境加详细日志,根据logId的查询,发现了两个Dubbo线程号(26和27)使用了相同的logId(logId是一个在分布式系统中全局传递的字符串,会随着日志组件记录到日志中,也就是分布式链路追踪用的,生命周期从网关接到请求时产生,到网关响应后结束)

5、通过日志分析发现 26号线程是先出现的,27号线程是后出现的,之后两个线程同时运行

6、根据日志的记录知道了27号的线程是从网关进入的,再加上同一个logId的证据,所以推断此接口触发了网关重试机制

7、网关重试机制触发的临界点是30秒,如果后端业务接口30秒没有响应,网关会重新发起请求,使用相同的logId

8、还有疑问:为什么只重复个别的单据,并且没有规律,时多时少? 为什么重复单据的插入时间戳如此接近?这无法解释啊

9、经过分析业务逻辑代码给出了答案:1)入库方法使用了自动提交事务(也就是没有开启事务),遍历集合插入,非批量插入  2)遍历集合前的一次去重操作。

10、由此得出了完整的事发过程

现场还原

前端向后端发起同步OA数据请求,前端堵塞等待响应,网关转发请求到业务服务,业务服务中dubbo 26号线程开始运行,下载OA数据,本地去重,本地存数据库过程中超过了30秒钟,网关重试机制触发,于是业务服务中27号线程开始执行同样的任务,(由于测试环境只启用了一份docker容器,所以两个线程都到了同一个jvm中)

它也进行了去重操作,由于方法没有开启事务,所以26号线程插入的数据都是实时生效的,所以27号线程通过去重的操作过滤了 大部分单据,只剩下了少量的单据进行插入操作,从而形成26号和27号几乎同时插入相同的单据信息,诡异的地方就是 这个业务表里的主键是一个独立的id自然主键,和业务数据无关,所以两个线程都可以插入成功,并且插入时间戳差异在毫秒级别。这就可以完全解释通上面的现象是如何造成的了。

问题总结

1、单据号列建立唯一索引,在数据库层面拒绝脏数据的产生,避免重复数据。

2、关于这种导数据的接口该不该加事务,没有一个绝对的答案,因为数据量大小不固定(上游接口提供的数据量不固定),我倾向于折中方案,数据量较大时 分批次提交事务,避免事务的过大或者过小。

3、同步操作改异步轮询状态来解决超时网关重试问题

4、去重操作还是需要的,这也是在保持接口的幂等

5、持久化没有事务+代码幂等去重操作+数据表没有建立唯一索引+重试机制 = 导致了此次诡异现象的发生。由于重复记录的时间戳非常接近,误导了最初的判断。

今天就到这里,感谢大家关注老吕架构。

一个诡异的问题的解决20211008相关推荐

  1. 树莓派3代刷ubuntu mate在命令行下配置wifi不能连接的一个诡异的bug的解决

    家里路由器不在自己卧室,用树莓派考虑用wifi,之前用Raspberry官方系统,按照教程写的wpa.conf可以连接wifi,后来重新刷ubuntu mate 16.04就不好用了 各种找原因,后来 ...

  2. Struts2一个诡异问题的解决

    项目中使用Struts2..像很多问题一样,刚开始出现的时候,觉得很诡异,难以入手:解决掉之后,就知道其实很简单了. 前几天遇到一个问题,在某Action类中定义了一个名为success的字符串变量, ...

  3. 在使用谷歌时发现一个诡异问题cookie传不过去

    在使用谷歌时发现一个诡异问题cookie传不过去 查找相关资料发现这是谷歌的一个新属性SameSite导致的, SameSite 属性 Cookie 的SameSite属性用来限制第三方 Cookie ...

  4. php fwrite 数组,浅析php fwrite写入txt文件的时...-发现一个诡异的bug,不知何解...-php折线图 布局图 - 侯志凯_169IT.COM...

    本页文章导读: ▪浅析php fwrite写入txt文件的时候用 \r\n不能换行的问题 - 一觉睡到天黑黑      以下是对php中fwrite写入txt文件的时候用 \r\n不能换行的问题进行了 ...

  5. oracle数据库sid已存在,Oracle SID在本机下已经存在,请指定一个不同的SID”的解决方法...

    Oracle SID在本机上已经存在,请指定一个不同的SID"的解决办法 windows 系统: 1. 开始->设置->控制面板->管理工具->服务 停止所有Orac ...

  6. cmd使用另一个Oracle的sid,(转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID”的解决办法...

    (转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID"的解决办法 (2014-04-30 10:57:17) 1. 开始->设置->控制面板->管理工具 ...

  7. 一个诡异的可见性问题

    转载自 一个诡异的"可见性"问题 之前介绍过可见性的特性,最近做测试的时候发现了一个很诡异的问题,下面看看这三个例子. test1: test1这个例子加了volatile,所以程 ...

  8. 开发过程中任何一个时刻,只关注解决当前面临的问题。

    开发过程中任何一个时刻,只关注解决当前面临的问题. 转载于:https://www.cnblogs.com/philosophywang/archive/2011/11/30/2269009.html

  9. 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决

    计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决. 这句话几乎概括了计算机软件体系结构的设计要点.整个体系从上到下都是按照严格的层级结构设计的. 而这个中间层通过映射来连接上下文. 不仅是 ...

最新文章

  1. a标签怎么传参_jsp页面中怎么利用a标签的href进行传递参数以及需要注意的地方...
  2. 配置Citrix Receiver 3.x、4.x支持添加HTTP站点
  3. 球迷福利!Next VR本周将直播三场ICC比赛
  4. 奥特曼系列ol光元在哪个服务器,奥特曼系列ol光元怎么合理使用
  5. UI基础:UILabel.UIFont
  6. mysql数据库check命令_利用mysqlcheck命令快速修复mysql数据库
  7. python怎么导出数据_如何用python将数据导出
  8. mayan 游戏真是毒瘤
  9. pr cpu100%_PR插件Beauty Box安装教程
  10. 2019年互联网企业软件测试面试题(常考)
  11. OSC 第 130 期高手问答 — 究竟什么才是微服务?_黄勇【摘选】
  12. 超越前作,实现动漫风格迁移——AnimeGANv2
  13. 【知识兔】Excel教程:文本转数值的这些套路,你都会了吗?
  14. ES6数据部分(字符串,数组,对象,symbol,set,map)
  15. 用python计算复利和年化收益率
  16. 西门子1200PLC和KTP700触摸屏控制西门子V90伺服电机例子程序
  17. 电磁场与仿真软件(20)
  18. 在C#隐藏主窗口的几种方法
  19. 热门移动端H5开源前端开发框架搜集整理
  20. 擦亮AI之星:百度奖学金到底在嘉奖什么?

热门文章

  1. 机器人滚边有波浪_基于ABB机器人滚边技术的研究与应用
  2. 使用CAXA 3D实体画一个立体五角星
  3. 微机原理和计算机组成原理一样吗_「连载」信息技术基础题型归纳之计算机组成原理3...
  4. 将flash中的代码复制到RAM中运行的方法
  5. 随机发牌_Java项目实战:斗地主洗牌发牌小游戏
  6. 谈谈培训机构的-骗局-怎么避免被坑
  7. [Matlab科学计算] 共轭梯度法求一般函数的最小值
  8. Classmate Reunion-Technical Support
  9. Springboot毕设项目健康美食及菜谱分享系统的设计与实现xr4n8(java+VUE+Mybatis+Maven+Mysql)
  10. ssm+jsp计算机毕业设计爱心捐赠管理系统设计与实现m7n8p(程序+LW+源码+远程部署)