Exchangetypen: direct, topic, fanout en headers
Routeer berichten naar de juiste consumers door de geschikte exchange- en bindingstrategie te kiezen.
Exchangetypen: direct, topic, fanout en headers is een gratis Bootcamp backendontwikkeling met Node.js-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Bootcamp backendontwikkeling met Node.js. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Bootcamp backendontwikkeling met Node.js bevat in totaal 4 lessen.
Waarom exchanges bestaan
In RabbitMQ publiceren producers nooit rechtstreeks naar een queue. Ze publiceren naar een exchange, waarna de exchange bepaalt welke queue(s) het bericht ontvangen op basis van bindings en een routing key.
Deze indirecte werkwijze vormt de kern van eventgestuurde routering. Om berichten bij de juiste consumers te krijgen, moet je het juiste type exchange kiezen:
direct— exacte overeenkomst met de routing keytopic— overeenkomst met patronen en jokertekensfanout— verspreiding naar alle gekoppelde queuesheaders— overeenkomst op basis van headerkenmerken van berichten
Als je het verkeerde type kiest, missen consumers berichten of worden ze overspoeld met irrelevante berichten.
Het denkmodel: exchange + binding + routing key
Drie onderdelen werken samen:
- Routing key: een tekenreeks die de producer aan elk bericht toevoegt (bijvoorbeeld
order.created). - Binding: een regel die een exchange met een queue verbindt, vaak met een bindingsleutel.
- Type exchange: het algoritme dat de routing key met de bindings vergelijkt.
De exchange beoordeelt elke binding. Een bericht kan in nul, één of meerdere queues terechtkomen. Als het met geen enkele binding overeenkomt, wordt het verwijderd (tenzij er een alternatieve exchange is geconfigureerd).
In deze voorbeelden gebruiken we overal de bibliotheek amqplib.
// Establishing a channel with amqplib
const amqp = require('amqplib');
async function connect() {
const conn = await amqp.connect('amqp://localhost');
const channel = await conn.createChannel();
return { conn, channel };
}
module.exports = { connect };Direct exchange: exacte overeenkomst
Een direct-exchange bezorgt een bericht aan queues waarvan de bindingssleutel exact gelijk is aan de routing key van het bericht.
Dit is de standaardkeuze wanneer elk berichttype aan een specifieke worker wordt gekoppeld. Een klassiek gebruiksscenario is het routeren van logberichten op ernst (error, warning, info) naar speciale queues.
- Routing key
error→ alleen de queue die meterroris verbonden. - Meerdere queues kunnen dezelfde bindingssleutel delen — allemaal ontvangen ze een kopie.
const amqp = require('amqplib');
async function setupDirect(channel) {
const ex = 'logs_direct';
await channel.assertExchange(ex, 'direct', { durable: true });
const errors = await channel.assertQueue('errors', { durable: true });
await channel.bindQueue(errors.queue, ex, 'error');
const allLogs = await channel.assertQueue('all_logs', { durable: true });
await channel.bindQueue(allLogs.queue, ex, 'error');
await channel.bindQueue(allLogs.queue, ex, 'warning');
await channel.bindQueue(allLogs.queue, ex, 'info');
}
module.exports = { setupDirect };Publiceren naar een direct exchange
De producer geeft de routing key als tweede argument door aan channel.publish(exchange, routingKey, content). De exchange doet de rest.
Hier komt een bericht met routing key error terecht in zowel de queue errors als de queue all_logs uit de vorige scène, terwijl een info-bericht alleen all_logs bereikt.
Let op: de inhoud moet een Buffer zijn.
async function publishLog(channel, severity, message) {
const ex = 'logs_direct';
channel.publish(
ex,
severity, // routing key: 'error' | 'warning' | 'info'
Buffer.from(JSON.stringify({ message, ts: Date.now() })),
{ persistent: true }
);
console.log(`Sent [${severity}] ${message}`);
}
// publishLog(channel, 'error', 'DB connection lost');
module.exports = { publishLog };Topic exchange: overeenkomst met patronen
Een topic-exchange vergelijkt routing keys met bindingspatronen aan de hand van twee jokertekens:
*(sterretje) komt overeen met precies één woord.#(hekje) komt overeen met nul of meer woorden.
Routing keys bestaan uit woorden die door punten worden gescheiden, bijvoorbeeld order.eu.created. Dit is de flexibelste exchange en deze is ideaal voor hiërarchische eventnamen.
order.*.createdkomt overeen metorder.eu.created, maar niet metorder.created.order.#komt overeen metorder.created,order.eu.shippedenzovoort.*.eu.*komt overeen met elk EU-event dat uit drie woorden bestaat.
Topic-bindings instellen
Neem een orderpijplijn. Verschillende services zijn geïnteresseerd in verschillende delen van de eventstroom:
- Een audit-service wil alles:
order.#. - Een service voor EU-compliance wil alleen EU-events:
order.eu.*. - Een shipping-service wil het verzonden event uit elke regio:
order.*.shipped.
Eén gepubliceerd event kan tegelijk aan meerdere patronen voldoen en wordt alleen verspreid naar de geïnteresseerde consumers.
const amqp = require('amqplib');
async function setupTopic(channel) {
const ex = 'orders_topic';
await channel.assertExchange(ex, 'topic', { durable: true });
const audit = await channel.assertQueue('audit', { durable: true });
await channel.bindQueue(audit.queue, ex, 'order.#');
const euCompliance = await channel.assertQueue('eu_compliance', { durable: true });
await channel.bindQueue(euCompliance.queue, ex, 'order.eu.*');
const shipping = await channel.assertQueue('shipping', { durable: true });
await channel.bindQueue(shipping.queue, ex, 'order.*.shipped');
}
module.exports = { setupTopic };Overeenkomsten met topic-patronen analyseren
We volgen welke queues elk event ontvangen bij de bindings order.# (audit), order.eu.* (EU), order.*.shipped (shipping).
order.eu.created→ audit + EUorder.us.shipped→ audit + shippingorder.eu.shipped→ audit + EU + shippingorder.created→ alleen audit (er staat maar één woord naorder, dusorder.eu.*enorder.*.shippedkomen niet overeen)
Deze helper in pure JavaScript bootst het algoritme voor topic-overeenkomsten na, zodat je je patronen offline kunt controleren.
function topicMatch(pattern, key) {
const p = pattern.split('.');
const k = key.split('.');
function rec(pi, ki) {
if (pi === p.length) return ki === k.length;
if (p[pi] === '#') {
for (let skip = ki; skip <= k.length; skip++) {
if (rec(pi + 1, skip)) return true;
}
return false;
}
if (ki < k.length && (p[pi] === '*' || p[pi] === k[ki])) {
return rec(pi + 1, ki + 1);
}
return false;
}
return rec(0, 0);
}
const keys = ['order.eu.created', 'order.us.shipped', 'order.eu.shipped', 'order.created'];
for (const key of keys) {
console.log(key, {
audit: topicMatch('order.#', key),
eu: topicMatch('order.eu.*', key),
shipping: topicMatch('order.*.shipped', key),
});
}Fanout-exchange: verspreiding
Een fanout-exchange negeert de routing key volledig en bezorgt elk bericht aan alle gekoppelde queues. Dit is de eenvoudigste en snelste exchange.
Gebruik deze voor scenario's waarin je berichten wilt verspreiden: cache-invalidering over alle app-instanties, realtime-meldingen of updates naar veel WebSocket-gateways.
Elke consumer declareert doorgaans zijn eigen exclusieve, automatisch verwijderende queue, zodat deze een privéversie van de verspreiding ontvangt.
const amqp = require('amqplib');
async function subscribeBroadcast(channel, onMessage) {
const ex = 'cache_invalidations';
await channel.assertExchange(ex, 'fanout', { durable: true });
// Exclusive, server-named queue: unique per consumer, auto-deleted on disconnect
const q = await channel.assertQueue('', { exclusive: true });
await channel.bindQueue(q.queue, ex, ''); // routing key ignored for fanout
await channel.consume(q.queue, (msg) => {
if (msg) {
onMessage(JSON.parse(msg.content.toString()));
channel.ack(msg);
}
});
}
module.exports = { subscribeBroadcast };Headers-exchange: overeenkomst op kenmerken
Een headers-exchange negeert de routing key en vergelijkt in plaats daarvan de headers van het bericht (sleutel-waardeparen). Bindings geven de headers op waarmee moet worden vergeleken, plus een speciaal argument x-match:
x-match: all— elke opgegeven header moet overeenkomen (EN).x-match: any— minstens één opgegeven header moet overeenkomen (OF).
Dit is nuttig wanneer de routering afhankelijk is van meerdere onafhankelijke dimensies (bijvoorbeeld format en region) die je niet netjes kunt combineren in één sleutel met punten.
const amqp = require('amqplib');
async function setupHeaders(channel) {
const ex = 'reports_headers';
await channel.assertExchange(ex, 'headers', { durable: true });
const pdfEu = await channel.assertQueue('pdf_eu', { durable: true });
await channel.bindQueue(pdfEu.queue, ex, '', {
'x-match': 'all',
format: 'pdf',
region: 'eu',
});
const anyCsv = await channel.assertQueue('any_csv', { durable: true });
await channel.bindQueue(anyCsv.queue, ex, '', {
'x-match': 'any',
format: 'csv',
priority: 'high',
});
}
module.exports = { setupHeaders };Publiceren met headers
De producer voegt headerwaarden toe via de eigenschap headers van de publicatieopties. Een lege routing key is gebruikelijk voor headers-exchanges, omdat deze niet wordt gebruikt.
Bij de bindings uit de vorige scène komt een bericht met { format: 'pdf', region: 'eu' } terecht in pdf_eu. Een bericht met { format: 'csv', region: 'us' } komt terecht in any_csv (omdat x-match: any overeenkwam op format).
async function publishReport(channel, payload, headers) {
const ex = 'reports_headers';
channel.publish(
ex,
'', // routing key unused for headers exchange
Buffer.from(JSON.stringify(payload)),
{ headers, persistent: true }
);
}
// publishReport(channel, { id: 42 }, { format: 'pdf', region: 'eu' });
// publishReport(channel, { id: 43 }, { format: 'csv', region: 'us' });
module.exports = { publishReport };De juiste exchange kiezen
Een praktische keuzehulp:
- Direct — je hebt een vaste verzameling categorieën en wilt exacte routering (ernstniveaus, taaktypen).
- Topic — eventnamen zijn hiërarchisch en consumers abonneren zich op flexibele patronen. Dit is de meest gebruikelijke keuze voor eventbussen van microservices.
- Fanout — elke consumer moet elk bericht zien (verspreiding, cache leegmaken).
- Headers — de routering hangt af van meerdere niet-hiërarchische kenmerken, of je hebt EN/OF-logica over verschillende dimensies nodig.
Vuistregel: kies in eventgestuurde systemen standaard voor topic; dit omvat direct (een patroon zonder jokertekens werkt als direct) en is veel uitbreidbaarder dan fanout.
Korte controle
Test je begrip van de keuze van exchanges.
Samenvatting
Je hebt geleerd hoe RabbitMQ berichten via exchanges en bindings routeert:
- Producers publiceren naar exchanges, nooit rechtstreeks naar queues; het type exchange is het routeringsalgoritme.
- Direct — exacte overeenkomst met de routing key voor vaste categorieën.
- Topic — overeenkomst met jokertekenpatronen (
*= één woord,#= nul of meer) voor hiërarchische events; de standaardkeuze voor eventbussen. - Fanout — verspreiding naar alle gekoppelde queues, waarbij de routing key wordt genegeerd.
- Headers — overeenkomst op headerkenmerken met
x-match: all(EN) ofany(OF).
Declareer de exchange en queues altijd met assertExchange/assertQueue en verbind ze met bindQueue. Kies de exchange die past bij de manier waarop je consumers zich moeten abonneren, zodat je de juiste berichten met minimale koppeling naar de juiste plaatsen routeert.
Leer JavaScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 22
- Lessen
- 92
Veelgestelde vragen
Is de les “Exchangetypen: direct, topic, fanout en headers” gratis?
Ja — de volledige tekst van “Exchangetypen: direct, topic, fanout en headers” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Bootcamp backendontwikkeling met Node.js wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Bootcamp backendontwikkeling met Node.js bevat in totaal 4 lessen.
Wat leer ik in “Exchangetypen: direct, topic, fanout en headers”?
Routeer berichten naar de juiste consumers door de geschikte exchange- en bindingstrategie te kiezen. Je oefent met Bootcamp backendontwikkeling met Node.js door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Bootcamp backendontwikkeling met Node.js te beginnen?
Ervaring vooraf is niet nodig. Bootcamp backendontwikkeling met Node.js op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Exchangetypen: direct, topic, fanout en headers”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Bootcamp backendontwikkeling met Node.js?
Ja. Elke les over Bootcamp backendontwikkeling met Node.js bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Producers, consumers en het AMQP-model
- Exchangetypen: direct, topic, fanout en headers
- Acknowledgements, dead-letter-queues en retries
- Work queues, prefetch en concurrerende consumers