【实践】2025年线上问题解决与总结-2

61 阅读8分钟

这个是本系列的第2个文章,主要用于记录一下告警业务的几个比较典型的线上问题,以此警戒

往期文章见【实践】2025年线上问题解决与总结-1

(告警业务就是安防行业会给消费者提供监控设备,监控设备会进行监控,监控过程中可能会通过算法获取到信息,比如行人通过,火花等,通过图像识别的方式将该画面/视频记录下来上报到我们这边的安防平台,或者是将视频发送到安防平台,再通过平台的AI识别进行告警判断,最终触发告警通知与存储,方便APP用户/第三方对接者等操作方获取告警以及对应的告警信息)

大概流程如下


graph LR

A[设备上报告警] --> B[告警网关]

B --> C[Kafka发送]

C --> D[消费告警数据]

D --> E{设备类型判断}

E -->|特定设备告警| F[P2P打洞连接]

F --> G[查询设备状态]

G --> H[数据处理]

E -->|其他设备告警| H

H --> I[数据存储]

I --> J[平台展示]

J --> K[通知相关人员]

1、告警慢查询解决

背景

告警页面由APP+ H5开发转纯H5页面优化

好处

  1. 开发与维护需要服务端+APP+H5同时开发,对于项目管理复杂

  2. 转成H5可以减少APP的开发压力

问题现象

  1. 慢查询16K/天

image.png

  1. 线上MySQL CPU有激增现象,不过缓存命中率,内存利用率无明显变化

image.png

image.png

排查方式

结论先行,以下是该列表的优化流程

image.png

  1. 直接使用购买MySQL实例的腾讯云上面的智能优化

可以优先查看AI的优化建议进行快速修复的凭证

image.png

  1. 查看慢sql的统计情况,发现慢sql和CPU趋势较为相同

这说明如果优化了慢查询,则MysqlCPU较高问题也可以解决

994a8ff4419f284e41339ad008f0d530

  1. 导出慢查询日志,进行sql统计分析,发现其中99%以上是开发的告警信息列表查询语句

这表明优化单一告警即可优化Mysql的慢查询

  1. 在线上环境使用explain对查询语句进行查看,发现以下现象:

partition占用较多——打算减少partition

type为range,不是ref、eq_ref、const、system等——怀疑索引效果差,需要优化索引

key有值——有索引

rows大,且filtered较小,只有2%——扫描200条数据需要进而扫描大量条数数据,不合理,需修改查询条件

extra——有Using filesort,排序未触发索引,需优化索引

4873f5fb0e88d3f8c86bf327d2fd566e

  1. 随机查看其他用户,发现告警量大的用户稳定出现慢查询,告警总量大约是20W-50W,告警量少的用户,即使是跨分区也不会出现慢查询

解决方式

3.1、自己可以修改的

  1. 改变查询条件顺序,减少查询条件

expire_time >now()——删除,因为每天会将超过过期时间的数据删掉

alarm_time between and——需要放在最后,因为联合索引在>,<,between and后会失效

设备id ——放到稍微靠前的位置,因为该字段在线上验证时,发现该字段独立度更高,如id 是114514时占总数据的1-5%,而告警类型2000可以占10%左右,所以设备id需要放在比告警类型更靠前的位置

  1. 优化联合索引顺序,个数

app的最常见查询条件作为联合索引的个数与顺序

通过腾讯云迁移数据到测试环境数据库验证解决

迁移单个表,单表200w数据,去其中的告警量50w单个用户进行压力测试

  1. 尝试增加资源——MySQL实例已经是购买的最贵的实例,无法优化

  2. paritition删除——删除会导致线上长时间停顿20min以上,且涉及到删除过期数据逻辑,无法优化

3.2、需要配合的

产品经理

  1. 重构时默认查询7天,涉及多个partition,可不可以改成默认查询1天——为了在功能上对标海康,大华,不能进行修改

app

  1. 缺少偏移量,期望入参增加偏移量,避免后续出现的深分页问题——app暂时没人力投入,不进行修改

问题回溯

  1. 新问题单开发同事开发时直接在原有查询中间添加查询条件

  2. 以下为测试环境压力测试时CPU,内存图片,无问题

推测可能是因为测试环境压测数据量不够导致问题

为什么没有准备合适数据,原因为慢查询多为数据量较少用户

image.png

image.png

优化效果

  1. 慢查询explain优化

filtered查询行数降低,筛选率变高

extra没有using filesort

type虽然还是range,但是实际上速度已经可以来到200ms左右,顾先不优化,因为本次目的是减少慢查询降低MySQL压力

image-20250706185239859

  1. 每日慢查询数量降低,从16k/天 -> 500/天

image.png

后续优化

  1. APP侧辅助修改提问题单

  2. 后续排查发现告警有子模块呼叫查询,也会使用tbl_alarm表,为了减少单表压力,提单将对应查询优化到专门存储呼叫的表中进行查询

推荐阅读

  1. Mysql Documentation

  2. MySQL documentation explain

2、打洞微服务CPU升高

背景

告警有主动P2P打洞的业务,添加该功能后,对应主要用于打洞的微服务有CPU升高问题

image.png

根因分析

  1. CPU高主要是pid为1的java进程占用的,也就是p2p-relay的服务

因为是CPU高,所以只需要查看下CPU高的愿意,如果是内存高则需要用另一种方式解决

  1. 使用top -H,查看线程号为8/9/10/11的线程CPU使用率的特别高
  • PID:进程ID。它是标识进程的唯一正整数。我们可以通过 kill 命令 带上 PID 来杀掉进程。

  • USER:启动该进程的“有效”用户名。Linux为进程分配一个真实的用户ID和一个有效的用户ID。后者允许进程代表另一个用户执行操作。(例如,非root用户可以提升为root用户才能安装软件包。) 扩展阅读:

  • NI:NI 字段显示进程的 nice 值,负值表示高优先级,正值表示低优先级。

  • PR:PR 字段从内核的角度显示了进程的调度优先级。nice 值会影响进程的优先级。

  • VIRT:进程消耗的内存总量。这包括程序的代码、进程存储在内存中的数据以及 Swap 的任何内存区域,即包含(RAM 和 Swap)

  • RES:是该进程在 RAM 中消耗的内存(不包含 Swap)

  • SHR:是与其他进程共享的内存量。

  • %MEM:进程消耗 RAM 内存总量的百分比。

  • S:进程状态。和前面叙述的一样,进程可能处于各种状态。此字段以单字母形式显示过程状态。

  • TIME+:自进程启动以来所使用的 CPU 总时间,精确到 1/100 秒。

  • COMMAND:进程名称。

img

  1. jstack 1查看线程8/9/10/11对应着四个ParalLelGC并行垃圾回收器(CPU 4核会存在4个垃圾回收器线程);

垃圾回收器线程为什么会CPU高,说明有大量的对象在被创建/没有引用/被回收持续往复

img

  1. 使用arthas的dashboard命令查看,young gc出现了289W次,持续了8小时(进程启动了25小时),再次确认有大量的对象在被创建

img

  1. 使用jstat -gc 1000 | awk ‘{print $6}’ 观察 Eden 分配速率,发现每隔几秒采集就有大量Eden对象创建(单位是kb);也就是说时时刻刻有2.27G的对象产生

大量对象产生说明业务中存在很大的并发的业务;结合p2p-relay流程,怀疑是接口/pr/device/p2p/invoke接口调用的频发;

但是TOMCAT的http-nio线程并不多,说明请求量并没有很大

image.png

  1. 怀疑是日志导致的GC较高,Java侧代码方便直接识别日志,C代码侧比较麻烦,是通过JNA进行Java的对象进行打印的。

  2. 业务如果回调频繁,岂不是要创建大量的String对象(JNA 将原生代码(如 C/C++的 char*)传递的字符串转换为 Java 的 String);为了确认日志回调的量,将打洞组件的日志级别开到最细(什么都会打印),在日志采集服务中发现P2P产生的日志是其他所有服务加起来的10倍+ image.png

那问题基本确认就是这个造成的,将设置回调的函数注释掉,并重新部署

解决方案

  1. 直接与P2P组件团队沟通,解决日志问题。

  2. 同步我们这一侧的开发规范给P2P组件团队,方便进行后续对接。

切打洞组件后,CPU正常了,闭环

image.png