SELECT id, payload FROM offline_msg WHERE user_id = ? AND create_time > NOW() - INTERVAL 7 DAY ORDER BY id ASC LIMIT 200;
一个用户三个月没上线,重连时把 90 万条离线消息一次性查出来,接口跑了 30 秒,客户端 5 秒就超时断开,重复三次后连接被限流。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。
追下去是这么回事:离线消息没有过期策略也没有条数上限,每次上线全量下发。查询没走覆盖索引,90 万行还要回表,内存瞬间涨到 1GB 以上。
「离线消息堆积」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
把复现步骤压到三条以内,交给同事也能跑出来,才算真的定位清楚。改动写完就同步给同事,下一个人踩同一个坑,成本还是你的。
处理上按这个顺序:重连只拉最近 7 天 更早的直接归档;每次最多返回 200 条 用游标继续拉;离线消息加 TTL 超过 30 天自动清理;按 user_id 和 create_time 建联合索引。
确认没问题再收工,重连首包 300 毫秒内返回 条数封顶 200 翻页能拉完 没有再超时。
