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

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

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

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

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

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

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

特性 观察者模式 发布订阅模式
耦合度 发布者知道订阅者,订阅者知道发布者 发布者和订阅者完全不知道彼此
通信方式 直接调用 通过消息代理异步传递
扩展性 随着订阅者增多,发布者修改压力大 发布者无感知,代理可水平扩展
典型实现 事件监听(如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://idctop.com/article/588131.html

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

相关推荐

  • 公安人脸识别技术如何破案?人脸识别技术有哪些应用场景

    【公安人脸识别技术破案】服务器性能深度评测:高并发下的算力基石与实战效能解析在“天网工程”与智慧城市建设深入推进的背景下,公安人脸识别技术已从单一的安防监控演变为复杂的实时大数据处理系统,这一转变对后端基础设施提出了极其严苛的要求:低延迟、高吞吐、强稳定性成为核心指标,本文将以某主流高性能GPU服务器为例,深入……

    2026年6月23日
    1700
  • 将日志存到MySQL数据库后如何查询慢日志?,有哪些优化方法?

    将MySQL慢查询日志持久化到数据库表中,是进行高效分析和长期存储的最佳实践,本文详细讲解配置步骤、查询方法及优化技巧,帮助你快速定位性能瓶颈,MySQL慢查询日志如何存储到数据库表开启慢日志并将输出指向表,是配置的第一步,这个过程涉及几个关键参数,需要逐一确认,开启慢日志并设置输出方式确保慢查询日志功能已开启……

    2026年8月1日
    600
  • 嵌入式开发代码怎么写,嵌入式C语言编程实例教程

    编写高质量嵌入式系统的核心在于在受限的硬件资源下,通过严谨的架构设计、精细的内存管理以及高效的实时控制策略,实现系统的高可靠性与高稳定性,这不仅要求开发者对底层硬件有深刻理解,更需要在代码层面遵循严格的工程规范,以确保系统在长期运行中具备极强的鲁棒性,构建分层解耦的软件架构优秀的嵌入式开发代码必须建立在清晰的分……

    2026年2月23日
    12400
  • 服务器双线配置与服务器配置的区别是什么,如何选择?

    服务器双线配置是通过同时接入电信和联通两条线路,直接解决南北互通延迟问题的核心方案,尤其适合用户覆盖全国的中型网站、视频平台和游戏服务器,双线配置的核心价值在于避免单线机房带来的地域访问瓶颈,如果你遇到北方用户访问顺畅、南方用户却频繁卡顿的情况,说明你的服务器需要调整网络架构,双线方案分为智能DNS、双IP和B……

    2026年8月20日
    600
  • M1通信网站内容是什么?M1通信模块使用方法

    关于m1通信的网站内容在云计算基础设施竞争日益激烈的当下,服务器性能、网络稳定性以及售后响应速度是衡量服务商核心竞争力的关键指标,我们对主流云服务商进行了深度实测,其中M1通信凭借其在底层架构优化与网络带宽调度上的独特优势,在2026年的市场环境中展现出了极强的竞争力,本文将从实测数据、网络延迟、业务场景适配及……

    2026年6月14日
    3200
  • Greenwebpage日本加拿大VPS怎么样?2.99欧元VPS实测性能值得买吗

    在当前的建站与业务部署环境中,选择具备高性价比与网络稳定性的VPS至关重要,Greenwebpage近期推出的日本与加拿大VPS套餐,以2.99欧元/月的起步价格吸引了众多开发者的关注,本文将基于真实的长期挂机测试数据,从硬件性能、网络质量、磁盘IO及路由节点等维度,对这两款VPS进行深度剖析,为您的选购提供客……

    2026年4月29日
    7900
  • K8s拓扑分布怎么配置?k8s topology spread constraints详解

    K8s Topology拓扑分布在容器化架构日益复杂的今天,Kubernetes (K8s) 的调度策略直接决定了业务的稳定性与资源利用率,Topology Spread Constraints(拓扑分布约束) 是K8s 1.19版本引入的关键特性,它允许管理员根据特定的拓扑域(如节点、可用区、机架等)来控制P……

    2026年7月10日
    9600
  • 井下矿山如何建设智慧矿山?智慧矿山建设方案有哪些

    关于井下矿山建设智慧矿山的思考在数字化转型的浪潮下,井下矿山正经历从“自动化”向“智能化”的深刻变革,物联网传感器、5G通信、边缘计算与大数据分析技术的深度融合,使得实时监测、远程操控和预测性维护成为可能,智慧矿山的核心瓶颈往往不在于前端感知设备的精度,而在于后端数据处理与存储基础设施的稳定性、低延迟特性以及高……

    2026年6月7日
    3800
  • 服务器设置阵列选项如何设置?什么是阵列关联?

    阵列选项之间并非独立存在,它们通过“磁盘组—虚拟磁盘—热备盘”三层结构互相约束,配置时必须先明确业务对性能和冗余的需求,再按“创建磁盘组→定义虚拟磁盘→设置缓存与回写策略→绑定热备盘”的顺序逐层关联,任何一层选项改动都会引发后续层级的联动变化,阵列选项之间到底怎么关联?刚接触服务器阵列时,大多数运维人员的第一反……

    2026年8月12日
    1300
  • 服务器白名单到底在哪个位置,怎么设置才有效

    服务器白名单的具体位置取决于你使用的操作系统和服务类型,通常在防火墙规则、应用配置文件或管理后台中,例如Linux系统通过iptables或firewalld配置,Windows Server在高级安全防火墙中设置,数据库如MySQL和Redis则在配置文件中指定IP白名单,服务器白名单在哪里设置?从系统到应用……

    2026年7月30日
    1600

发表回复

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