沃尔玛基于前后端的消息通知框架介绍和源码
ccwgpt 2024-11-15 17:07 22 浏览 0 评论
微服务是一种流行的设计模式,其中一个大型应用程序被分解为多个独立且松散耦合的服务,这些服务通过预定义的接口相互通信;Walmart 的ML平台使用相同的原理构建: 部署在 Kubernetes 集群中的独立服务通过 REST API 进行通信。
作为平台功能,为事件提供以用户为目标的通知是一项优先要求。为此,我们开发了一个模型框架,可供任何对通知服务感兴趣的基于微服务的应用程序使用。
在较高级别上,系统应该能够根据以下规则生成和处理通知。
- 每个服务都可以独立生成针对一个用户或一组用户的通知。
- 针对用户的所有通知都将存储在通知存储中
- 对于在线用户,通知消息应立即在 UI 中弹出。对于离线用户,一旦他们登录,通知应该在通知托盘中可用。
- 用户可以将通知标记为已读或删除旧通知。
- 如果需要,系统还可以选择清除旧通知。
除了所需的规则外,我们还向系统添加了一些所需的功能:
- 系统不应给微服务带来重大负担。
- 系统应该是快速且相当稳定的。
- 虽然丢失通知是不可取的,但可以稍微延迟发送它们。
我们将整个系统设计为一个基于 Java 的库,可以将其导入任何有兴趣发送通知的微服务中。对于通知存储,Redis 是首选,服务器发送事件 (SSE) 用于将通知发送到 UI 客户端(用户的浏览器)。我们将在后续部分中分别介绍每个系统,然后将它们放在一起,看看它们是如何加起来完成此功能的。
后端实现
1. 通知模型
通知结构的一个非常简单的设计需要两个字段——目标用户和消息。这是我们最初采用的结构,随着功能开始成熟,添加了更多字段以增强界面并在数据结构中捆绑更多信息。最后,我们正式确定了这种通知结构。
|
2. 存储通知
在 Notification Store 中存储通知有两个要点需要考虑:
- 给定通知,应该很容易将其推送到存储
- 给定用户,应该很容易从存储获取他们的通知。
作为键值存储的 Redis 以毫秒级的延迟完成了这两项任务。此外,Redis 已被证明具有故障恢复能力和高度可扩展性。因此,它被选为通知的后备存储。
此外,Redis 具有对更高 ADT 的内置支持,例如列表和映射。我们利用映射(即 Redis 中的哈希)来存储通知。对于每个用户,存储通知 JSON 的相应通知 id 哈希值。每个唯一的用户 ID 都充当 Redis 中的一个键。这种结构确保支持系统中的 232 个用户,每个用户都有 232 个潜在的通知。
Redis 可以以线程安全的方式支持高并发工作负载。它还可以通过 Redis Sentinels 提供生产级支持以实现高可用性和 AOF 文件备份以实现持久性。有关于如何设置它们以运行生产级 Redis 集群的优秀文档(请参阅Redis Sentinel和Redis Persistence)。
3.推送通知到存储
通知库公开了NotifierClient具有notifyUsers和notifyGroup方法的接口。要触发通知,微服务将notifyUsers使用Notification对象和要向其发送通知的用户 ID 列表调用该方法。该库还允许创建可用于将相似用户(例如,特定项目的所有用户、使用 GPU 的所有用户等)聚集在一起的组,并且微服务可以选择使用notifyGroup方法向整个组发送通知。
Jedis是 Java 中最著名的与 Redis 通信的库,我们在库中使用它来读写通知。Jedis 支持 Sentinel 支持和连接池等高级功能,这也使其成为生产服务器的理想选择。
为了防止读取和写入偶尔中断,对 Redis 的调用通过Resilience4J 进行包装,以确保在出现临时故障时进行正确的重试和错误处理。
前端实现
为了启用前端,我们使用 Express 服务器作为用户浏览器和后端微服务之间的中间件来执行身份验证和会话管理。我们搭载在这个服务器上从 Redis 读取通知并将它们推送给用户。
1. 将通知推送到浏览器
服务器发送事件 (SSE) 是一种建立在 HTTP 之上的技术。对于登录到系统的每个用户,我们在用户会话期间建立一个持久的 HTTP 连接。SSE 的协议规范规定将 JSON 数据转换为字符串,并且每个事件以两个换行符结尾。
建立连接后,我们利用 Node.js 事件模型在 Redis 提供新通知时将数据推送到客户端。我们发出一个通知事件,该事件附加到 HTTP SSE 处理程序范围内的事件侦听器。我们使用登录用户的唯一 id 将来自 Redis 的消息与用户的连接进行匹配。
这个GitHub 代码片段描述了它是如何完成的。
2.在浏览器中接收通知
在客户端,SSE 提供了一个 EventSource API,允许我们连接到服务器并从它接收更新。SSE 有一个限制,它可以同时支持六个并发连接。由于我们在每个浏览器选项卡中打开一个新连接,因此它限制了我们的用户一次只能打开六个选项卡。为了规避这个限制,我们使用SharedWorkers。这使我们能够在 SharedWorker 中创建一个持久连接,并通过不同的浏览器选项卡和 iframe 访问它。
共享工作者SharedWorker的一个缺点是它在 Safari 和 IE 上不受支持,但由于我们的大多数用户群都在 Chrome 和 Firefox 上,因此这被视为可接受的解决方案。如果用户使用 IE 或 Safari,我们将退回到仅允许 6 个选项卡的 SSE 模型。
当用户第一次登录时,会实例化一个新的共享工作者实例,然后将其附加到窗口实例。然后可以在所有浏览器上下文中访问它。然后,网页可以使用 MessagePort 对象与共享 worker 通信,并附加一个事件处理程序,每次共享 worker 推送消息时都会调用该处理程序。
github中的以下代码段具有在浏览器中接收通知的代码。
3. 向用户显示通知
每次打开新选项卡或浏览器窗口时,共享工作者都会为每个新选项卡分配一个端口号。这些端口号为每个用户保存在一个数组中。每当生成新通知时,都会将其推送到所有端口,以使其在选项卡之间保持一致。关闭选项卡时beforeUnload会触发一个事件,在该事件中我们从阵列中删除相应的端口。
为了仅当用户在选项卡上处于活动状态时才显示通知,我们处理visibilitychange由Page Visibility API公开的事件。处理程序将页面标记为非隐藏,然后使用来自后端的通知刷新 redux 存储。这会触发 UI 的渲染,并且通知显示在小吃栏中。
桥接后端和前端
系统的两个部分协同工作以提供整个通知系统:
- 一组后端服务——生成通知并将它们持久化到 Redis
- UI 负责向用户显示通知,无论是在用户在线时实时显示,还是在用户上线时作为错过的通知列表。
- 后端到前端——通过 Redis PubSub
对于实时场景,新的通知一生成就需要通知 UI。我们使用 Redis PubSub 创建从后端服务到 UI 服务器的反馈通道,然后如所述通过 HTML5 SSE 与 UI 客户端(或用户的浏览器)进行通信。
当生成通知并将通知写入用户的密钥时,库还会在特定频道上生成一条 PubSub 消息,其中相应的用户 ID 已被修改。UI 服务器订阅给定的 PubSub 频道,并在接收到用户 ID 时在其内存中构建通知映射。如果用户在线,UI 服务器会在该用户的 SSE 套接字上发送整个通知 JSON 映射,以在他的浏览器中呈现它。
下面给出了一个粗略的序列图,用于演示通知实例从在后端服务中生成到向用户显示的流程。
- 前端到后端——通过 REST
一旦用户响应通知(阅读、点击或删除它),该信息必须流经后端存储。我们将其实现为 REST 端点。
该库本身公开了一个 Java API,它可以采用唯一的通知 id、用户 id 和要更新的状态,并且它将用更新的状态修补 Redis 中的通知。然后可以使用服务将这个 API 与 REST 或任何其他类似(例如 gRPC)端点包装在一起。
为了清除 Redis 中过期和删除的通知,库内部使用了Quartz调度程序。为了确保一次只运行一个清洁器实例,使用Redlock 算法来创建分布式锁定机制。
整个框架可在https://github.com/daichi-m/notification4J 上作为库使用。
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)