2025.11–2026实习相关整理2
问题排查和避坑文档整理
案例:DAO服务全表查询导致服务频繁重启
问题现象
DAO(数据访问对象)服务间隔一段时间就重启,但日志中没有明显的OOM(内存溢出)错误。排查发现,当有查询执行对十几万乃至上百万数据表的全表扫描时,服务就会重启。
根因分析
- 接口设计缺乏安全护栏:DAO服务提供了全量查询接口且没有分页或数据量限制。这是一个非常危险的设计。当表数据量较小时可能没问题,一旦数据量增长到一定程度,必然成为性能炸弹。
- 资源管理不当:大查询会耗尽数据库连接、网络带宽和服务本身的内存/CPU资源,导致服务不可用进而重启。代码层面对这种“慢查询”或“大查询”没有超时中断或资源保护机制。
- 问题排查困难:由于服务重启瞬间的日志丢失,以及最初没有配置正确的进程管理器来上报重启日志,导致问题定位耗时较长。
解决措施
- 紧急措施:在DAO服务中拦截并禁用这两个危险的全量查询SQL。
- 长远解决:重构接口,强制进行分页查询,并增加查询超时设置。
经验教训与启示
- 启示一(接口设计):在设计数据查询接口时,必须将“分页”作为首要考虑因素。对于后台需要全量数据的场景,也应通过流式处理或分批查询来实现,避免一次性加载所有数据。
- 启示二(资源边界):任何服务都必须清楚自己的资源边界(CPU、内存、数据库连接等),并对可能突破边界的操作进行限制和防护。
- 启示三(可观测性):完善的日志、监控和告警是快速定位问题的生命线。服务异常重启的告警应该第一时间触发。
最佳实践
MySQL 最佳实践
- 需要定时 全表扫描 更新索引,分批排队请求,控制并发,添加间隔拉取(每次最多不超过 1000 条),不能全表一次拉取。
- 统一搜索中,需要盘点所有的可用数据资产,包括 dao 中已有数据,按搜索类别构建索引:要应用 高性能分页查询,并且在 dao 层面直接限制最大 limit。
消息队列最佳实践
- 消息幂等性(最核心)- 必须在业务层实现幂等。不要依赖消息引擎不投递重复消息,应使用业务唯一键(如MessageID)配合数据库唯一索引进行防重执行。
- 消费端最佳实践 - 消费端位移管理: 必须对消费确认。
DNS解析阻塞文件IO
问题的现象
变更告警服务要接收告警信息进行分析处理,后端服务新启动了两个订阅者,消费「现象告警」、「调用关系、全景监控、idkey、单机」维度的告警。http服务在启动的之前会先启动事件中心的订阅者等待接受tdmq的消息,当前服务启动订阅者的数量为4个。
排查思路
服务启动之后,测试调用服务接口,出现一直没有返回,直置等待超时的情况。加日志排查发现,是卡在调用下游服务时,下游服务一直没有返回。
尝试注释了订阅者的代码后服务正常。因此怀疑是订阅者逻辑可能有问题存在资源竞争卡死的情况,但排查后,只要注释掉任意一个订阅者服务都正常,订阅者的逻辑没什么问题。
再一次排查后发现,请求下游服务,只有遇到带域名的http请求会出现阻塞的情况,但是通过ip端口访问方式的请求,都能够被正常处理。抓包看通过域名的请求,没有真正发出请求包,看着像是卡在了dns解析。
查找资料发现dns解析会阻塞文件io,nodejs证据,底层执行dns解析,是阻塞式执行,libvu.so执行的阻塞式的任务(包括dns解析),是通过线程池的方式执行,线程池的线程数量默认是4个,与订阅者的数量匹配,因此,初步怀疑是tdmq的某些请求占满了线程池,导致dns无法获取到执行的线程导致阻塞。尝试改大了线程池的数量之后,服务处理请求正常。
总是隔一天就会收到测试执行超时和上传执行日志的告警;上传日志失败的原因是,没有对应的日志文件
执行测试用例的时候,会fork一个子进程来执行日志,子进程的最长保持时间是550s,超时会杀掉进程。同时最后会上传日志。
从问题现象和日志看,是fork出了一个子进程,然后代码并没有真正的执行,就这么等了550s,从而没有日志文件
深入分析代码后发现,如果worker存在某种没有兜住的异常,则会退出进程,此时并没有join对应的子进程,可能导致子进程的文件描述符不会按照预期回收,在这种场景下,持续时间足够长后,则可能导致机器文件描述符太多,从而fork出子进程的时候,出现异常,测试用例没有正在执行,join也不会按预期回收子进程
fork子进程后,缺少做存活检查,从而导致子进程可能不会回收,导致fd爆炸的问题。这里需要对执行测试用例的进程做好存活检查
突增流量,导致容量不足出现不可用
猜测这个时间可能是国庆购票问题,因此回溯2024年,发现24年这个时间是有突增的。
处理方式: 构建容量预警预警模块突增流量以及缓慢上涨流量

