前言

随着业务的不断拓展和系统架构的日益复杂化,确保系统的持续稳定性和高可用性成为了工作的重中之重。定期进行系统健康检查和性能监控,以便及时发现并诊断潜在的系统隐患,是防范风险、保障业务连续性的关键措施。通过检查系统相关指标(JVM、堆内存、线程情况、CPU负载、网络状况、接口耗时、SQL耗时等),我们可以更有效地进行问题排查和风险预警,从而避免因系统故障导致的业务中断和资损发生。

背景

在支付业务场景中,系统需承受极高的每秒查询率(QPS),任何系统波动都可能引发成百上千笔交易流程的异常。在一次针对接口响应时间的深入排查中,我们注意到接口的99th百分位响应时间(99线)显著超出正常范围。经过细致的分析和调优,我们成功识别并优化了导致接口响应延时的关键因素,有效提升了系统的吞吐量和稳定性,确保了支付业务的顺畅进行。

问题的发现与解决

通过接口链路监控排查,发现系统偶尔存在查询数据耗时较高的情况,正常情况下访问数据库耗时20ms左右,但是会偶尔出现700ms以上的耗时。

但是从慢sql日志中并不存在该条查询语句,排查耗时采集的时间范围,确认监控指标中耗时是从服务Mysql驱动com.mysql.cj.jdbc.StatementImpl方法 到 MYSQL服务响应之间的耗时;一种可能是网络抖动会出现偶尔耗时,另一种可能是mysql负载过高导致。

通过网络抓包分析异常链路中服务到MYSQL服务器中间的耗时,从MYSQL服务器请求接收的ACK到MYSQL服务器给到查询结果之间耗时一共是600ms,目前就可以定位是MYSQL服务负载问题。

进一步分析什么原因导致MYSQL服务器负载过高?还有为什么没有该请求记录慢sql?

通过查看慢sql记录,排查出慢sql语句

SELECT   COUNT(1) FROM  tb_order WHERE 1 = 1   AND orrder_status IN (?, ?)   AND updatetime BETWEEN DATE_FORMAT(?, '%Y-%m-%d %H:%i:%s')   AND DATE_FORMAT(?, '%Y-%m-%d %H:%i:%s')   AND order_channel IN (?)   AND order_pay_type NOT IN (?) ;

上述sql优化器选择执行idx_status索引执行查询,扫描行数9w行 查询效率并不高,而且存在日期格式化函数,通过添加子查询来优化查询,使查询命中两个索引。

优化后sql:

SELECT   COUNT(1) FROM  tb_order WHERE 1 = 1   AND orrder_status IN (?, ?)   AND order_channel IN (?)   AND order_pay_type NOT IN (?)   AND id >     (SELECT id     FROM      tb_order     WHERE updatetime > ?     ORDER BY updatetime asc LIMIT 1    )

在优化慢sql过程中发现该sql是JOB站点跑批执行,进而推测该问题是由多个job同时触发,在同一时间大量执行查询和更新语句,且99线呈毛刺状,与JOB触发时间吻合,怀疑是因为JOB导致短时间内MYSQL服务器出现高负载的情况。

调整JOB执行时间,错峰执行、慢sql优化。

优化后mysql服务器负载降低

疑问分析

问题已经解决,为什么请求mysql慢,并没有记录慢sql日志?

MYSQL服务器处理查询请求时,大致处理流程可以分为三个部分:连接管理、解析与优化、存储引擎。

开启慢SQL日志(Slow Query Log)时,MySQL主要统计的是查询执行阶段的耗时,即从开始执行SQL语句(包括查询优化和执行计划的应用)直到返回结果给客户端的这一整个过程的耗时。具体来说,统计的时间包括:

·       优化器阶段:生成执行计划的时间。虽然这个过程一般相对较快,但对于特别复杂的查询,优化也可能是耗时的一部分。

·       执行阶段:按照优化器选择的执行计划,对SQL语句进行实际的数据读取、处理和结果生成的过程。这包括访问存储引擎获取数据、执行必要的排序、聚合等操作。

说明在优化器阶段和SQL执行阶段并不是影响查询的问题点,所以在慢Mysql日志中看不到耗时链路较长的sql

慢SQL会引起MySQL服务器处理连接和线程效率变慢。这主要是因为MySQL为每个客户端连接分配一个单独的线程来处理请求。因此,当出现慢SQL时,它会影响到分配给该连接的线程,进而可能影响到服务器整体的处理效率。以下是详细的分析:

线程占用

·       长时间占用线程:每个慢SQL查询都会占用一个处理线程直到查询完成。如果查询运行时间过长,该线程会被长时间占用,无法处理其他请求。

·       线程池耗尽:在高并发的情况下,如果大量的慢SQL查询占用了大部分线程,新的连接请求就可能无法及时分配线程进行处理,由于线程资源有限,导致新的请求必须等待,这直接降低了服务器的响应速度和处理效率。

资源竞争

·        

CPU和I/O资源:慢SQL往往伴随着高CPU利用率或高I/O等待,这会导致处理其他SQL请求的线程必须竞争有限的CPU时间和I/O资源。在资源竞争激烈的情况下,即使是轻量级的查询也可能会受到影响,响应时间增加。

·        

·        

内存使用:复杂的查询可能会消耗大量内存资源(例如,为了排序和聚合操作创建大型临时表),这会影响到MySQL的整体性能,包括处理其他查询的效率。

·        

连接管理

·       连接堆积:由于处理线程被慢SQL长时间占用,新的客户端连接请求可能会在连接队列中堆积,等待空闲线程。这会进一步增加客户端的等待时间,并可能触发超时错误。

·       请求超时和失败:在极端情况下,如果服务器因为慢SQL过多而过载,客户端请求可能会因为超时而失败,这对用户体验和应用可用性产生负面影响。

锁竞争

·       锁等待和死锁:慢SQL查询可能涉及到复杂的表锁或行锁操作,这可以导致其他查询在等待锁释放时被阻塞,增加了其他操作的延迟。在某些情形下,还可能导致死锁,进一步降低数据库处理速度。

在MySQL服务器遭遇高负载的场景下,慢SQL查询的负面影响会被放大,此时数据库线程的占用时间显著延长,资源竞争现象加剧,进而引发锁等待和线程阻塞,这些情况会连锁反应式地影响到其他并发查询的执行效率。最终,这种资源争夺和延迟累积效应将导致整个数据库接口的平均响应时间和99线指标急剧上升。

总结

确保系统稳定性是开发的关键目标之一,通过定期对系统进行全面监控和性能指标分析,能够有效识别出潜在的系统性风险。通过对一次简单的调整,就可能显著提升系统的整体性能和响应能力。