「消息桥」:从轮询到事件驱动的消息推送系统工程化落地

广告位招租
扫码页面底部二维码联系

轮询的困境与局限性

如果你干过后端或者前端,你一定写过类似这【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。样的代码:`setInterval(()原创内容,盗版必究。【作者:唐霜】 => fetch(‘本文版权归作者所有,未经授权不得转载。【本文受版权保护】/api/status’),原创内容,盗版必究。原创内容,盗版必究。 3000)`。别急着否认,我们都干过。本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】轮询这东西,就像快餐——不健康,但方便、未经授权,禁止复制转载。【未经授权禁止转载】便宜、随叫随到。项目早期,谁有空搞什么消【原创内容,转载请注明出处】【作者:唐霜】息队列、WebSocket、事件驱动?一【原创内容,转载请注明出处】【本文受版权保护】个定时器解决问题,多好。

本文版权归作者所有,未经授权不得转载。【本文受版权保护】

但业务一旦跑起来,轮询就开始还债了。

未经授权,禁止复制转载。【本文受版权保护】【版权所有】唐霜 www.tangshuang.net

想象一个场景:页面上有 10 个任务需要未经授权,禁止复制转载。【版权所有,侵权必究】通过轮询来获取最新状态,每个都跑着一个 转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net3 秒一次的轮询。算一下,每 3 秒就是【本文首发于唐霜的博客】【本文受版权保护】将近 30 个请求,而且其中 99% 的【本文受版权保护】【本文受版权保护】请求返回的数据跟上次一模一样——服务器在未经授权,禁止复制转载。【版权所有,侵权必究】那儿白忙活,带宽在那儿白白流,用户的设备【访问 www.tangshuang.net 获取更多精彩内容】【本文首发于唐霜的博客】也在那儿白白耗电。

【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。

这还不是最糟糕的。当你的系统从单页面变成转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。多页面,从单终端变成多终端——手机上点了原创内容,盗版必究。本文作者:唐霜,转载请注明出处。”生成”,电脑上【版权所有】唐霜 www.tangshuang.net【本文受版权保护】想看进度——轮询就彻底抓瞎了。你开始在各原创内容,盗版必究。【本文受版权保护】处补同步逻辑,今天这个页面加一段 `us未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。eEffect` 监听,明天那个组件加一【转载请注明来源】【作者:唐霜】个 `refetch` 调用,后天发现两【转载请注明来源】本文版权归作者所有,未经授权不得转载。个页面的状态互相打架。代码库里到处散落着【转载请注明来源】【本文受版权保护】”同步”的碎片,本文作者:唐霜,转载请注明出处。【原创内容,转载请注明出处】像打地鼠一样,按下去了这个,那个又冒出来本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net

【本文首发于唐霜的博客】【本文首发于唐霜的博客】原创内容,盗版必究。未经授权,禁止复制转载。

WebSocket 固然是最好的,但是一【转载请注明来源】【未经授权禁止转载】方面它一直占着一个长链接,用户一多,服务【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。器成本高。另一方面,前后端在接入 web【关注微信公众号:wwwtangshuangnet】【访问 www.tangshuang.net 获取更多精彩内容】socket 时,需要协调好连接的建立、本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。维护和关闭,这给开发带来了额外的复杂性。本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】另外,还有一种 SSE 的方案,但是,仍【转载请注明来源】转载请注明出处:www.tangshuang.net然有长链接占用服务器连接数,一旦出现高并【未经授权禁止转载】【未经授权禁止转载】发就会导致服务器长期被占用,新用户进不来本文版权归作者所有,未经授权不得转载。【作者:唐霜】的问题。相比之下,轮询更可控,更简单。

转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】

所以问题的本质不是”轮询好不本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】好”,而是我们需要一套系统性的方案来管理状态传播。轮询可以是这套方案的一部分,但不能是全【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。部。

【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。

问题的本质:构建分层状态传播机制

先明确一下目标。我们要建的不是什么花哨的本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。实时通信系统,而是一套分层的状态传播机制。这个机制要能覆盖三种典型场景:

【版权所有,侵权必究】未经授权,禁止复制转载。【转载请注明来源】【原创不易,请尊重版权】

第一种,日常状态。大部分时候系统很安静,没有任务在跑,没【本文受版权保护】【未经授权禁止转载】有什么需要频繁更新的。这时候我们希望用最【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】低的成本来维持”感知能力&#【转载请注明来源】本文作者:唐霜,转载请注明出处。8221;——有变化了我能知道,没变化的原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。时候你别来烦我。事件通知天然适合干这个。

【作者:唐霜】未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】

第二种,忙碌状态。用户点了个”生成视频本文作者:唐霜,转载请注明出处。【未经授权禁止转载】221;,进度条在那儿转,停止按钮随时可【原创不易,请尊重版权】未经授权,禁止复制转载。能被按下去。这时候你不能等事件慢悠悠地来【本文受版权保护】本文作者:唐霜,转载请注明出处。,用户对延迟的容忍度几乎是零。需要局部的【版权所有,侵权必究】【关注微信公众号:wwwtangshuangnet】、短周期的高频同步来保障体验。

本文版权归作者所有,未经授权不得转载。【转载请注明来源】

第三种,出了问题的时候。网络抖了,消息丢了,服务重启了——这种转载请注明出处:www.tangshuang.net【转载请注明来源】事一定会发生,区别只是早晚。你需要一个兜著作权归作者所有,禁止商业用途转载。【未经授权禁止转载】底机制,在事件链路和同步链路都掉链子的时【原创内容,转载请注明出处】【未经授权禁止转载】候,还能把数据拉回来,保证最终一致性。

本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】

这三层各司其职,互相补充。后面所有的设计【原创不易,请尊重版权】【作者:唐霜】决策,都是围绕这个三层模型展开的。

【未经授权禁止转载】转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.net

核心设计原则:通知与数据解耦

在我见过的消息系统里,最容易犯的一个错误【转载请注明来源】【版权所有】唐霜 www.tangshuang.net就是往消息体里塞太多东西。任务状态变了?【版权所有,侵权必究】【版权所有,侵权必究】好,把整个任务对象塞进消息里。资源更新了未经授权,禁止复制转载。【转载请注明来源】?把完整的资源数据也带上。听起来挺方便—【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。—前端收到消息直接用,不用再发请求了,多转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。省事。

【作者:唐霜】未经授权,禁止复制转载。

省事是省事了,但后患无穷。

【本文受版权保护】转载请注明出处:www.tangshuang.net

首先,消息体一大,吞吐量就下来了。你本来【原创内容,转载请注明出处】【原创不易,请尊重版权】一秒能发一万条轻量通知,现在一条消息就几【本文受版权保护】未经授权,禁止复制转载。 KB,同样的带宽能承载的量直接缩水。其【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。次,业务字段一变,消息协议就得跟着变。今著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。天加个字段,明天改个结构,消息的消费端全【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.net得跟着改——这就是耦合的代价。最要命的是著作权归作者所有,禁止商业用途转载。【作者:唐霜】,前端收到一个”大消息原创内容,盗版必究。【本文受版权保护】221;之后,到底要不要刷新?如果消息里【本文受版权保护】【本文受版权保护】的数据已经是最新的了,那确实不用刷;但如著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。果消息在路上耽搁了一会儿,数据库又更新了【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】呢?你拿消息里的数据去渲染,反而是错的。

【作者:唐霜】【本文首发于唐霜的博客】原创内容,盗版必究。【本文首发于唐霜的博客】

所以正确做法是:消息只告诉你”哪里脏了【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net221;,具体脏成了什么样,你自己去查。

【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。未经授权,禁止复制转载。【原创内容,转载请注明出处】

一条消息大概长这样:实体类型是̶【作者:唐霜】【版权所有】唐霜 www.tangshuang.net1;项目”,实体 ID 是 本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net123,任务类型是”视频生成【版权所有,侵权必究】【访问 www.tangshuang.net 获取更多精彩内容】”,时间戳是变更发生的时刻。原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。就够了。前端收到这条消息,知道̶本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】1;项目 123 的视频生成任务有变化&【转载请注明来源】本文版权归作者所有,未经授权不得转载。#8221;,然后自己去拉最新的数据。消【转载请注明来源】本文版权归作者所有,未经授权不得转载。息体小、协议稳定、前端按需刷新——三赢。

本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。未经授权,禁止复制转载。

幂等与去重:消息可靠性的基石

很多人在设计消息系统的时候,潜意识里假设本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】消息是可靠的——发一条,收一条,顺序还对【本文受版权保护】【作者:唐霜】。但现实是:消息可能重复发送(网络超时触本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。发了重试),可能乱序到达(走了不同的链路本文版权归作者所有,未经授权不得转载。【本文受版权保护】),可能延迟很久才到(某个中间件卡了一下【原创内容,转载请注明出处】原创内容,盗版必究。)。如果你不考虑这些,用户就会看到进度条【未经授权禁止转载】本文作者:唐霜,转载请注明出处。先跳到 100% 又弹回 50%,或者一【转载请注明来源】【原创内容,转载请注明出处】个已经完成的任务突然变成”进原创内容,盗版必究。【原创内容,转载请注明出处】行中”——这种体验,比没有通未经授权,禁止复制转载。【访问 www.tangshuang.net 获取更多精彩内容】知还糟糕。

转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。

所以在协议层面就要把去重和幂等做好。每条【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。消息带一个单调递增的 `timestam【作者:唐霜】【原创内容,转载请注明出处】p`(注意,必须是业务更新的真实时间,不本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。是消息发送的时间),前端收到消息后先跟本本文作者:唐霜,转载请注明出处。原创内容,盗版必究。地记录比一下:时间戳没前进?忽略。时间戳本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。前进了但 payload 一样?也忽略。本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。时间戳前进了且 payload 有变化?【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net更新本地记录,触发刷新。

【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。

还有一种常见的场景:短时间内同一个实体连【未经授权禁止转载】【本文首发于唐霜的博客】着来了好几条通知。比如一个视频生成任务,【版权所有】唐霜 www.tangshuang.net【未经授权禁止转载】先是”开始”,再著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】是”进度 30%”本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】;,再是”进度 60%【本文受版权保护】未经授权,禁止复制转载。221;——三条消息在一秒内扎堆到达。你未经授权,禁止复制转载。【未经授权禁止转载】不需要刷三次,合并成一次刷新就够了。这就本文版权归作者所有,未经授权不得转载。【原创不易,请尊重版权】是所谓的”通知合并̶【访问 www.tangshuang.net 获取更多精彩内容】【关注微信公众号:wwwtangshuangnet】1;,在桥接层做。

【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。

三层架构设计:采集、桥接与运行时

好,原则讲完了,来看具体的架构。整个系统【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。分三层,从上到下分别是消息采集层、客户端【关注微信公众号:wwwtangshuangnet】【未经授权禁止转载】桥接层和页面运行时层。听起来挺唬人,其实【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。每层做的事情都很明确。

著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net

第一层:消息采集层

这一层跑在后端,职责很简单:定期看看最近【版权所有,侵权必究】转载请注明出处:www.tangshuang.net有哪些实体发生了变化,整理成一个R【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】21;脏列表”返回给前端。

【访问 www.tangshuang.net 获取更多精彩内容】【访问 www.tangshuang.net 获取更多精彩内容】【本文首发于唐霜的博客】未经授权,禁止复制转载。

你可能会问:这不是还是轮询吗?对,但它跟【未经授权禁止转载】未经授权,禁止复制转载。页面的业务轮询有本质区别。页面轮询是&#原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。8221;我要查某个具体的东西有没有变&【原创不易,请尊重版权】【本文首发于唐霜的博客】#8221;,采集层是”有什【转载请注明来源】【转载请注明来源】么东西变了告诉我”。前者是 【版权所有,侵权必究】【转载请注明来源】N 个页面各轮询各的,后者是统一的、聚合本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】的状态变更源。前端只需要跟这一个源头打交著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】道,不用关心后端有多少个业务模块在产生变未经授权,禁止复制转载。【本文首发于唐霜的博客】更。

【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。

采集层吐出来的数据也很轻量:变更对象的类【本文受版权保护】【作者:唐霜】型和 ID、变更的范围(比如是资源变了还【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。是任务状态变了)、任务类型、时间戳。就这原创内容,盗版必究。【原创内容,转载请注明出处】么几个字段,JSON 序列化完也就一两百【原创不易,请尊重版权】【访问 www.tangshuang.net 获取更多精彩内容】字节。

【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。【作者:唐霜】【本文首发于唐霜的博客】

第二层:客户端桥接层

这一层跑在前端,是整个系统的中枢。它全局【本文受版权保护】【本文受版权保护】监听采集层吐出来的脏列表,写入本地的 d【转载请注明来源】未经授权,禁止复制转载。irty store,然后分发给各个页面【作者:唐霜】【转载请注明来源】

【本文首发于唐霜的博客】原创内容,盗版必究。【本文受版权保护】

桥接层要做的四件事,我在前面其实都提过了未经授权,禁止复制转载。【版权所有,侵权必究】:去重(基于时间戳)、合并(同实体多次通原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。知合并成一个)、限频(短时间窗口内的突发未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。通知攒一批再处理)、分发(转给对应的页面【本文受版权保护】未经授权,禁止复制转载。或模块)。这四件事做好了,下游的页面就不本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。用操心消息的可靠性问题了——你给它的就是本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】干净、去重、合并过的信号。

本文版权归作者所有,未经授权不得转载。【作者:唐霜】

第三层:页面运行时层

这一层是离用户最近的地方,也是最容易写出【作者:唐霜】【未经授权禁止转载】面条代码的地方。

本文作者:唐霜,转载请注明出处。【原创不易,请尊重版权】

页面收到 dirty 信号后,要决定怎么未经授权,禁止复制转载。【作者:唐霜】刷新。最直觉的做法是在事件回调里写一堆条未经授权,禁止复制转载。未经授权,禁止复制转载。件判断:如果任务类型是 A 就刷这个接口【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。,如果是 B 就刷那个接口,如果两个都有未经授权,禁止复制转载。【本文受版权保护】就都刷……写着写着,回调函数就膨胀成了几原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。百行的怪物,而且逻辑散落各处,谁也不敢改著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】

转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】

更好的做法是抽象出一个策略映射表。输入是任务类型、变更范围和当前页面的上著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。下文(是不是忙态、页面可不可见、当前选中【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。了什么),输出是一个明确的”【原创内容,转载请注明出处】【原创内容,转载请注明出处】刷新计划”——需要刷哪些接口【关注微信公众号:wwwtangshuangnet】【本文受版权保护】、以什么粒度刷、串行还是并行。这样逻辑集本文作者:唐霜,转载请注明出处。【原创内容,转载请注明出处】中在一处,新增任务类型只需要加一行映射,【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】不用动流程代码。

【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。

刷新执行完之后,还要做一次”【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】收敛检查”——确认本地的状态未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net跟远端的状态一致了。如果不一致,说明中间本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net可能漏了什么,这时候就触发兜底拉取。

著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net【版权所有,侵权必究】

系统工作流程:注册、采集与消费的完整链路

前面讲了三层架构各自负责什么,但光知道&【本文受版权保护】本文作者:唐霜,转载请注明出处。#8221;谁干什么”还不够【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net——你得看到数据是怎么从头到尾流转的,才【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。能真正理解这套系统为什么这么设计。

【本文受版权保护】【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net

整个工作流程分六个步骤,先用一张图把全局【转载请注明来源】转载请注明出处:www.tangshuang.net串起来:

本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。 服务端(Server) 业务模块 A 业务模块 B 业务模块 C ① register(type, handler) MessageRegistry ② collect(uid) GET /api/messages ③ HTTP 轮询(3s 间隔) 请求 ↓ ↑ 响应 { messages: [{ type, has_new }], timestamp: 1717000000 } 客户端(Client) MessagePoller ④ globalEvent.emit(‘MSG:${type}’, data) globalEvent Bus ⑤ on(‘MSG:${type}’, handler) 业务 Hook A 业务 Hook B 业务 Hook C ⑥ DataSource.fetch() & 渲染 UI 组件 A UI 组件 B UI 组件 C 注册阶段 采集阶段 消费阶段

下面逐步拆解。

转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】

① 注册:业务模块告诉系统”【关注微信公众号:wwwtangshuangnet】【作者:唐霜】我能检测变化”

未经授权,禁止复制转载。未经授权,禁止复制转载。

这是整个流程的起点。每个业务模块在服务启著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。动的时候,向 MessageRegist【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】ry 注册自己:我叫什么名字(type)原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。,以及怎么检测变化(handler)。比【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】如通知模块注册了 `notificati【原创内容,转载请注明出处】【原创内容,转载请注明出处】on.announcement`,视频任本文作者:唐霜,转载请注明出处。【本文受版权保护】务模块注册了 `video.genera【本文首发于唐霜的博客】【作者:唐霜】tion`——每个模块只需要管好自己的 【版权所有,侵权必究】【原创不易,请尊重版权】handler,不用关心谁在消费这些消息【转载请注明来源】本文作者:唐霜,转载请注明出处。

【原创内容,转载请注明出处】未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】

handler 的接口很简单:给它一个用【原创不易,请尊重版权】【本文首发于唐霜的博客】户 ID,它返回 `{ has_new:转载请注明出处:www.tangshuang.net【作者:唐霜】 true/false, data: {本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。…} }`。至于”【关注微信公众号:wwwtangshuangnet】【未经授权禁止转载】;怎么判断有没有新消息”,那【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】是每个业务模块自己的事——查数据库也好,未经授权,禁止复制转载。原创内容,盗版必究。读缓存也好,MessageRegistr【作者:唐霜】著作权归作者所有,禁止商业用途转载。y 不操心。

【本文受版权保护】【原创不易,请尊重版权】【作者:唐霜】转载请注明出处:www.tangshuang.net

② 采集:统一入口,并发调用所有 han本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】dler

【版权所有,侵权必究】【关注微信公众号:wwwtangshuangnet】

当前端发来 `GET /api/mess原创内容,盗版必究。本文版权归作者所有,未经授权不得转载。ages` 请求时,API 层调用 `M著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】essageRegistry.colle原创内容,盗版必究。【本文受版权保护】ct(uid)`。这个方法会遍历所有已注原创内容,盗版必究。【转载请注明来源】册的 handler,用 `Promis【原创不易,请尊重版权】【原创内容,转载请注明出处】e.allSettled` 并发调用——【原创内容,转载请注明出处】未经授权,禁止复制转载。注意是 `allSettled` 而不是本文版权归作者所有,未经授权不得转载。【转载请注明来源】 `all`,意思是某个 handler【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net 挂了不影响其他 handler 的结果【版权所有,侵权必究】【本文首发于唐霜的博客】。最后把 `has_new` 为 tru【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.nete 的消息筛出来返回。

本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】

这就是”通知与数据解耦著作权归作者所有,禁止商业用途转载。【作者:唐霜】221;的具体体现:返回的不是完整业务数未经授权,禁止复制转载。【转载请注明来源】据,而是一个轻量的”有没有变本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。化”的信号。前端拿到这个信号【版权所有】唐霜 www.tangshuang.net【作者:唐霜】,再决定要不要去拉具体数据。

转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】原创内容,盗版必究。【作者:唐霜】

③ 轮询:前端的统一心跳

转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net

MessagePoller 是前端唯一跟转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。消息系统打交道的地方。它每 3 秒发一次【版权所有,侵权必究】【关注微信公众号:wwwtangshuangnet】 `GET /api/messages`【转载请注明来源】【版权所有】唐霜 www.tangshuang.net,不管页面上有多少个业务模块在等消息——转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。只需要这一个轮询就够了。跟之前̶转载请注明出处:www.tangshuang.net【本文受版权保护】1;每个业务各轮询各的”相比【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。,请求量从 N 降到 1。

【版权所有】唐霜 www.tangshuang.net【本文受版权保护】

返回的数据也很精简:一组 `{ type【转载请注明来源】【版权所有】唐霜 www.tangshuang.net, has_new, data }` 加【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net一个全局时间戳。如果没有任何变化,响应就本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。是空的,几乎不占带宽。

本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net

④ 广播:把”脏信号R【版权所有,侵权必究】原创内容,盗版必究。21;分发出去

【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】【未经授权禁止转载】

Poller 收到响应后,遍历所有 `h【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.netas_new` 的消息,通过 `glob【访问 www.tangshuang.net 获取更多精彩内容】【原创内容,转载请注明出处】alEvent.emit(‘【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。MSG:${type}’, 未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。data)` 广播出去。这一步就是著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。221;桥接层”在干活——它本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。把后端的轮询响应转化成了前端内部的事件总【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。线。

【转载请注明来源】未经授权,禁止复制转载。【本文首发于唐霜的博客】

为什么要用事件总线而不是直接调各个模块的【本文首发于唐霜的博客】【转载请注明来源】方法?因为解耦。Poller 不需要知道【版权所有,侵权必究】原创内容,盗版必究。页面上有哪些模块在监听,也不需要知道每个本文版权归作者所有,未经授权不得转载。【本文受版权保护】模块拿到消息后要干什么。它只管̶【版权所有】唐霜 www.tangshuang.net转载请注明出处:www.tangshuang.net1;谁有变化,就喊一嗓子”,未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。至于谁来听、听了之后做什么,各自负责。

【未经授权禁止转载】【转载请注明来源】转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。

⑤ 订阅:各取所需,按类型监听

未经授权,禁止复制转载。【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。

每个业务模块在前端通过 `globalE转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。vent.on(‘MSG:$本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】{type}’, handl【访问 www.tangshuang.net 获取更多精彩内容】【未经授权禁止转载】er)` 监听自己关心的消息类型。通知模原创内容,盗版必究。原创内容,盗版必究。块听 `MSG:notification【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】.announcement`,视频任务模【原创内容,转载请注明出处】【原创内容,转载请注明出处】块听 `MSG:video.genera未经授权,禁止复制转载。【版权所有,侵权必究】tion`——互不干扰,各自拿到各自的信【本文受版权保护】原创内容,盗版必究。号。

【作者:唐霜】转载请注明出处:www.tangshuang.net

这种模式的好处是:新增一个业务模块,只需【版权所有,侵权必究】转载请注明出处:www.tangshuang.net要在后端注册一个 handler、在前端【作者:唐霜】【版权所有】唐霜 www.tangshuang.net加一个 `on` 监听,不用改 Poll【未经授权禁止转载】【转载请注明来源】er、不用改 API、不用改任何其他模块原创内容,盗版必究。本文作者:唐霜,转载请注明出处。的代码。真正的”开闭原则&#本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。8221;。

本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。

⑥ 拉取与渲染:按需获取完整数据

【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】原创内容,盗版必究。

Hook 收到”脏信号【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net221;之后,才去调具体的业务接口拉完整转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。数据——这就是所谓的”按需拉著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net取”。拉到数据后更新本地状态【版权所有,侵权必究】【原创内容,转载请注明出处】,UI 组件自动响应式渲染。

【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。

整个链路串起来就是:业务模块注册 → Poller 轮询触发未经授权,禁止复制转载。未经授权,禁止复制转载。采集 → Registry 并发调用 h未经授权,禁止复制转载。【本文首发于唐霜的博客】andler → 返回脏信号 → Pol本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】ler 广播 → Hook 订阅 → 按【本文首发于唐霜的博客】【本文首发于唐霜的博客】需拉取 → UI 更新。每一步职责清晰,每一步都可以独立演进。

【版权所有】唐霜 www.tangshuang.net【转载请注明来源】著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。

并发控制:刷新风暴的防御策略

这是实际落地中很容易踩的坑。想象一下:用【本文受版权保护】【关注微信公众号:wwwtangshuangnet】户一口气提交了 10 个生成任务,每个任本文版权归作者所有,未经授权不得转载。【转载请注明来源】务的状态变更都会触发刷新,短时间内你可能【转载请注明来源】原创内容,盗版必究。面临几十次刷新请求同时发出的情况——这就【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】是刷新风暴。

原创内容,盗版必究。转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】【作者:唐霜】

有三个招可以防。

【转载请注明来源】【作者:唐霜】

第一招:请求合并(In-flight C本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。oalescing)。 同一个接口的请求如果在飞了(还没回来)【原创不易,请尊重版权】【本文首发于唐霜的博客】,后来的请求不要重复发,只打个标记。等前【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。面的请求回来了,根据标记决定要不要再发一【未经授权禁止转载】原创内容,盗版必究。次。这样就算一瞬间来了 10 个通知,同原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net一个接口最多也就 2 次请求:一次处理已本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net有的变更,一次处理积攒的新变更。

本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。转载请注明出处:www.tangshuang.net

第二招:模式升级(Mode Escala【访问 www.tangshuang.net 获取更多精彩内容】本文版权归作者所有,未经授权不得转载。tion)。 有时候一个”轻刷新R本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】21;(比如只拉任务状态)和一个R【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net21;重刷新”(比如拉完整的【未经授权禁止转载】【原创内容,转载请注明出处】资源列表)同时触发了。与其分别执行两次,转载请注明出处:www.tangshuang.net【作者:唐霜】不如直接升级成重刷新一次搞定。反正重刷新本文作者:唐霜,转载请注明出处。【转载请注明来源】的结果包含轻刷新的结果,做一次就够了。

【未经授权禁止转载】原创内容,盗版必究。【本文首发于唐霜的博客】【原创不易,请尊重版权】

第三招:软超时兜底。 正常情况下,事件链路会自然收敛——任务【作者:唐霜】【转载请注明来源】结束了,最后一轮刷新确认了状态,皆大欢喜著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。。但万一没收敛呢?比如最后一条消息丢了,转载请注明出处:www.tangshuang.net【本文受版权保护】前端一直卡在”进行中R转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】21;。这时候需要一个软超时:如果过了指【作者:唐霜】著作权归作者所有,禁止商业用途转载。定时间还没有收敛确认,就主动触发一次兜底本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。拉取,强行把状态拉对。注意是”【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】;软”超时——不是硬中断,而本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net是温和地补一次。

本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。【作者:唐霜】转载请注明出处:www.tangshuang.net

生命周期策略:忙态与闲态的分治管理

如果你的系统在任何时候都以同样的策略运行本文作者:唐霜,转载请注明出处。【本文受版权保护】,那一定有什么地方在浪费。没有任务跑的时转载请注明出处:www.tangshuang.net【转载请注明来源】候,没必要每 3 秒同步一次;任务跑得正本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。欢的时候,你也不能指望事件通知能跟上用户【未经授权禁止转载】【转载请注明来源】对即时反馈的期望。

原创内容,盗版必究。【转载请注明来源】

所以需要区分两种状态:忙态和闲态。

【转载请注明来源】转载请注明出处:www.tangshuang.net

忙态就是有任务在跑的时候。这时候保持一个短周【原创内容,转载请注明出处】【作者:唐霜】期的局部同步(比如 2~3 秒一次),主【本文受版权保护】著作权归作者所有,禁止商业用途转载。要为了保障进度条的即时更新、锁定状态的准转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】确显示、停止按钮的快速响应。这个同步范围【未经授权禁止转载】转载请注明出处:www.tangshuang.net要尽量小——只同步当前关心的那个实体的任【版权所有】唐霜 www.tangshuang.net【本文受版权保护】务状态,不要全量拉。

【转载请注明来源】【转载请注明来源】著作权归作者所有,禁止商业用途转载。

闲态就是没有活动任务的时候。这时候关掉高频同【本文受版权保护】本文作者:唐霜,转载请注明出处。步,主要依赖事件通知来唤醒刷新。没变化就本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。什么都不做,有变化了事件会告诉你。

本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】【版权所有】唐霜 www.tangshuang.net

关键在于怎么切换。进入忙态不能只看本地状态——用户可能在【作者:唐霜】【本文首发于唐霜的博客】另一个设备上启动了任务——必须结合远端状【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】态一起判断。退出忙态也不能急,必须确认状本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】态已经收敛了(本地状态跟远端状态一致了)【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。才能退,不然 UI 会抖。

【访问 www.tangshuang.net 获取更多精彩内容】【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。

这里有个细节值得注意:退出忙态的时机太早【本文受版权保护】【版权所有】唐霜 www.tangshuang.net,用户会看到进度条突然跳回旧状态;太晚,【未经授权禁止转载】转载请注明出处:www.tangshuang.net又白白多轮询了好几轮。实践中,我们会在最【转载请注明来源】【本文首发于唐霜的博客】后一轮同步确认”没有活跃任务原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。”之后,再等一个周期做二次确【本文受版权保护】本文版权归作者所有,未经授权不得转载。认,然后才真正退出忙态。两轮确认,换来的【作者:唐霜】【原创不易,请尊重版权】是 UI 的稳定。同时,为了在有新任务时原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net,避免闲态轮询间隔时间过长,我们可以在发【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】起新任务的地方,立即激活忙态,让轮询恢复【转载请注明来源】【未经授权禁止转载】较短间隔。

未经授权,禁止复制转载。【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net

数据一致性与异常场景处理

设计消息系统的时候,有一些边界情况特别容【本文受版权保护】【关注微信公众号:wwwtangshuangnet】易忽略,但一旦出问题就特别显眼。

【作者:唐霜】本文作者:唐霜,转载请注明出处。

乱序问题。*消息 A 先发出,消息 B 后发出,但 【本文首发于唐霜的博客】【原创不易,请尊重版权】B 先到了。如果你简单地”收【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】到就更新”,就会用旧数据覆盖【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。新数据。解决方案是永远以更新的版本为准—【原创内容,转载请注明出处】【本文首发于唐霜的博客】—不是”后到为准”【未经授权禁止转载】【作者:唐霜】;,而是”时间戳更大为准&#转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】8221;。

【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。

停止的语义。 “用户点了停止”【版权所有,侵权必究】【原创不易,请尊重版权】;和”任务已经停了̶【作者:唐霜】本文作者:唐霜,转载请注明出处。1;是两个不同的状态。点了停止之后,任务本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。可能还需要一段时间才能真正停下来。如果 转载请注明出处:www.tangshuang.net【作者:唐霜】UI 在用户点完停止后就直接显示R【版权所有】唐霜 www.tangshuang.net【原创内容,转载请注明出处】21;已完成”,用户会以为结转载请注明出处:www.tangshuang.net原创内容,盗版必究。果已经出来了;如果一直显示”转载请注明出处:www.tangshuang.net原创内容,盗版必究。停止中”不动,用户又以为系统【原创不易,请尊重版权】【原创内容,转载请注明出处】卡死了。正确的做法是有一个明确的R【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】21;停止中”过渡态,等任务【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】真正停了再切换到最终状态。

【原创不易,请尊重版权】【原创内容,转载请注明出处】【作者:唐霜】本文作者:唐霜,转载请注明出处。

失败恢复。 刷新失败了怎么办?第一反应可能是立即重【未经授权禁止转载】【原创内容,转载请注明出处】试,但这是错的——如果失败是因为服务端过未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net载,立即重试只会让情况更糟。应该用指数退转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】避:第一次等 1 秒重试,第二次等 2 【作者:唐霜】【版权所有】唐霜 www.tangshuang.net秒,第三次等 4 秒……同时保留一个最小转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】兜底路径,确保即使重试都失败了,用户下次【本文受版权保护】【版权所有】唐霜 www.tangshuang.net操作时也能拿到正确数据。别忘了打点记录失本文作者:唐霜,转载请注明出处。【原创不易,请尊重版权】败原因——这些数据在排查问题的时候是无价本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。之宝。

未经授权,禁止复制转载。【转载请注明来源】本文版权归作者所有,未经授权不得转载。

可观测性设计:上线后的关键指标

系统做完了不是结束,是开始。没有可观测性【作者:唐霜】转载请注明出处:www.tangshuang.net的消息系统,上线之后就是一个谁都不敢动的原创内容,盗版必究。【转载请注明来源】黑盒——出了问题不知道,知道了不知道为什转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net么,知道了为什么不知道怎么修。

【本文首发于唐霜的博客】【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。【原创不易,请尊重版权】

建议关注四组指标。

【原创不易,请尊重版权】【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】

链路健康:消息采样成功率怎么样?`has_new本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】` 的命中率是多少(如果命中率太低,说明【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。采样周期内大部分时候都没变化,可以适当拉【版权所有】唐霜 www.tangshuang.net【作者:唐霜】长周期)?客户端消费成功率呢(有没有消息【关注微信公众号:wwwtangshuangnet】本文作者:唐霜,转载请注明出处。到了前端但没被处理的情况)?

【本文受版权保护】【转载请注明来源】【版权所有,侵权必究】

性能:单用户每分钟的消息量是多少?单页面每分【访问 www.tangshuang.net 获取更多精彩内容】【本文首发于唐霜的博客】钟的刷新请求量是多少?刷新的平均耗时和 原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】P95 是多少?这些数字能帮你判断系统有【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】没有在”空转”。

著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】【版权所有,侵权必究】

正确性:兜底同步触发了多少次?如果兜底同步触发【转载请注明来源】【未经授权禁止转载】太频繁,说明主链路有问题。状态收敛超时率未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。是多少?前端有没有”卡在运行本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net中”一直不恢复的情况?

【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】

体验:从任务实际结束到 UI 显示更新,用户【原创内容,转载请注明出处】【转载请注明来源】等了多久?从用户按下”停止&【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】#8221;到看到停止反馈,又等了多久?【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。这两个延迟是用户最直接能感知到的。

本文作者:唐霜,转载请注明出处。【转载请注明来源】

工程化落地路径

说了这么多,真正动手的时候应该从哪一步开【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net始?我建议按这个顺序来:

【版权所有,侵权必究】本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】【版权所有,侵权必究】

先定义统一的 dirty 协议。这是整个【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。系统的基石,协议不定好,后面都白搭。然后著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。搭服务端采集器,按 TTL 返回最近变化本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。。接下来搭前端桥接层,把去重、合并、分发【版权所有】唐霜 www.tangshuang.net【本文受版权保护】做好。这三步做完,基础设施就有了。

【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。

然后抽象刷新策略映射表,把页面里的面条逻【原创不易,请尊重版权】【转载请注明来源】辑收拢。再接入页面运行时,实现忙态轮询和【原创内容,转载请注明出处】【本文受版权保护】闲态消息唤醒。加上 in-flight 转载请注明出处:www.tangshuang.net【版权所有,侵权必究】合并和软超时兜底之后,系统的可靠性就基本转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。有保障了。

【转载请注明来源】【版权所有】唐霜 www.tangshuang.net

最后补观测指标和报警,做灰度验证,对比改转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】造前后的指标变化。千万别跳过灰度——消息本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。系统是底层基础设施,全量上线出问题就是全【本文受版权保护】【转载请注明来源】局性的。

转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net

常见反模式与规避策略

在结束之前,再聊几个我见过的典型反模式,【原创不易,请尊重版权】【版权所有,侵权必究】希望你看了能绕开。

【作者:唐霜】转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。

把完整业务对象塞进消息体。 前面说过这个了,再说一遍是因为真的太常【原创内容,转载请注明出处】未经授权,禁止复制转载。见了。图一时方便,后面维护的时候就知道什未经授权,禁止复制转载。原创内容,盗版必究。么叫”牵一发而动全身R【未经授权禁止转载】【作者:唐霜】21;。

著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】

页面里到处都是”收到通知就全转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】量刷新”。 这种做法简单粗暴,短期内能跑,但请求量著作权归作者所有,禁止商业用途转载。【转载请注明来源】大、用户体验差、服务器压力大。而且每个页【原创不易,请尊重版权】【原创内容,转载请注明出处】面的刷新逻辑都是独立的,改一个地方容易,【版权所有】唐霜 www.tangshuang.net【未经授权禁止转载】改十个地方就呵呵了。

【转载请注明来源】【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。

不做去重。 重复通知触发重复请求,重复请求返回重复【本文受版权保护】【未经授权禁止转载】数据,重复数据触发重复渲染——这条链路每【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net一环都在浪费。

【原创不易,请尊重版权】【作者:唐霜】【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net

任务结束只靠单一信号判断。 比如只看”任务状态变成了 本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.netcompleted”,但如果【版权所有,侵权必究】本文作者:唐霜,转载请注明出处。这条消息丢了呢?或者来了但被去重逻辑误判【转载请注明来源】本文版权归作者所有,未经授权不得转载。了呢?必须有兜底手段。

本文版权归作者所有,未经授权不得转载。【原创不易,请尊重版权】

用固定高频轮询覆盖所有场景。 不管有没有任务在跑,都 3 秒轮询一次【转载请注明来源】著作权归作者所有,禁止商业用途转载。。这是偷懒的做法,对用户、对服务器都不友【版权所有,侵权必究】【转载请注明来源】好。

转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。【作者:唐霜】【版权所有】唐霜 www.tangshuang.net

说到底,一套好的消息通知系统就在做三件事转载请注明出处:www.tangshuang.net【本文受版权保护】:用事件减少无效同步的成本,用运行时策略【转载请注明来源】未经授权,禁止复制转载。保障关键交互的体验,用兜底机制守住最终一著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。致性。

本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net

它不是某个框架的特性,也不是某段代码的技【原创不易,请尊重版权】【原创不易,请尊重版权】巧,而是一种可以复制的工程化能力。只要你【原创内容,转载请注明出处】【关注微信公众号:wwwtangshuangnet】的系统存在”异步任务 + 状【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net态反馈 + 多端一致性”的问【关注微信公众号:wwwtangshuangnet】【作者:唐霜】题——说白了,只要你做过任何涉及异步状态原创内容,盗版必究。【转载请注明来源】的 Web 应用——这套方案都能落地,而【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】且能跟着业务一起演进。

转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】

当然,这篇文章里的每一条都是过来人的经验【关注微信公众号:wwwtangshuangnet】【作者:唐霜】总结,不是什么金科玉律。你的业务场景可能【原创内容,转载请注明出处】【原创内容,转载请注明出处】有自己的特殊性,该调整的地方就调整。重要本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net的是理解背后的思路:分层、解耦、幂等、可本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。观测——这四个词记住了,设计出来的系统就本文作者:唐霜,转载请注明出处。原创内容,盗版必究。不会差到哪里去。

未经授权,禁止复制转载。【作者:唐霜】

2026-05-29 604

为价值买单,打赏一杯咖啡

本文价值6.04RMB
已有1条评论
  1. […] 而轮询,则是作为顶替长链接的一种原始办法。我在《「消息桥」:从轮询到事件驱动的消息推送系统工程化落地》一文中,基于轮询设计了一套消息通知系统。 […]