从构建分布式秒杀系统聊聊WebSocket推送通知

前言

秒杀架构到后期,我们采用了消息队列的形式实现抢购逻辑,那么之前抛出过这样一个问题:消息队列异步处理完每个用户请求后,如何通知给相应用户秒杀成功?

场景映射

timg

首先,我们举一个生活中比较常见的例子:我们去银行办理业务,一般会选择相关业务打印一个排号纸,然后就可以坐在小板凳上玩着手机,等待被小喇叭报号。当小喇叭喊到你所持有的号码,就可以拿着排号纸去柜台办理自己的业务。

这里,假设当我们取排号纸的时候,银行根据时间段内的排队情况,比较人性化的提示用户:排队人数较多,您是否继续等待?否的话我们可以换个时间段再来办理。

由此我们把生活场景映射到真实的秒杀业务逻辑中来:

  • 我们可以把柜台比喻成商品下单处理逻辑单元
  • 拿到排号纸说明你进入相应商品处理队列
  • 拿到排号纸的请求直接返回前台,提示用户抢购进行中
  • 排号纸进入队列后,等待商品业务处理逻辑
  • 小喇叭叫到自己的排号相当于服务端通知用户秒杀成功,这时候可以进行支付逻辑
  • 那些拿不到票号的同学,相当于队列已满直接返回秒杀失败
  • https://yq.aliyun.com/articles/614326?utm_content=m_1000007223
在后台系统中配置消息推送路由,通常涉及两个核心部分:**后端路由逻辑的实现**以及**客户端与服务端之间的通信机制设计**。根据引用内容中的示例代码和技术方向[^1],可以提供以下配置方法和实现思路。 ### 三、消息推送路由配置方法 #### 3.1 基于 WebSocket 的实时消息路由 WebSocket 是实现消息实时推送的理想协议,适用于聊天室、单聊、群聊等场景。可以通过维护一个连接池(如 `clients` 映射)来管理所有客户端连接,并根据消息类型进行路由处理。 例如,后端可使用如下 Node.js 示例代码实现基础的消息路由功能: ```javascript wss.on('connection', (ws) => { // 将新连接加入客户端集合 const clientId = generateUniqueClientId(); // 生成唯一标识符 clients.set(clientId, ws); ws.on('message', (data) => { try { const msg = JSON.parse(data); // 单聊消息路由 if (msg.type === "chat" && clients.has(msg.targetId)) { const targetClient = clients.get(msg.targetId); targetClient.send(JSON.stringify(msg)); } // 群聊广播 if (msg.type === "group") { clients.forEach((client) => { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(msg)); } }); } } catch (e) { console.error("消息解析失败:", e); } }); // 连接关闭时移除 ws.on('close', () => { clients.delete(clientId); }); }); ``` 该实现通过判断 `msg.type` 来决定是单聊还是群聊消息,并将消息发送到对应的客户端连接上。 #### 3.2 消息路由的扩展性考虑 为提升系统的可扩展性和性能,建议采用以下优化策略: - **异步 I/O 模型**:使用 Java NIO 或 Netty 等技术提高并发处理能力。 - **分布式架构**:结合 Kafka、Redis Pub/Sub 实现跨服务的消息广播和订阅机制。 - **负载均衡**:通过 Nginx 或 HAProxy 分流请求,避免单点故障并提升吞吐量。 - **水平扩展**:部署多个 WebSocket 服务节点,配合 Redis 存储在线用户状态,实现多实例间的消息同步[^3][^4]。 #### 3.3 移动端推送集成 对于移动端应用,除了 WebSocket 实时连接外,还需集成平台级推送服务(如 FCM、APNs、极光推送等),以确保在 App 被杀死或网络断开时仍能接收通知。 Android 端可通过 HTTP 请求将设备令牌注册至后端服务器: ```java OkHttpClient client = new OkHttpClient(); String token = FirebaseInstanceId.getInstance().getToken(); RequestBody body = new FormBody.Builder() .add("token", token) .build(); Request request = new Request.Builder() .url("https://your-backend.com/api/register-token") .post(body) .build(); Response response = client.newCall(request).execute(); ``` 后端需保存该令牌并在推送时调用对应平台 API 发送消息[^2]。 #### 3.4 推送消息格式与响应处理 在某些企业级推送接口中(如钉钉机器人),需要遵循特定的消息格式规范。例如发送富文本消息时,结构可能如下: ```json { "msgtype": "link", "link": { "messageUrl": "https://example.com", "picUrl": "https://example.com/image.png", "title": "标题", "text": "消息正文" } } ``` 后端收到此类请求后,应封装成统一格式并通过第三方推送服务发出。同时记录日志并返回标准响应码以便前端处理结果反馈[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值