上周跟一个做电商的后端工程师蹲在楼梯间抽烟,他说刚上线的大促链路差点被消息队列搞崩。
最先被吹爆的削峰故事最容易翻车
很多人第一次接触消息队列,听来的第一个故事永远是削峰。说白了,就是把瞬时打过来的海量请求攒在队列里,后面的消费者按自身的处理速度慢慢捞,不用怕流量直接把后端服务冲垮。
听着特别爽。真落地全是坑。
那个工程师踩的坑我印象很深。大促零点的时候,用户付完款的通知消息全往Kafka里塞,本来做了容量评估,说集群能扛每秒10万条写入,结果消费端的服务没调好参数,每秒只能稳定处理200条。三个小时过去,队列里的消息堆了快30万条,用户付完款等半小时才收到发货提醒,客服后台的投诉直接刷了屏。

很多人只看到削峰的爽感,没算过背后的隐性账。当你把原本的同步调用改成异步投递,所有原本同步链路里的即时反馈全得自己补逻辑。原来调支付接口,成功了直接弹提示给用户,现在发个消息到队列就返回成功了,万一消息丢了呢?万一消费到一半服务挂了呢?你得做重试机制,做死信队列,做离线对账任务,这些额外写的代码量,往往比当初省下来的同步调用逻辑多三倍。
解耦的前提是你得先把边界划清楚
团队愿意花成本搭消息队列,第二个常见的理由是解耦。说两个系统别直接绑着接口调用,改个字段就得两边一起发版,牵一发动全身。听着完全没毛病。
实际跑起来才知道,这种“隔了一层的耦合”,出问题的时候更闹心。
之前跟着排查过一个线上事故:用户中心改了用户标签的字段类型,发消息的时候没同步通知下游,原来消费这个消息的营销系统,因为字段类型不匹配,直接把消费逻辑跑崩了,消息堆了整整两个小时,当天的会员日推送晚了大半天才发出去。我当时蹲在会议室喝了三杯冰美式,最后发现就是个字段少了默认值。换作以前用同步接口调用,一上线接口直接报500,测试环境就能测出来问题,现在倒好,隔了三层服务,出问题都得顺着链路一层一层找源头。

说白了,消息队列的解耦从来不是免费的,你得为跨系统的消息约定付上长期维护的成本。你得有统一的消息schema管理,得有下游的消费告警,得有跨团队的变更同步机制,这些事没有一样是能省的。
到底什么时候真的该用消息队列

别听网上的架构教程说什么微服务体系就必须配消息队列,纯扯淡。
比如你就一个几十人的小团队,做个内部用的OA系统,总不能为了所谓的解耦,专门搭一套三节点的消息队列集群,还要写运维脚本,还要处理消息丢失、重复消费的问题,这不是纯纯给自己找事吗?
我见过太多团队,技术选型的时候追时髦,什么组件火就上什么,最后系统没快多少,维护成本翻了两三倍。其实判断要不要上消息队列的标准特别简单:如果某个操作,晚个几秒甚至几分钟处理,完全不影响用户的即时体验,也不会产生直接资损,你再考虑用。比如用户注册完了发个欢迎短信,晚十秒发根本没人在意;比如用户点完赞,把点赞数异步更新到数据库,晚个一秒两秒,用户也不会盯着屏幕等。
但如果是用户输完密码点登录,你总不能把登录校验的请求扔到队列里,等个几十秒再告诉用户登录成功吧?那用户早就把APP删了。
至于大家都头疼的消息重复消费问题,这事没那么玄。别想着费九牛二虎之力搞什么绝对精准的一次性投递,最后把整个链路的性能掉一半。不如在消费端做个简单的幂等逻辑:拿消息的唯一ID去数据库查一下,处理过了就直接跳过,没处理过就接着跑,逻辑简单,出问题也好排查。
上周再碰到那个蹲楼梯间抽烟的工程师,他说他们已经把大促链路里非核心的通知类消息全迁到了独立的队列集群,核心的支付回调还是走同步接口,堆消息的问题解决了,大促当天的相关投诉量降了七成。其实技术选型哪有什么银弹啊,你把每一笔账算清楚,知道用什么东西要付什么代价,比背多少架构师手册都管用。