[TOC] #### 前言 --- 你有没有遇到过这种事 ? 系统刚上线那段时间,点哪儿都快,自己都要忍不住夸一句 「这系统真丝滑」。 结果过了几个月,用户量一上来,页面开始转圈圈。再过一阵子,用户开始骂人了:「你们这破系统怎么这么卡?」 如果你遇到过,别慌,几乎每个后端开发者都经历过,今天我们就来聊聊:系统到底是怎么一步步变慢的 #### 一个真实的场景 --- 假设你做了一个电商系统,用户下单的代码大概是这样的 ```php // 用户下单 public function createOrder($userId, $goodsId) { // 1. 扣库存(MySQL) $this->reduceStock($goodsId); // 2. 创建订单(MySQL) $order = $this->insertOrder($userId, $goodsId); // 3. 发送短信通知(调用第三方接口) $this->sendSms($userId, $order->id); // 4. 发送邮件通知(调用第三方接口) $this->sendEmail($userId, $order->id); // 5. 通知物流系统(调用内部接口) $this->notifyLogistics($order->id); return $order; } ``` 看起来逻辑很清晰,对吧 ?我们来算一下每个步骤的耗时: | 步骤 | 耗时 | | ------------ | ------------ | | 扣库存 | 20ms | | 创建订单 | 30ms | | 发送短信 | 500ms | | 发送邮件 | 300ms | | 通知物流 | 200ms | | 统计 | 1050ms | 用户点击 “下单” 按钮,要等 1秒多才能看到下单成功,平时一天几百个订单,1秒的响应时间,用户基本无感。 + 因为并发低,服务器扛得住,第三方短信接口也不会超时 你会觉得:系统跑的挺好啊,有啥问题 ? #### 平时没问题,一搞活动就崩 --- 某天你上了一场限时秒杀活动,商品挂到了首页推荐。 一瞬间,几千个用户同时点「下单」,每个请求都要走完这 5 步,每个请求都要 1秒多 更要命的是,发短信的那个第三方接口,平时响应 500ms,现在几千个人同时调它,它也开始扛不住了,响应时间飙到了3 秒 + 短信接口一慢,所有下单请求都被拖慢。也就是一个环节卡住,整条链路都跟着排队 用户看到的就是:页面一直转,下单按钮点了没反应。这就是「同步调用」埋下的坑。 #### 慢的根源在哪 --- 我们来复盘一下这 5 步: 扣库存、创建订单:这是核心业务,必须同步执行。用户下单了,你得先扣库存、再建订单,这个顺序不能乱 发短信、发邮件、通知物流:这三步,用户真的需要等它们完成吗 ? 想想自己网购的经历,下单之后你最关心什么 ?「订单创建成功了吗?扣款了吗?」 你关心短信什么时候收到吗?不关心。你关心邮件什么时候发出来吗?也不关心 + 这些东西晚几秒,甚至晚几分钟到,你根本感知不到。但现在的代码,让请求傻等着这些事情全部做完,才返回结果 #### 改为异步会怎样 --- 如果我们把下单流程改成这样: ```php public function createOrder($userId, $goodsId) { // 1. 扣库存(必须同步) $this->reduceStock($goodsId); // 2. 创建订单(必须同步) $order = $this->insertOrder($userId, $goodsId); // 3. 把后续任务丢到队列里(异步) $this->dispatch(newSendSmsTask($userId, $order->id)); $this->dispatch(newSendEmailTask($userId, $order->id)); $this->dispatch(newNotifyLogisticsTask($order->id)); return $order; } ``` 耗时变成了: | 步骤 | 耗时 | | ------------ | ------------ | | 扣库存 | 20ms | | 创建订单 | 30ms | | 丢任务到队列 | 5ms | | 总计 | 55ms | 我们发现耗时从 1050ms 降到了 55ms 但这里要强调一点:发短信、发邮件、通知物流这些活儿,一个都没少 它们只是从「用户盯着等」变成了「后台悄悄做」,用户等的时间少了,但该干的事情系统一样没落下 #### 这个队列是什么 --- 就是我们接下来要讲的:消息队列。 你可以把它理解成一个「任务暂存区」:主程序把任务丢进去,立刻返回,继续处理下一个用户请求 后台有专门的进程,从队列里取任务,一个一个慢慢处理 #### 不只是快,还有更多好处 --- 今天讲的是异步,但消息队列能做的事情远不止这些。 比如: 解耦:订单系统不用关心谁要发短信、谁要通知物流。它只管把消息丢出去,谁需要谁来取。以后加一个「积分系统」,订单代码一行都不用改。 削峰填谷:秒杀那一瞬间,几万个请求涌进来。与其直接打到数据库让它崩掉,不如先堆在队列里,慢慢消化。数据不会挂,用户也不会看到报错。 提高稳定性:短信接口挂了?没关系,消息在队列里存着,等它恢复了再继续发。不会因为一个下游服务挂了,整个系统跟着瘫痪 这些内容,后面的章节会一个一个展开讲。 今天只需要记住一件事:消息队列能让你的系统更快、更稳、更好维护 #### 小结 --- 系统变慢,往往不是代码写的差,而是「不该同步的事情,同步做了」 + 核心业务必须同步(扣库存、创建订单) + 非核心业务可以异步(发短信、发邮件、通知物流) 而实现异步的关键工具,就是:消息队列 但问题来了: 如果短信服务超时了怎么办,用户下单还能成功吗? 如果物流系统挂了,会不会影响整个下单流程 ? 订单系统和短信系统绑的太紧,一个出问题,另一个也跟着遭殃 这就是「同步调用」更深层的问题。下一讲,我们来好好聊聊:同步调用到底有哪些坑。