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

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

轮询的困境与局限性

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

【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。

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

本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】

想象一个场景:页面上有 10 个任务需要【版权所有,侵权必究】转载请注明出处:www.tangshuang.net通过轮询来获取最新状态,每个都跑着一个 原创内容,盗版必究。【转载请注明来源】3 秒一次的轮询。算一下,每 3 秒就是【作者:唐霜】【原创内容,转载请注明出处】将近 30 个请求,而且其中 99% 的【转载请注明来源】【未经授权禁止转载】请求返回的数据跟上次一模一样——服务器在【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net那儿白忙活,带宽在那儿白白流,用户的设备【原创不易,请尊重版权】【版权所有,侵权必究】也在那儿白白耗电。

著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。未经授权,禁止复制转载。【本文受版权保护】

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

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

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

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

所以问题的本质不是”轮询好不【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。好”,而是我们需要一套系统性的方案来管理状态传播。轮询可以是这套方案的一部分,但不能是全【原创内容,转载请注明出处】【原创内容,转载请注明出处】部。

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

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

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

【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。

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

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

第二种,忙碌状态。用户点了个”生成视频【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。221;,进度条在那儿转,停止按钮随时可【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】能被按下去。这时候你不能等事件慢悠悠地来原创内容,盗版必究。【转载请注明来源】,用户对延迟的容忍度几乎是零。需要局部的【本文受版权保护】著作权归作者所有,禁止商业用途转载。、短周期的高频同步来保障体验。

【原创内容,转载请注明出处】【版权所有,侵权必究】未经授权,禁止复制转载。【版权所有,侵权必究】

第三种,出了问题的时候。网络抖了,消息丢了,服务重启了——这种【关注微信公众号:wwwtangshuangnet】【访问 www.tangshuang.net 获取更多精彩内容】事一定会发生,区别只是早晚。你需要一个兜【原创内容,转载请注明出处】【版权所有,侵权必究】底机制,在事件链路和同步链路都掉链子的时本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net候,还能把数据拉回来,保证最终一致性。

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

这三层各司其职,互相补充。后面所有的设计原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。决策,都是围绕这个三层模型展开的。

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

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

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

【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net

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

未经授权,禁止复制转载。【原创内容,转载请注明出处】【作者:唐霜】

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

原创内容,盗版必究。【作者:唐霜】原创内容,盗版必究。

所以正确做法是:消息只告诉你”哪里脏了原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】221;,具体脏成了什么样,你自己去查。

【未经授权禁止转载】【未经授权禁止转载】

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

转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。【本文受版权保护】

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

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

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

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

【本文首发于唐霜的博客】本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net

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

【作者:唐霜】【本文首发于唐霜的博客】

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

好,原则讲完了,来看具体的架构。整个系统本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】分三层,从上到下分别是消息采集层、客户端【未经授权禁止转载】【原创内容,转载请注明出处】桥接层和页面运行时层。听起来挺唬人,其实【本文首发于唐霜的博客】未经授权,禁止复制转载。每层做的事情都很明确。

转载请注明出处:www.tangshuang.net原创内容,盗版必究。

第一层:消息采集层

这一层跑在后端,职责很简单:定期看看最近本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net有哪些实体发生了变化,整理成一个R【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】21;脏列表”返回给前端。

【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】【未经授权禁止转载】【未经授权禁止转载】

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

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

采集层吐出来的数据也很轻量:变更对象的类著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】型和 ID、变更的范围(比如是资源变了还未经授权,禁止复制转载。未经授权,禁止复制转载。是任务状态变了)、任务类型、时间戳。就这【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。么几个字段,JSON 序列化完也就一两百未经授权,禁止复制转载。【本文首发于唐霜的博客】字节。

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

第二层:客户端桥接层

这一层跑在前端,是整个系统的中枢。它全局本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】监听采集层吐出来的脏列表,写入本地的 d【未经授权禁止转载】【本文受版权保护】irty store,然后分发给各个页面【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。

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

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

【本文受版权保护】著作权归作者所有,禁止商业用途转载。

第三层:页面运行时层

这一层是离用户最近的地方,也是最容易写出【转载请注明来源】【原创内容,转载请注明出处】面条代码的地方。

原创内容,盗版必究。【未经授权禁止转载】

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

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

更好的做法是抽象出一个策略映射表。输入是任务类型、变更范围和当前页面的上原创内容,盗版必究。【未经授权禁止转载】下文(是不是忙态、页面可不可见、当前选中未经授权,禁止复制转载。未经授权,禁止复制转载。了什么),输出是一个明确的”【转载请注明来源】【原创不易,请尊重版权】刷新计划”——需要刷哪些接口转载请注明出处:www.tangshuang.net【未经授权禁止转载】、以什么粒度刷、串行还是并行。这样逻辑集【转载请注明来源】原创内容,盗版必究。中在一处,新增任务类型只需要加一行映射,【转载请注明来源】原创内容,盗版必究。不用动流程代码。

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

刷新执行完之后,还要做一次”【作者:唐霜】【原创内容,转载请注明出处】收敛检查”——确认本地的状态【本文受版权保护】著作权归作者所有,禁止商业用途转载。跟远端的状态一致了。如果不一致,说明中间【原创内容,转载请注明出处】【本文受版权保护】可能漏了什么,这时候就触发兜底拉取。

原创内容,盗版必究。【作者:唐霜】【未经授权禁止转载】

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

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

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

整个工作流程分六个步骤,先用一张图把全局本文作者:唐霜,转载请注明出处。原创内容,盗版必究。串起来:

未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】本文作者:唐霜,转载请注明出处。 服务端(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】我能检测变化”

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

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

本文作者:唐霜,转载请注明出处。【未经授权禁止转载】

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

【版权所有】唐霜 www.tangshuang.net【作者:唐霜】【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。

② 采集:统一入口,并发调用所有 han【作者:唐霜】未经授权,禁止复制转载。dler

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

当前端发来 `GET /api/mess转载请注明出处:www.tangshuang.net【版权所有,侵权必究】ages` 请求时,API 层调用 `M本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】essageRegistry.colle【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.netct(uid)`。这个方法会遍历所有已注本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。册的 handler,用 `Promis转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】e.allSettled` 并发调用——【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】注意是 `allSettled` 而不是未经授权,禁止复制转载。【原创内容,转载请注明出处】 `all`,意思是某个 handler本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。 挂了不影响其他 handler 的结果本文作者:唐霜,转载请注明出处。【版权所有】唐霜 www.tangshuang.net。最后把 `has_new` 为 tru【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.nete 的消息筛出来返回。

著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】【本文受版权保护】

这就是”通知与数据解耦【原创不易,请尊重版权】【本文受版权保护】221;的具体体现:返回的不是完整业务数【未经授权禁止转载】转载请注明出处:www.tangshuang.net据,而是一个轻量的”有没有变未经授权,禁止复制转载。转载请注明出处:www.tangshuang.net化”的信号。前端拿到这个信号【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。,再决定要不要去拉具体数据。

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

③ 轮询:前端的统一心跳

转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】【本文受版权保护】本文作者:唐霜,转载请注明出处。

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

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

返回的数据也很精简:一组 `{ type本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】, has_new, data }` 加原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】一个全局时间戳。如果没有任何变化,响应就【本文受版权保护】著作权归作者所有,禁止商业用途转载。是空的,几乎不占带宽。

本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net

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

未经授权,禁止复制转载。【原创不易,请尊重版权】

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

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

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

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

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

【作者:唐霜】著作权归作者所有,禁止商业用途转载。

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

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

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

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

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

著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。

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

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

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

【本文受版权保护】原创内容,盗版必究。

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

这是实际落地中很容易踩的坑。想象一下:用【转载请注明来源】未经授权,禁止复制转载。户一口气提交了 10 个生成任务,每个任【作者:唐霜】原创内容,盗版必究。务的状态变更都会触发刷新,短时间内你可能【转载请注明来源】【原创不易,请尊重版权】面临几十次刷新请求同时发出的情况——这就【未经授权禁止转载】【作者:唐霜】是刷新风暴。

【未经授权禁止转载】【关注微信公众号:wwwtangshuangnet】

有三个招可以防。

转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】【原创内容,转载请注明出处】【未经授权禁止转载】

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

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

第二招:模式升级(Mode Escala【本文受版权保护】【作者:唐霜】tion)。 有时候一个”轻刷新R未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。21;(比如只拉任务状态)和一个R【本文首发于唐霜的博客】【本文受版权保护】21;重刷新”(比如拉完整的【原创内容,转载请注明出处】【未经授权禁止转载】资源列表)同时触发了。与其分别执行两次,本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。不如直接升级成重刷新一次搞定。反正重刷新转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。的结果包含轻刷新的结果,做一次就够了。

本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。【未经授权禁止转载】

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

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

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

如果你的系统在任何时候都以同样的策略运行【本文受版权保护】转载请注明出处:www.tangshuang.net,那一定有什么地方在浪费。没有任务跑的时【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】候,没必要每 3 秒同步一次;任务跑得正【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net欢的时候,你也不能指望事件通知能跟上用户【版权所有,侵权必究】【访问 www.tangshuang.net 获取更多精彩内容】对即时反馈的期望。

【转载请注明来源】原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。

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

本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。【版权所有,侵权必究】

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

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

闲态就是没有活动任务的时候。这时候关掉高频同【版权所有,侵权必究】【作者:唐霜】步,主要依赖事件通知来唤醒刷新。没变化就【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。什么都不做,有变化了事件会告诉你。

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

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

本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。【原创不易,请尊重版权】

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

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

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

设计消息系统的时候,有一些边界情况特别容本文作者:唐霜,转载请注明出处。原创内容,盗版必究。易忽略,但一旦出问题就特别显眼。

【本文首发于唐霜的博客】【版权所有,侵权必究】【访问 www.tangshuang.net 获取更多精彩内容】

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

转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net

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

【本文受版权保护】转载请注明出处:www.tangshuang.net【版权所有,侵权必究】

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

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

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

系统做完了不是结束,是开始。没有可观测性【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。的消息系统,上线之后就是一个谁都不敢动的【本文首发于唐霜的博客】未经授权,禁止复制转载。黑盒——出了问题不知道,知道了不知道为什未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。么,知道了为什么不知道怎么修。

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

建议关注四组指标。

【访问 www.tangshuang.net 获取更多精彩内容】【版权所有,侵权必究】

链路健康:消息采样成功率怎么样?`has_new【本文受版权保护】【原创不易,请尊重版权】` 的命中率是多少(如果命中率太低,说明未经授权,禁止复制转载。【转载请注明来源】采样周期内大部分时候都没变化,可以适当拉著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net长周期)?客户端消费成功率呢(有没有消息【作者:唐霜】本文作者:唐霜,转载请注明出处。到了前端但没被处理的情况)?

【本文受版权保护】著作权归作者所有,禁止商业用途转载。

性能:单用户每分钟的消息量是多少?单页面每分【原创不易,请尊重版权】【作者:唐霜】钟的刷新请求量是多少?刷新的平均耗时和 【转载请注明来源】【版权所有】唐霜 www.tangshuang.netP95 是多少?这些数字能帮你判断系统有【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net没有在”空转”。

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

正确性:兜底同步触发了多少次?如果兜底同步触发【转载请注明来源】【原创不易,请尊重版权】太频繁,说明主链路有问题。状态收敛超时率原创内容,盗版必究。本文作者:唐霜,转载请注明出处。是多少?前端有没有”卡在运行【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】中”一直不恢复的情况?

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

体验:从任务实际结束到 UI 显示更新,用户【作者:唐霜】【原创内容,转载请注明出处】等了多久?从用户按下”停止&【未经授权禁止转载】【作者:唐霜】#8221;到看到停止反馈,又等了多久?转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。这两个延迟是用户最直接能感知到的。

著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。

工程化落地路径

说了这么多,真正动手的时候应该从哪一步开未经授权,禁止复制转载。【版权所有,侵权必究】始?我建议按这个顺序来:

原创内容,盗版必究。【本文受版权保护】【作者:唐霜】著作权归作者所有,禁止商业用途转载。

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

本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】

然后抽象刷新策略映射表,把页面里的面条逻本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。辑收拢。再接入页面运行时,实现忙态轮询和【访问 www.tangshuang.net 获取更多精彩内容】【原创内容,转载请注明出处】闲态消息唤醒。加上 in-flight 【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。合并和软超时兜底之后,系统的可靠性就基本转载请注明出处:www.tangshuang.net本文版权归作者所有,未经授权不得转载。有保障了。

【本文首发于唐霜的博客】【本文首发于唐霜的博客】本文版权归作者所有,未经授权不得转载。

最后补观测指标和报警,做灰度验证,对比改本文版权归作者所有,未经授权不得转载。【作者:唐霜】造前后的指标变化。千万别跳过灰度——消息【本文受版权保护】【版权所有】唐霜 www.tangshuang.net系统是底层基础设施,全量上线出问题就是全【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。局性的。

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

常见反模式与规避策略

在结束之前,再聊几个我见过的典型反模式,著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。希望你看了能绕开。

本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。

把完整业务对象塞进消息体。 前面说过这个了,再说一遍是因为真的太常【访问 www.tangshuang.net 获取更多精彩内容】【关注微信公众号:wwwtangshuangnet】见了。图一时方便,后面维护的时候就知道什【原创内容,转载请注明出处】【原创内容,转载请注明出处】么叫”牵一发而动全身R【转载请注明来源】本文作者:唐霜,转载请注明出处。21;。

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

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

转载请注明出处:www.tangshuang.net【未经授权禁止转载】

不做去重。 重复通知触发重复请求,重复请求返回重复本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。数据,重复数据触发重复渲染——这条链路每转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。一环都在浪费。

【本文受版权保护】未经授权,禁止复制转载。原创内容,盗版必究。

任务结束只靠单一信号判断。 比如只看”任务状态变成了 【原创内容,转载请注明出处】【本文首发于唐霜的博客】completed”,但如果本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】这条消息丢了呢?或者来了但被去重逻辑误判未经授权,禁止复制转载。【未经授权禁止转载】了呢?必须有兜底手段。

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

用固定高频轮询覆盖所有场景。 不管有没有任务在跑,都 3 秒轮询一次【原创不易,请尊重版权】【版权所有,侵权必究】。这是偷懒的做法,对用户、对服务器都不友【作者:唐霜】转载请注明出处:www.tangshuang.net好。

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

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

著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】【作者:唐霜】

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

【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net原创内容,盗版必究。

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

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

2026-05-29 602

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

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