这个是本系列的第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页面优化
好处
-
开发与维护需要服务端+APP+H5同时开发,对于项目管理复杂
-
转成H5可以减少APP的开发压力
问题现象
- 慢查询16K/天
- 线上MySQL CPU有激增现象,不过缓存命中率,内存利用率无明显变化
排查方式
结论先行,以下是该列表的优化流程
- 直接使用购买MySQL实例的腾讯云上面的智能优化
可以优先查看AI的优化建议进行快速修复的凭证
- 查看慢sql的统计情况,发现慢sql和CPU趋势较为相同
这说明如果优化了慢查询,则MysqlCPU较高问题也可以解决
- 导出慢查询日志,进行sql统计分析,发现其中99%以上是开发的告警信息列表查询语句
这表明优化单一告警即可优化Mysql的慢查询
- 在线上环境使用explain对查询语句进行查看,发现以下现象:
partition占用较多——打算减少partition
type为range,不是ref、eq_ref、const、system等——怀疑索引效果差,需要优化索引
key有值——有索引
rows大,且filtered较小,只有2%——扫描200条数据需要进而扫描大量条数数据,不合理,需修改查询条件
extra——有Using filesort,排序未触发索引,需优化索引
- 随机查看其他用户,发现告警量大的用户稳定出现慢查询,告警总量大约是20W-50W,告警量少的用户,即使是跨分区也不会出现慢查询
解决方式
3.1、自己可以修改的
- 改变查询条件顺序,减少查询条件
expire_time >now()——删除,因为每天会将超过过期时间的数据删掉
alarm_time between and——需要放在最后,因为联合索引在>,<,between and后会失效
设备id ——放到稍微靠前的位置,因为该字段在线上验证时,发现该字段独立度更高,如id 是114514时占总数据的1-5%,而告警类型2000可以占10%左右,所以设备id需要放在比告警类型更靠前的位置
- 优化联合索引顺序,个数
app的最常见查询条件作为联合索引的个数与顺序
通过腾讯云迁移数据到测试环境数据库验证解决
迁移单个表,单表200w数据,去其中的告警量50w单个用户进行压力测试
-
尝试增加资源——MySQL实例已经是购买的最贵的实例,无法优化
-
paritition删除——删除会导致线上长时间停顿20min以上,且涉及到删除过期数据逻辑,无法优化
3.2、需要配合的
产品经理
- 重构时默认查询7天,涉及多个partition,可不可以改成默认查询1天——为了在功能上对标海康,大华,不能进行修改
app
- 缺少偏移量,期望入参增加偏移量,避免后续出现的深分页问题——app暂时没人力投入,不进行修改
问题回溯
-
新问题单开发同事开发时直接在原有查询中间添加查询条件
-
以下为测试环境压力测试时CPU,内存图片,无问题
推测可能是因为测试环境压测数据量不够导致问题
为什么没有准备合适数据,原因为慢查询多为数据量较少用户
优化效果
- 慢查询explain优化
filtered查询行数降低,筛选率变高
extra没有using filesort
type虽然还是range,但是实际上速度已经可以来到200ms左右,顾先不优化,因为本次目的是减少慢查询降低MySQL压力
- 每日慢查询数量降低,从16k/天 -> 500/天
后续优化
-
APP侧辅助修改提问题单
-
后续排查发现告警有子模块呼叫查询,也会使用tbl_alarm表,为了减少单表压力,提单将对应查询优化到专门存储呼叫的表中进行查询
推荐阅读
2、打洞微服务CPU升高
背景
告警有主动P2P打洞的业务,添加该功能后,对应主要用于打洞的微服务有CPU升高问题
根因分析
- CPU高主要是pid为1的java进程占用的,也就是p2p-relay的服务
因为是CPU高,所以只需要查看下CPU高的愿意,如果是内存高则需要用另一种方式解决
- 使用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:进程名称。
- jstack 1查看线程8/9/10/11对应着四个ParalLelGC并行垃圾回收器(CPU 4核会存在4个垃圾回收器线程);
垃圾回收器线程为什么会CPU高,说明有大量的对象在被创建/没有引用/被回收持续往复
- 使用arthas的dashboard命令查看,young gc出现了289W次,持续了8小时(进程启动了25小时),再次确认有大量的对象在被创建
- 使用jstat -gc 1000 | awk ‘{print $6}’ 观察 Eden 分配速率,发现每隔几秒采集就有大量Eden对象创建(单位是kb);也就是说时时刻刻有2.27G的对象产生
大量对象产生说明业务中存在很大的并发的业务;结合p2p-relay流程,怀疑是接口/pr/device/p2p/invoke接口调用的频发;
但是TOMCAT的http-nio线程并不多,说明请求量并没有很大
-
怀疑是日志导致的GC较高,Java侧代码方便直接识别日志,C代码侧比较麻烦,是通过JNA进行Java的对象进行打印的。
-
业务如果回调频繁,岂不是要创建大量的String对象(JNA 将原生代码(如 C/C++的 char*)传递的字符串转换为 Java 的 String);为了确认日志回调的量,将打洞组件的日志级别开到最细(什么都会打印),在日志采集服务中发现P2P产生的日志是其他所有服务加起来的10倍+
那问题基本确认就是这个造成的,将设置回调的函数注释掉,并重新部署
解决方案
-
直接与P2P组件团队沟通,解决日志问题。
-
同步我们这一侧的开发规范给P2P组件团队,方便进行后续对接。
切打洞组件后,CPU正常了,闭环