Publish Subscribe


Overview

The Essence of Publish-Subscribe

Historically, software components interacted primarily through explicit, synchronous procedure calls—Component A directly invokes a specific method on Component B. However, as systems scaled and became increasingly distributed, this tight coupling proved fragile and difficult to evolve. The publish-subscribe architectural style (often referred to as an event-based style or implicit invocation) emerged as a fundamental paradigm shift to resolve this fragility (Garlan and Shaw 1993).

In the publish-subscribe style, components interact via asynchronously announced messages, commonly called events. The defining characteristic of this style is extreme decoupling through obliviousness. A dedicated component takes the role of the publisher (or subject) and announces an event to the system’s runtime infrastructure. Components that depend on these changes act as subscribers (or observers) by registering an interest in specific events.

The core invariant—the “law of physics” for this style—is dual ignorance:

  1. Publisher Ignorance: The publisher does not know the identity, location, or even the existence of any subscribers. It operates on a “fire and forget” principle.
  2. Subscriber Ignorance: Subscribers depend entirely on the occurrence of the event, not on the specific identity of the publisher that generated it.

Because the set of event recipients is unknown to the event producer, the correctness of the producer cannot depend on the recipients’ actions or availability.

This is the key difference from direct communication. In direct communication, the sender calls a known receiver and can usually detect that the receiver is unavailable. In publish-subscribe, the sender publishes to a topic and moves on. That buys extensibility - new publishers and subscribers can appear without editing existing components - but it also means the publisher cannot rely on some particular subscriber doing the work.

Structural Paradigms: Elements and Connectors

Like all architectural styles, publish-subscribe restricts the design vocabulary to a specific set of elements, connectors, and topological constraints.

The Elements The primary components in this style are any independent entities equipped with at least one publish port or subscribe port. A single component may simultaneously act as both a publisher and a subscriber by possessing ports of both types (Clements et al. 2010).

The Event Bus Connector The true “rock star” of this architecture is not the components, but the connector. The event bus (or event distributor) is an N-way connector responsible for accepting published events and dispatching them to all registered subscribers. All communications strictly route through this intermediary, preventing direct point-to-point coupling between the application components.

The canonical topology looks like this — publishers on one side, the topic in the middle, subscribers on the other. Crucially, no arrow ever crosses directly between a publisher and a subscriber:

Behavioral Variation: Push vs. Pull Models When an event occurs, how does the state information propagate to the subscribers? The literature details two distinct behavioral variations:

  • The Push Model: The publisher sends all relevant changed data along with the event notification. This creates a rigid dynamic behavior but is highly efficient if subscribers almost always need the detailed information.
  • The Pull Model: The publisher sends a minimal notification simply stating that an event occurred. The subscriber is then responsible for explicitly querying the publisher to retrieve the specific data it needs. This offers greater flexibility but incurs the overhead of additional round-trip messages (Buschmann et al. 1996).

Topologies and Variations

While the platonic ideal of publish-subscribe describes a simple bus, embodied implementations in modern distributed systems take several specialized forms:

  1. List-Based Publish-Subscribe: In this tighter topology, every publisher maintains its own explicit registry of subscribers. While this reduces the decoupling slightly, it is highly efficient and eliminates the single point of failure that a centralized bus might introduce in a distributed system.
  2. Broadcast-Based Publish-Subscribe: Publishers broadcast events to the entire network. Subscribers passively listen and filter incoming messages to determine if they are of interest. This offers the loosest coupling but can be highly inefficient due to the massive volume of discarded messages.
  3. Content-Based Publish-Subscribe: Unlike traditional “topic-based” routing (where subscribers listen to predefined channels), content-based routing evaluates the actual attributes of the event payload. Events are delivered only if their internal data matches dynamic, subscriber-defined pattern rules (Bass et al. 2012).
  4. The Event Channel (Gatekeeper) Variant: Popularized by distributed middleware (like CORBA and enterprise service buses), this introduces a heavy proxy layer. To publishers, the event channel appears as a subscriber; to subscribers, it appears as a publisher. This allows the channel to buffer messages, filter data, and implement complex Quality of Service (QoS) delivery policies without burdening the application components.

System Evolution: Quality Attribute Trade-offs

The publish-subscribe style is a strategic tool for architects precisely because it drastically manipulates a system’s quality attributes, heavily favoring adaptability at the cost of determinism.

Promoted Qualities: Modifiability and Reusability The primary benefit of this style is extreme modifiability and evolvability. Because producers and consumers are decoupled, new subscribers can be added to the system dynamically at runtime without altering a single line of code in the publisher. It provides strong support for reusability, as components can be integrated into entirely new systems simply by registering them to an existing event bus (Rozanski and Woods 2011).

Inhibited Qualities: Predictability, Performance, and Testability

  • Performance Overhead: The event bus adds a layer of indirection that fundamentally increases latency.
  • Lack of Determinism: Because communication is asynchronous, developers have less control over the exact ordering of messages, and delivery is often not guaranteed. Consequently, publish-subscribe is generally an inappropriate choice for systems with hard real-time deadlines or where strict transactional state sharing is critical.
  • Testability and Reasoning: Publish-subscribe systems are notoriously difficult to reason about and test. The non-deterministic arrival of events, combined with the fact that any component might trigger a cascade of secondary events, creates a combinatorial explosion of possible execution paths, making debugging highly complex.
  • Robustness for mandatory work: If a sender must know that a specific receiver processed the message, strict publish-subscribe is the wrong default. A brake command, payment authorization, or safety-critical shutdown request may require direct acknowledgment, retry, or a stronger messaging protocol.

Publish-subscribe can also inhibit understandability. A component diagram may show that several components are connected to the same topic, but the diagram alone may not show which publication causes which subscriber action, or whether subscriber actions trigger secondary events. For complex systems, teams often need runtime tracing, topic inventories, contract tests, and live component-and-connector views to recover the causal story.

Real-World Topic Bugs

Robotics systems commonly use publish-subscribe middleware. The Robot Operating System (ROS), MQTT, DDS, and Apache Kafka all impose variants of this style. By adopting one of these frameworks, a team also inherits the quality-attribute trade-offs of the style.

A real Autoware.AI bug illustrates the risk. Autoware.AI is an open-source self-driving-car framework that uses ROS topics. One commit renamed a topic inconsistently: one component published to a new topic name while other components still subscribed to the old topic name. The code compiled, the components still existed, and each local implementation looked reasonable. At runtime, however, the intended message flow was broken because publishers and subscribers were silently attached to different named channels.

This bug is hard because publish-subscribe intentionally removes direct references. The publisher does not know which subscribers should exist, and a subscriber may simply receive no messages without throwing a local error. That is the same decoupling that makes the style extensible. It is also why strict topic naming, schema registries, integration tests, and runtime observability matter in publish-subscribe systems.

Divergent Perspectives and Architectural Smells

A synthesis of the literature reveals critical debates and warnings regarding the implementation of this style.

The “Wide Coupling” Smell While publish-subscribe is lauded for decoupling components, researchers have identified a hidden architectural bad smell: wide coupling. If an event bus is implemented too generically (e.g., using a single receive(Message m) method where subscribers must cast objects to specific types), a false dependency graph emerges. Every subscriber appears coupled to every publisher on the bus. If a publisher changes its data format, a maintenance engineer cannot easily trace which subscribers will break, effectively destroying the understandability the style was meant to provide (Garcia et al. 2009).

The Illusion of Obliviousness vs. Developer Intent There is a divergent perspective regarding the “obliviousness” constraint. While components at runtime are technically ignorant of each other, the human developer designing the system is not. Fairbanks cautions against losing design intent: a developer intentionally creates a “New Employee” publisher specifically because they know the “Order Computer” subscriber needs it. If architectural diagrams only show components loosely attached to a bus, the critical “who-talks-to-who” business logic is entirely obscured (Fairbanks 2010).

The CAP Theorem and Eventual Consistency In modern cloud and Service-Oriented Architectures (SOA), publish-subscribe is often used to replicate data and trigger updates across distributed databases. This forces architects into the trade-offs of the CAP Theorem (Consistency, Availability, Partition tolerance). Because synchronous, guaranteed delivery over a network is prone to failure, architects often configure publish-subscribe connectors for “best effort” asynchronous delivery. This means the system must embrace eventual consistency—accepting that different subscribers will hold stale or inconsistent data for a bounded period of time in exchange for higher system availability and lower latency.

Production Variations and Quality of Service

Production publish-subscribe frameworks offer knobs that relax or strengthen the pure style:

  • Topic-based routing: subscribers register for named channels such as market.quotes.NASDAQ. This is simple and fast, but topic names become part of the architecture.
  • Content-based routing: subscribers express predicates over event contents, such as company == "TELCO" and price < 100. This is more expressive, but matching costs more at the broker.
  • Durable subscriptions: the broker stores messages while a subscriber is disconnected and delivers them later. This improves reliability but adds storage cost and stale-message concerns.
  • Delivery guarantees: frameworks often distinguish “at most once,” “at least once,” and “exactly once” delivery. Stronger guarantees reduce message loss but increase latency, coordination, and duplicate-handling complexity.

These variations are not just middleware configuration. They are architectural decisions because they change the system’s quality profile. A high-frequency telemetry stream may accept occasional loss for lower latency. A billing workflow may need stronger delivery guarantees and idempotent consumers even if that costs throughput.

Framework Examples

Common publish-subscribe technologies include:

  • DDS (Data Distribution Service): used in ROS 2 and other real-time distributed systems.
  • MQTT: a lightweight protocol for low-bandwidth, unreliable, or resource-constrained IoT environments.
  • Apache Kafka: a high-throughput event-streaming platform built around durable logs and partitioned topics.
  • RabbitMQ: message-oriented middleware that supports flexible routing and queue-based delivery.

The framework does not remove the architectural trade-off. It packages one version of the trade-off so that teams can use it consistently.

Publish-Subscribe Quiz and Flashcards

Use these flashcards and quiz questions to check whether you can reason about publisher/subscriber ignorance, event-bus trade-offs, routing variants, delivery guarantees, topic bugs, and the observability needed to make publish-subscribe systems understandable.

Publish-Subscribe Flashcards

Key concepts, structural elements, subscription models, and trade-offs of the publish-subscribe architectural style.

Difficulty: Basic

What is the defining invariant of the publish-subscribe style?

Difficulty: Basic

Name the three architectural elements of a publish-subscribe system.

Difficulty: Basic

What’s the difference between the push and pull notification models in pub-sub?

Difficulty: Intermediate

How does topic-based routing work, and what’s its main trade-off?

Difficulty: Advanced

How does content-based routing work, and what’s its main trade-off?

Difficulty: Advanced

What is the Event Channel (Gatekeeper) variant of pub-sub, and what does it allow?

Difficulty: Intermediate

Why is pub-sub generally a poor fit for systems with hard real-time deadlines?

Difficulty: Advanced

What are the three delivery-guarantee levels pub-sub frameworks typically distinguish, and what is the headline trade-off?

Difficulty: Advanced

What three forms of decoupling does pub-sub provide?

Difficulty: Advanced

What is the wide coupling smell in pub-sub, and how do you avoid it?

Difficulty: Advanced

Name the four pub-sub topologies discussed in the literature.

Difficulty: Intermediate

What is a durable subscription in pub-sub middleware?

Difficulty: Advanced

Compare Apache Kafka and RabbitMQ as pub-sub technologies.

Difficulty: Intermediate

Why does pub-sub force architects to embrace eventual consistency?

Difficulty: Advanced

What is the illusion of obliviousness and why does Fairbanks warn about it?

Difficulty: Basic

Give three real-world examples of publish-subscribe in industry.

Difficulty: Advanced

When should you NOT use publish-subscribe?

Difficulty: Intermediate

Why are topic names architecturally significant in topic-based publish-subscribe?

Publish-Subscribe Quiz

Apply the publish-subscribe style to real architectural decisions — choose between push and pull, diagnose coupling smells, pick QoS levels, and judge when pub-sub is the wrong tool.

Difficulty: Basic

Your team runs an e-commerce backend. A new Recommendations service needs to react to every OrderPlaced event the Checkout service emits. The architect insists no code in Checkout may change to add the new consumer. Which style makes this possible?

Correct Answer:
Difficulty: Intermediate

A real-time stock-trading dashboard pushes PriceChanged events at ~5,000 per second. Subscribers (chart, alert engine, order matcher) all need the new price every tick. The team is choosing between push and pull. Which is correct?

Correct Answer:
Difficulty: Advanced

A pub-sub framework offers three delivery modes: at most once (may lose messages), at least once (may deliver duplicates), and exactly once (stronger protocol coordination, higher latency). A team uses the broker to publish InvoicePaid events to a billing-fulfillment consumer. The consumer is not idempotent, so a duplicate InvoicePaid would charge the customer twice. Loss would mean a paid invoice is never recorded. Latency is acceptable. Which delivery mode fits this exact stem?

Correct Answer:
Difficulty: Expert

Your manager wants to use a typical asynchronous pub-sub bus (e.g., Kafka with default settings) for the money-transfer engine of a retail bank. Transfers must commit in a strictly defined order, must never be lost, and an ops team must be able to trace why any specific transfer failed within seconds. Which of these are legitimate warning signs that this style is the wrong fit as proposed? Select all that apply.

Correct Answers:
Difficulty: Advanced

A microservices team’s bus is implemented with a single method bus.send(Message msg) and every subscriber casts the message to a concrete type. After 18 months the team can no longer answer “what breaks if I change OrderPlaced’s currency field?” without a manual codebase grep. Which architectural smell does this match, and what is the right refactor?

Correct Answer:
Difficulty: Intermediate

A mobile chat app must continue to deliver messages to users whose phones were offline for hours. Which pub-sub feature is the team relying on?

Correct Answer:
Difficulty: Advanced

Your team adopts a content-based pub-sub broker so subscribers can register predicates like region == 'EU' AND amount > 10000. After three months, broker CPU is saturated at 80% and the team is debating switching to topic-based. Under what condition is this switch justified?

Correct Answer:
Difficulty: Advanced

An architect proposes pub-sub for syncing inventory counts across a global e-commerce platform. The product manager pushes back: “we need every region to see the same count instantly so we never oversell.” How should the architect respond?

Correct Answer:
Difficulty: Intermediate

You inherit a system whose architecture diagram shows 20 microservices, each connected by a single arrow to a central “Event Bus” component. After three weeks you still cannot answer “which services break if we change the UserDeleted payload?” What is the root cause of your confusion, per Fairbanks?

Correct Answer:
Difficulty: Advanced

Two designs for an IoT temperature monitor are on the table. Design A: sensors call monitor.report(temp) directly via REST. Design B: sensors publish TempReading to MQTT; the monitor subscribes. The PM says “Design B is obviously more decoupled, so it’s better.” Which counter-argument best frames the honest trade-off?

Correct Answer:
Difficulty: Intermediate

In a robotics pub-sub system, one team renames the publisher topic from line_class to line_topic, but a safety component still subscribes to line_class. Tests compile, both components start, and the safety component silently receives no data. What architectural lesson does this illustrate?

Correct Answer: