任务队列声称缓冲一千,压测时上游发了两万条,日志里统计的处理数只有一万三,中间那七千条既没有报错也没有重试记录,监控上队列长度还一直是满的。乍看像缓存或者权限的锅,追下去往往不是。
grep -n 'default:' queue.go grep -c 'select' queue.go go test -run TestQueue -count=1 ./...
追下去是这么回事:select 里写了 default,channel 一满就走进 default 被静默跳过,缓冲只是把触发时间往后推,生产速度长期高于消费速度时丢数据是必然的,加容量只能延缓不能解决。
「channel 满丢任务」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。
线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
具体做法是,先统计入队数和出队数的差值确认丢了多少条;把默认分支换成阻塞写入或者落到本地重试;给队列长度和丢弃计数补上监控和告警阈值。
验收就看一点,压测后入队数等于处理数加剩余队列长度,丢弃计数始终为零。
