发布订阅模式如何实现,发布订阅与观察者模式区别

发布订阅模式是一种通过中间代理层彻底解耦消息发送者和接收者的设计模式,广泛应用在事件驱动架构和消息队列系统中,能显著提升系统的灵活性和可扩展性。

发布订阅模式是什么?和观察者模式对比有什么不同?

很多人把发布订阅模式和观察者模式混为一谈,但它们在使用场景和耦合度上差异明显,发布订阅模式的核心是引入一个事件通道或消息代理,发布者不直接发送消息给订阅者,而是将消息发布到通道,由通道负责路由给所有订阅该主题的接收者,订阅者也不需要知道发布者的存在,只需声明自己感兴趣的主题即可。

「观察者模式」与「发布/订阅模式」,你分得清楚吗?
加载中
「观察者模式」与「发布/订阅模式」,你分得清楚吗?

观察者模式与发布订阅模式的本质区别

观察者模式中,被观察者直接持有观察者的引用,当状态变化时遍历调用通知,这种设计是直接通知,两者之间仍然存在依赖,而发布订阅模式完全切断这种依赖,双方都只与代理交互。

特性 观察者模式 发布订阅模式
耦合度 发布者知道订阅者,订阅者知道发布者 发布者和订阅者完全不知道彼此
通信方式 直接调用 通过消息代理异步传递
扩展性 随着订阅者增多,发布者修改压力大 发布者无感知,代理可水平扩展
典型实现 事件监听(如Java的Observable) 消息队列(如RabbitMQ、Kafka)

从实际项目选型来看,如果你只是需要单个对象内部的状态广播,观察者模式就够用了,但一旦涉及分布式系统、跨服务通信或者需要高吞吐量和异步处理,发布订阅模式是更稳妥的选择,业内专家指出,在微服务架构中,超过80%的异步通信场景都会选择基于发布订阅模式的消息中间件来降低服务间的直接耦合。

发布订阅模式的工作原理拆解

发布订阅模式包含三个角色:发布者、代理、订阅者,发布者产生消息,定义好主题标签;代理维护主题与订阅者的映射关系,并负责消息的存储和转发;订阅者预先注册自己感兴趣的主题,当消息到达时收到通知,整个过程是异步的,发布者不需要等待订阅者处理完成,订阅者也可以在不同时间消费消息,这种设计让系统更容易应对突发流量,因为代理可以缓存消息,等订阅者空闲时再推送。

发布订阅模式如何实现,发布订阅与观察者模式区别

发布订阅模式使用场景有哪些?实际项目怎么选?

发布订阅模式的使用场景非常广泛,从前端交互到后端数据流都能见到它的身影,选择它而不是其他模式,通常是因为系统需要应对动态变化的订阅关系、异步处理以及跨模块通信。

典型场景:事件驱动与消息队列

  • 前端事件系统:浏览器中的DOM事件机制就是典型的发布订阅模式,用户点击按钮时,浏览器自动触发事件,所有注册的处理函数依次执行,元素之间没有直接耦合。
  • 微服务异步通信:订单服务创建订单后,通过消息队列发布“订单已创建”事件,库存服务、通知服务、积分服务各自订阅该事件并执行后续操作,服务间不需要知道彼此的地址和接口,只需要约定好消息格式。
  • 日志收集与监控:各个服务将日志发布到统一主题,日志收集系统作为订阅者实时获取并聚合分析,避免直接写入文件导致的性能瓶颈。
  • 实时数据推送:股票行情、社交动态等需要实时更新的场景,服务器将变化数据推送到消息通道,客户端通过长连接订阅并更新界面。

根据项目规模选择实现方式

如果你在单体应用或小型项目中实现发布订阅模式,可以自己编写一个轻量级的事件总线,使用内存队列和回调函数即可,但一旦系统涉及跨进程、跨网络通信,就需要引入成熟的消息中间件,行业共识认为,RabbitMQ适合中小规模、需要灵活路由的场景,Kafka更适合高吞吐、日志场景,而Redis的Pub/Sub功能则适合快速搭建原型或低延迟透传,选择时不必纠结于“哪个最好”,而是看你的业务对消息持久化、消费顺序、吞吐量的要求,如果消息丢失会导致严重问题,就应该选择支持持久化的消息队列,而不是简单的内存队列。

发布订阅模式的优缺点分析

多数情况下,发布订阅模式能带来架构上的灵活性,但也会引入额外的复杂性,了解这些权衡,才能决定是否在项目中采用。

核心优势

  • 完全解耦

    发布订阅模式如何实现,发布订阅与观察者模式区别

    :发布者和订阅者不直接依赖,可以独立开发、部署和扩展,新增一个订阅者只需要注册新服务,不需要修改发布者代码。

  • 异步处理提升响应速度:发布者发送消息后立即返回,后续处理由订阅者异步完成,前台请求的响应时间大幅缩短。
  • 支持一对多广播:一条消息可以被多个订阅者同时消费,无需发布者重复发送,这在通知、日志等场景中非常高效。
  • 扩展性好:代理可以独立扩展,支持水平分片来提高吞吐量,发布者无须感知负载变化。

潜在问题

  • 消息可能丢失:如果代理宕机或订阅者处理失败,消息可能丢失,需要引入确认机制和重试策略。
  • 调试和追踪困难:消息流不再靠代码调用链,而是通过代理传递,出现问题时很难定位是发布者、代理还是订阅者的问题。
  • 消息顺序性难保证:在分布式环境下,消息到达顺序可能和发送顺序不一致,对顺序敏感的业务需要额外处理。
  • 系统复杂度增加:引入消息代理意味着多了一个维护点,需要处理网络延迟、消息积压等问题。

从实际项目经验看,发布订阅模式更适合业务逻辑相对独立、不需要强一致性的场景,如果系统要求实时强一致,比如金融交易,直接使用发布订阅模式可能会带来风险,通常需要结合分布式事务或最终一致性方案。

发布订阅模式实例:实现一个简单的发布订阅系统

理解概念最好的方式是自己动手实现一个最小版本,这里我们用伪代码演示核心逻辑,关键步骤拆解如下:

核心组件:事件总线

  1. 定义事件通道对象:用于存储主题和订阅者列表的映射关系。
  2. 实现订阅方法:接收主题和回调函数,将回调函数添加到对应主题的队列中。
  3. 实现发布方法:接收主题和消息数据,遍历该主题的所有订阅者,逐个调用回调函数,可异步执行。
  4. 实现取消订阅方法:从主题列表中移除指定的回调函数,避免内存泄漏。

操作路径

  • 初始化:创建一个空对象 events = {}。
  • 订阅:subscribe(topic, callback) →

    发布订阅模式如何实现,发布订阅与观察者模式区别

    events[topic] 不存在,则初始化为空数组,然后将 callback 加入数组。

  • 发布:publish(topic, data) → 获取 events[topic],遍历数组,对每个 callback 执行 callback(data)(可包裹在 setTimeout 或 Promise 中实现异步)。
  • 取消订阅:unsubscribe(topic, callback) → 过滤掉数组中的该回调。

实际项目中的注意事项

  • 避免回调地狱:在发布订阅中使用异步回调时,要注意控制并发,避免回调嵌套过深,可以使用 async/await 或消息队列的中间件机制。
  • 内存管理:订阅者不再需要时一定要取消订阅,否则会形成闭包引用,导致内存泄漏,在组件销毁或服务关闭时,主动清理注册的订阅。
  • 错误隔离:单个订阅者的回调异常不应影响其他订阅者,应该用 try...catch 包裹每个回调的调用,避免整个发布过程崩溃。

发布订阅模式常见问题

发布订阅模式如何保证消息不丢失?

消息丢失通常发生在三个环节:发布者到代理的传输、代理内部存储、代理到订阅者的传输,在发布者端,使用消息确认机制(如RabbitMQ的发布确认)确保消息被代理接收,在代理端,开启持久化,将消息写入磁盘,即使宕机也能恢复,在订阅者端,手动确认消费成功后再通知代理删除消息,如果处理失败,消息会重新入队,这样三层保障下,消息丢失概率极低。

发布订阅模式适合所有场景吗?

不是,如果系统内模块依赖关系简单,且消息量不大,直接调用或观察者模式更轻量,引入发布订阅会过度设计,对实时性要求极高且需要严格顺序的场景,比如实时交易撮合,发布订阅的异步特性可能引入延迟和乱序,此时需要更复杂的控制机制。

发布订阅模式实现时需要注意哪些性能问题?

主要关注消息积压和回调执行效率,代理的消费能力如果跟不上发布速度,消息会积压,导致内存或磁盘爆满,需要设置合理的队列长度和限流策略,订阅者回调应尽量异步且轻量,避免在回调中执行耗时操作,否则会阻塞后续消息的消费,如果订阅者数量巨大,考虑使用线程池或并发消费模型,同时监控代理的吞吐量指标,及时扩容。

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://test.idctop.com/article/588131.html

赞 (0)
我的世界2b2t服务器外挂怎么用?,2b2t外挂哪个好用?
上一篇 2026年8月21日 02:20
如何正确发送蓝牙数据和多媒体数据,有哪些方法?
下一篇 2026年8月21日 02:21

相关推荐

  • 野草云双11香港VPS年付83元起值得买吗,香港服务器租用价格

    2026年双11期间,野草云凭借香港BGP网络VPS年付83元起的极致性价比,以及香港国际线路年付79美元起的稳定通道,成为中小站长和企业搭建海外业务的首选方案,其独立服务器199元/月起的配置更是满足了高并发场景的需求,在云计算市场竞争日益白热化的2026年,选择海外节点服务器不再仅仅是为了“出海”,更是为了……

    2026年6月28日
    1200
  • 服务器异步通知客户端如何实现?,工作原理是什么?

    服务器异步通知客户端是现代分布式架构中实现实时数据传递的核心手段,它通过WebSocket、Server-Sent Events(SSE)及HTTP长轮询等技术,替代了低效的客户端轮询模式,在兼顾资源消耗与时效性的前提下,为支付回调、消息推送、监控看板等场景提供了可靠的通信基础,服务器异步通知客户端实现方式对比……

    2026年7月16日
    2500
  • 发国际短信的系统哪个好,国际短信群发平台哪个靠谱?

    发国际短信的系统,是连接企业与海外用户的关键通信桥梁,选型时需重点考察通道稳定性、到达率和价格透明度,发国际短信的系统怎么选?在选择发国际短信的系统时,你会发现市场上有很多平台,但真正适合你业务的并不多,以下几个维度需要重点考量,通道覆盖与稳定性系统的通道决定了短信能否到达,优秀的系统会采用全球直连或多通道轮询……

    2026年7月28日
    600
  • 个人网站能挂广告吗,个人网站挂广告赚钱吗

    个人网站能挂广告吗?对于许多独立博主、技术爱好者以及小型内容创作者而言,建立个人网站不仅是展示自我的窗口,更是实现流量变现的重要途径,在决定接入广告联盟或自行投放广告之前,核心问题往往指向一个被忽视的基础设施因素:服务器性能与稳定性,许多新手站长在遭遇广告加载缓慢、页面崩溃或账号被封禁时,往往第一时间怀疑广告策……

    2026年7月4日
    16400
  • SQL数据库上传云服务器失败怎么办,是什么原因?

    SQL数据库上传到云服务器失败,本质上是连接、权限、格式或资源四类问题中的一种,按顺序排查即可解决,许多人在本地测试环境一切正常,一到云服务器就报错,多半不是SQL文件本身坏了,而是云端环境和本地差异导致的,下面直接进入正题,按故障概率从高到低拆解,数据库迁移到云服务器报错时,这些排查顺序最有效先别急着反复重传……

    2026年8月22日
    300
  • 服务器主机能当普通电脑用吗,性能怎么样?

    服务器主机完全可以作为普通电脑使用,但需要额外配置独立显卡和操作系统,且存在噪音大、功耗高的问题,不推荐作为日常办公主力机,在用例管理系统中直接新建用例进行功能验证是高效且标准化的做法,尤其适合测试服务器主机各项功能是否正常,服务器主机做普通电脑的可行性分析硬件差异与兼容性CPU架构:服务器主机通常搭载Inte……

    2026年8月9日
    300
  • ecshop app开发哪家好?ecshop app开发费用明细

    在移动互联网主导商业流量的当下,将PC端商城系统向移动端迁移已成为企业转型的必经之路,Ecshop app 开发的核心价值在于通过原生或混合开发技术,实现电商系统数据与移动端用户体验的无缝对接,从而显著提升用户留存率与转化率, 传统的WAP触屏版已无法满足现代消费者对流畅度、交互体验及功能深度的需求,构建独立的……

    2026年3月16日
    8900
  • 如何选择最适合初学者的web应用程序开发在线教程?

    Web应用程序开发实战指南 认识现代Web应用现代Web应用已从简单的静态页面演变为功能强大、交互丰富的动态平台(SPA、PWA),其核心在于前后端分离架构:前端负责用户界面与交互逻辑,通过API与后端通信;后端处理业务逻辑、数据存取与安全;数据库持久化存储信息,这种架构提升了开发效率和可维护性, 技术栈选型……

    2026年2月6日
    15940
  • 广州虚拟主机试用3天怎么申请?广州虚拟主机哪家好

    广州虚拟主机试用3天欢迎来电,这是2026年检验底层算力与网络连通性最直接的零成本试错路径,通过实测华南BGP节点延迟与IOPS并发,精准规避建站资源错配风险,为什么2026年企业更倾向先试后买?算力内卷下的选择困境根据中国信通院2026年《云计算白皮书》数据显示,华南地区IDC服务商数量较三年前增长37%,同……

    2026年4月26日
    5200
  • js忘记tbody追加和追加上传怎么解决?,如何实现

    “js忘tbody追加”本质是DOM操作未正确创建tbody元素,而追加上传(Node.js SDK)则是实现大文件断点续传的关键技术,两者虽属不同领域,但都涉及“追加”操作,以下分别给出解决方案与实现步骤,js忘tbody追加:表格操作中的隐蔽陷阱错误表现:表格数据无法正常显示当你通过JavaScript向H……

    2026年8月5日
    400

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注