Direct vs. Topic vs. Fanout: Den richtigen Exchange-Typ wählen

Wählen Sie RabbitMQ Direct-, Topic- oder Fanout-Exchanges basierend auf exaktem Routing, Wildcard-Routing oder Broadcast-Zustellung.

Direct vs. Topic vs. Fanout: Den richtigen Exchange-Typ wählen

Der Exchange-Typ in RabbitMQ bestimmt, wohin Ihre Nachrichten gelangen, nachdem ein Produzent sie veröffentlicht hat. Wählen Sie den falschen Exchange und Sie könnten private Arbeiten ausstrahlen, Nachrichten mit nicht übereinstimmenden Routing-Keys verlieren oder Routing-Regeln fest codieren, die später schmerzhaft werden.

Die praktische Wahl ist einfach: Verwenden Sie direct für exaktes Routing, fanout für Broadcast und topic für Wildcard-Routing über ein Benennungsschema.

Wie RabbitMQ-Routing funktioniert

Ein Produzent veröffentlicht an einen Exchange, nicht direkt an eine Queue. Der Exchange vergleicht den Nachrichten-Routing-Key mit Queue-Bindungen und leitet die Nachricht dann gemäß dem Exchange-Typ weiter.

Drei Begriffe sind wichtig:

  • Exchange: empfängt veröffentlichte Nachrichten.
  • Queue: speichert Nachrichten, bis Verbraucher sie empfangen.
  • Binding: verbindet eine Queue mit einem Exchange, manchmal mit einem Binding-Key.

Wenn keine Queue übereinstimmt und die Nachricht nicht als mandatory markiert ist, kann RabbitMQ die nicht routbare Nachricht verwerfen. Verwenden Sie für wichtige Abläufe Publisher Confirms und behandeln Sie zurückgesendete Nachrichten.

Direct Exchange

Ein Direct Exchange leitet eine Nachricht an Queues weiter, deren Binding-Key exakt mit dem Nachrichten-Routing-Key übereinstimmt.

Verwenden Sie ihn, wenn die Routing-Entscheidungen bekannt und präzise sind. Gute Beispiele sind Log-Schweregrade, Aufgabentypen oder mandantenspezifische Queues, bei denen exakte Namen ausreichen.

Zum Beispiel binden Sie error_queue mit error und info_queue mit info. Eine mit dem Routing-Key error veröffentlichte Nachricht geht an error_queue; eine mit info an info_queue. Wenn zwei Queues mit error binden, erhalten beide Queues eine Kopie. Verbraucher auf derselben Queue konkurrieren weiterhin um Nachrichten aus dieser Queue.

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs_direct', exchange_type='direct')

channel.basic_publish(
    exchange='logs_direct',
    routing_key='error',
    body=b'Datenbankverbindung fehlgeschlagen'
)

connection.close()

Wählen Sie Direct, wenn Ihre Routing-Keys stabil sind und Sie kein Wildcard-Matching benötigen.

Fanout Exchange

Ein Fanout Exchange leitet jede Nachricht an jede Queue weiter, die an den Exchange gebunden ist. Er ignoriert den Routing-Key.

Verwenden Sie ihn für Broadcast-Ereignisse, bei denen jeder Abonnent dieselbe Nachricht erhalten soll. Häufige Fälle sind Cache-Invalidierung, Ereignisse zu aktualisierten Benutzerprofilen, Bereitstellungsbenachrichtigungen oder Echtzeit-Statusaktualisierungen.

Zum Beispiel könnte ein user_updates Fanout Exchange drei Queues speisen: email_queue, search_index_queue und analytics_queue. Ein veröffentlichtes Profil-Update erreicht alle drei Dienste.

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='user_updates', exchange_type='fanout')

channel.basic_publish(
    exchange='user_updates',
    routing_key='',
    body=b'Benutzer 123 hat seinen Anzeigenamen geändert'
)

connection.close()

Wählen Sie Fanout, wenn die Routing-Logik keine Rolle spielt und jede gebundene Queue eine Kopie erhalten soll.

Topic Exchange

Ein Topic Exchange routet durch Abgleich von punktgetrennten Routing-Keys mit Wildcard-Binding-Keys. Er bietet flexibles Routing, ohne für jeden Ereignistyp einen anderen Exchange erstellen zu müssen.

Topic-Bindungen verwenden zwei Wildcards:

  • * entspricht genau einem Wort.
  • # entspricht null oder mehr Wörtern.

Zum Beispiel mit Routing-Keys wie order.created.us und order.cancelled.eu:

  • order.*.us entspricht einer Aktion für US-Bestellungen.
  • order.created.# entspricht erstellten Bestellungen in allen Regionen und optionalen zusätzlichen Wörtern.
  • #.eu entspricht Ereignissen, die auf eu enden.
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='events_topic', exchange_type='topic')

channel.basic_publish(
    exchange='events_topic',
    routing_key='order.created.us',
    body=b'Bestellung 9001 erstellt'
)

connection.close()

Wählen Sie Topic, wenn Verbraucher gefilterte Teilmengen eines größeren Ereignisstroms benötigen, wie z.B. service.environment.severity, entity.action.region oder tenant.event.priority.

Kurze Entscheidungshilfe

Bedarf Exchange-Typ Beispiel
Exaktes Match-Routing Direct error, invoice.created
Broadcast an jeden Abonnenten Fanout Cache-Purge-Ereignis
Wildcard-Routing Topic orders.*.us, logs.#

Vermeiden Sie es, einen Topic Exchange als Ablage für inkonsistente Routing-Keys zu verwenden. Wählen Sie frühzeitig eine Namenskonvention, dokumentieren Sie sie und halten Sie die Wörter von breit zu spezifisch oder von Entität zu Aktion geordnet, je nachdem, wie Ihre Verbraucher filtern.

Fazit

Verwenden Sie Direct Exchanges für exakte Ziele, Fanout Exchanges für Broadcast und Topic Exchanges, wenn Verbraucher Wildcard-Filter benötigen. Wenn Sie die Route als ein exaktes Label beschreiben können, verwenden Sie Direct. Wenn jeder die Nachricht benötigt, verwenden Sie Fanout. Wenn Abonnenten Muster benötigen, verwenden Sie Topic.