Skip to content

扫描任务导致慢SQL堆积 #2790

@iwanghc

Description

@iwanghc

版本信息(Version)

SQLE: main cb0747e

问题描述(Describe)

扫描任务启用后mysql processlist中发现出现了线程堆积,并发连接大量select count(1)的sql,并且出现mysql cpu使用率过高问题。

截图或日志(Log)

image
image

如何复现(To Reproduce)

  1. 在某个表写入大量数据(5000万以上记录数的表比较容易复现)
  2. 在该数据源的审核模板上开启“查询数据量超过阈值,筛选条件必须带上主键或者索引”和规则“UPDATE/DELETE操作影响行数不建议超过阈值”规则
  3. 创建processlist扫描任务,,设置采集周期为1秒
  4. 在快捷审核中审核select * from xxx触发以上规则(为了让select count(1) sql语句出现在processlist中)
  5. 查看processlist是不是出现了线程堆积和mysql server cpu使用情况

问题原因

扫描任务并发审核时下发的慢sql堆积导致CPU负载过高
某些审核规则会下发select count(1)sql语句,当该语句统计的表记录数过多时,会导致sql执行变慢,而processlist或慢日志扫描任务会采集到这些慢sql,扫描任务的审核是多线程执行的,当采集到select count(1)时,又触发了下发该语句的规则,周而复始,造成连接到数据库的线程堆积,引起cpu高负载。

解决方案

问题的根本原因在于并发审核,解决思路有两种,一种改为单线程审核,另一种是审核时过滤数据。

方案一:

在AggregateSQL时过滤掉管控表中已经审核过的sql
优点:减小了审核的压力
缺点:审核结果无法自动更新,只能通过页面上一键审核按钮更新审核结果

方案二:

将审核sql这个动作改为单线程
image
优点:成本小
缺点:采集数据量较大审核较慢时,会按一批一批显示在页面上(每次1000条),体验不好。

方案三:

创建全局map,记录审核中的sql,在审核完后从map中delete,并在审核时过滤已经触发审核但没审核完的sql 。
优点:影响面小,并且保证了采集数据的完整
缺点:使扫描任务审核逻辑变得复杂

最终方案:

方案三,新增一个map存放审核中的sql,没有数据库操作不会加重扫描任务审核负担,且实现相对较容易,仅需要注意保证map的线程安全。
单独启用一个job用来聚合queue更新record表,改为从record中读取数据进行单线程审核。

  1. 在sql_manage_record_processes表中新增最后审核时间字段
  2. 新增一个更新record表的job,从队列表中取数据聚合后更新到record表,并把审核结果置空,界面显示审核中。
  3. 在审核job中,从record表更新时间 > 最后审核时间+?min(刚审完几分钟的就不审了) 或 最后审核时间为空的数据取出来进行审核,并将审核改为单线程,审核时不同实例多线程执行。
  4. 来源是快捷审核的数据也要同步更新或插入审核时间字段

变更影响面

影响版本

3.2409-3.2411

受影响的模块或功能

扫描任务采集sql处理的聚合保存模块、审核模块

外部引用的潜在问题或风险

版本兼容性

sql_manage_record_processes表新增了last_audit_time字段,记录最后的审核时间,需要根据存量管控数据的updated_time更新last_audit_time。

测试建议

参考问题原因如何复现部分测试,注意服务器cpu使用率

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions