在每天的结算跑批过程中,前面A应用会更新某些值,紧接着B应用就会去查询这批数据。但是,在某一天跑批的过程中,突然自动报警反馈,结算跑批异常。协同开发进行相关问题的跟踪排查,本来是秒级查询结果的任务,但是突然出现了超时好几分的情况,这是哪里的问题?

更新SQL
UPDATE AAA.T_ORD_INFP
AUD_BNO = '24080206551ABCD',
DT_UTE = to_char(sysdate,'yyyymmdd'),
TM_UTE = to_char(sysdate,'hh24miss')
                        where set_ono='20240802222CCC'
                        and (SET_STS = '02' or SET_STS = 'AC')

查询SQL
SELECT
                inf.SET_ONO as "setOno"
                FROM
                AAA.T_ORD_INFP inf
WHERE
                        inf.aud_bno = '24080206551ABCD' and inf.SET_STS = '02'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

网络层进行了抓包

结算跑批返回结果超时扫雷排查_线程池

结算跑批返回结果超时扫雷排查_线程池_02

我们能看见开发所说的时间范围内的SQL。那么到底在数据库里面是如何的,我们使用logmner进行日志挖掘,这里说一下,当问题发生的时候,及时保留现场证据是最为重要的,比如当时的alert日志,crs日志,主机messages,osw日志,或者使用tfa及时进行相关证据数据的保留以备不时之需。

结算跑批返回结果超时扫雷排查_数据库_03

从上图我们可以看见,数据库开启事务时间是6:55:11秒、结束时间是6:57:38秒,相差2分钟。而开发给出的结果是,当前A事务在更新完成后,使用架构框架会自动提交,然后紧接着B应用,就会去查询,如果查询不到会走降级处理。2分钟查询不到怀疑是数据库的问题。

而DBA这里反复与开发沟通的是,库内确认提交的时间在2分钟后。为此陷入了扯皮环节或者在自证清白环节。这里我在重新把该事故进行相关梳理罗列:

1,A应用51个事务进行批量数据处理。
2,B应用在1-50个事务进行批量处理过程中,即可查询,如无结果降级处理。
3,DBA排查入库开始时间与提交时间相差2分钟。
4,DBA挖到的日志ID也就是XID均为同一个XID,而开发给出的是51个独立的事务。那这里是有什么事务合并吗?数据库没有设定批提参数,因为批提参数是以丢数风险换取性能。在我们金融行业很明显不可取。
5,那么是不是在中间链路环节出了问题,如防火墙、交换机、网络过程中?慢了这2分钟。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

结算跑批返回结果超时扫雷排查_线程池_04

网络流量确实有凸起,找网络同事排查,该服务器确实有一些丢包问题。那么回归疑问,为啥51个事务,会是同一个XID?

更新结算单状态时,每一个批次开启一个异步线程,开线程使用的Spring的Async注解,线程池设置核心线程数为20,等待队列为2000,当付款单总笔数大于404000笔时(也就是2020个批次),会大概率触发线程池的拒绝策略,Spring对于使用Async开启线程的机制是触发拒绝策略,将异步降级为同步http调用,上周五有51个批次降级为同步Http调用,降级后,51个批次使用外层的大事务一次性提交到数据,造成子线程执行完成后立刻查询数据查询不到,因为外层事务没有提交。

该问题就是事务过大:如果一个事务覆盖了大量的操作,它会锁定大量资源,导致数据库性能下降,增加了死锁的风险,同时事务持续时间过长还会影响数据库的并发能力。

数据延迟可见性:由于外层事务一次性提交,虽然内部子任务可能已经处理完成,但由于事务尚未提交,其它事务或操作无法看到这些变更,这会导致数据访问上的延时。

降级为同步执行的性能问题:当异步任务过多导致线程池饱和后降级为同步执行,会严重影响系统的处理能力和响应时间,这在高并发场景下尤为致命。

优化建议
优化线程池和任务分配:

增加线程池容量:根据系统的可承载能力,适当增加线程池的大小或调整队列长度。
动态调节策略:实施动态的线程池管理策略,根据当前系统负载动态调整线程池参数。
任务切分:尽量减少单个批次处理的数据量,分更小的任务单元来处理,可以减轻单个事务的压力。
改进事务管理:

分布式事务或局部提交:对于数据量大的操作,考虑使用分布式事务管理,或者在每个子任务完成后即时提交事务,避免使用一个庞大的事务包裹太多操作。
优化数据处理逻辑:如果可能,重新设计数据处理逻辑,确保数据操作的效率最大化,减少事务的范围和持续时间。
使用更合适的异步模型:

消息队列:考虑使用消息队列来处理任务调度和执行,这样可以有效地解耦任务的产生和消费,改善系统的伸缩性和响应性。
限流和降级策略:设计合理的限流机制和更智能的降级策略,避免在系统压力大时还过多地启动同步任务,影响系统整体性能。
增强监控和告警:

实现实时监控:监控线程池的使用情况、事务的执行时间和数据库性能指标。
及时告警:当系统达到某些预设的阈值时,及时通过告警通知相关人员,以便快速响应可能出现的问题。
通过实施这些优化措施,可以提高系统的稳定性和性能,避免因为事务过大和同步执行导致的问题。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

让我们敬畏生产~保持一颗求真的心,by 2024年立秋绝日前~