{"id":54286,"date":"2025-12-01T06:04:24","date_gmt":"2025-12-01T06:04:24","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54286"},"modified":"2026-02-21T08:29:29","modified_gmt":"2026-02-21T08:29:29","slug":"dotnet-high-performance-messaging-in-net-service-bus-vs-rabbitmq-vs-kafka-and-event-driven-architecture-with-rabbitmq","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/dotnet-high-performance-messaging-in-net-service-bus-vs-rabbitmq-vs-kafka-and-event-driven-architecture-with-rabbitmq\/","title":{"rendered":"DOTNET: High-Performance Messaging in .NET: Service Bus vs RabbitMQ vs Kafka (and Event-Driven Architecture with RabbitMQ)"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">1. Big picture \u2013 why messaging in .NET?<\/h2>\n\n\n\n<p>In modern .NET systems, you almost never want services talking to each other via direct HTTP calls only. Messaging brokers give you:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Loose coupling<\/strong> \u2013 producer and consumer don\u2019t need to be online at the same time.<\/li>\n\n\n\n<li><strong>Resilience<\/strong> \u2013 if a consumer is down, messages can wait in a queue.<\/li>\n\n\n\n<li><strong>Scalability<\/strong> \u2013 multiple consumers can process messages in parallel.<\/li>\n\n\n\n<li><strong>Backpressure<\/strong> \u2013 the broker can buffer load spikes instead of killing your API.<\/li>\n\n\n\n<li><strong>Observability<\/strong> \u2013 you can inspect queues\/topics to understand system health.<\/li>\n<\/ul>\n\n\n\n<p>In .NET you commonly see three families of brokers:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Azure Service Bus<\/strong> \u2013 fully managed enterprise messaging on Azure.<\/li>\n\n\n\n<li><strong>RabbitMQ<\/strong> \u2013 general-purpose message broker implementing AMQP.<\/li>\n\n\n\n<li><strong>Apache Kafka<\/strong> \u2013 distributed log for streaming and very high throughput.<\/li>\n<\/ul>\n\n\n\n<p>We\u2019ll first cover each, then do an EDA deep-dive with RabbitMQ, and finally discuss \u201cwhich is best\u201d for .NET performance.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">2. Core messaging concepts (applies to all three)<\/h2>\n\n\n\n<p>All brokers implement variations of the same ideas:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Producer<\/strong> \u2013 your .NET app that <em>sends<\/em> a message.<\/li>\n\n\n\n<li><strong>Consumer<\/strong> \u2013 your .NET app that <em>receives<\/em> and <em>handles<\/em> a message.<\/li>\n\n\n\n<li><strong>Message<\/strong> \u2013 some payload + metadata (headers, key, etc.).<\/li>\n\n\n\n<li><strong>Queue \/ Topic \/ Stream<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Queue<\/strong> \u2013 point-to-point, one consumer gets each message.<\/li>\n\n\n\n<li><strong>Topic<\/strong> \u2013 publish\/subscribe, many consumers get a copy.<\/li>\n\n\n\n<li><strong>Stream \/ log<\/strong> \u2013 ordered, append-only sequence of messages.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Common patterns:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Competing consumers<\/strong> \u2013 many consumers read from one queue to scale out.<\/li>\n\n\n\n<li><strong>Pub\/Sub<\/strong> \u2013 one producer, many independent subscribers.<\/li>\n\n\n\n<li><strong>Request\/Reply<\/strong> \u2013 send command, get response on another queue\/topic.<\/li>\n<\/ul>\n\n\n\n<p>Keep these in mind as we compare brokers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">3. Azure Service Bus (ASB)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">3.1 What it is<\/h3>\n\n\n\n<p>Azure Service Bus is a fully managed message broker from Microsoft, providing queues and publish\/subscribe topics. It\u2019s designed for enterprise integration, transactional messaging, and complex routing.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-queues-topics-subscriptions?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/p>\n\n\n\n<p>Key entities:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Queues<\/strong> \u2013 FIFO queues; one consumer processes each message.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-queues-topics-subscriptions?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n\n\n\n<li><strong>Topics &amp; Subscriptions<\/strong> \u2013 topic = publish-point; subscriptions = virtual queues with filters.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-queues-topics-subscriptions?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3.2 Why use it?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You\u2019re <strong>already on Azure<\/strong> and want a managed, \u201cbatteries-included\u201d broker.<\/li>\n\n\n\n<li>You need <strong>transactions<\/strong>, <strong>sessions<\/strong>, <strong>dead-letter queues<\/strong>, <strong>scheduled delivery<\/strong>, <strong>duplicate detection<\/strong>, etc.<\/li>\n\n\n\n<li>You want <strong>enterprise-grade security &amp; RBAC<\/strong> with Azure AD \/ Entra and role-based access (Data Sender\/Receiver\/Owner).(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-dotnet-get-started-with-queues?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3.3 Architecture &amp; flow in .NET<\/h3>\n\n\n\n<p>Typical architecture:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>.NET Producer API \u2192 Azure Service Bus namespace \u2192 queue\/topic \u2192 .NET Consumer API<\/p>\n<\/blockquote>\n\n\n\n<p>Flow example (queue):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Producer<\/strong> (.NET API) uses <code>Azure.Messaging.ServiceBus<\/code> to connect and send a message to a queue.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-dotnet-get-started-with-queues?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n\n\n\n<li>Service Bus stores the message durably.<\/li>\n\n\n\n<li><strong>Consumer<\/strong> (.NET worker \/ WebJob \/ Azure Function \/ container) receives messages using the same SDK.<\/li>\n\n\n\n<li>Consumer processes message and completes\/abandon\/dead-letters based on result.<\/li>\n<\/ol>\n\n\n\n<p>Flow example (topic):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Producer sends message to Topic <code>orders<\/code>.<\/li>\n\n\n\n<li>Subscriptions: e.g., <code>AccountingSub<\/code> with filter <code>Type = 'Paid'<\/code>, <code>ShippingSub<\/code> with filter <code>Type = 'Shipped'<\/code>.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-dotnet-how-to-use-topics-subscriptions?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n\n\n\n<li>Each subscription gets <em>its own copy<\/em> of matching messages.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">3.4 Performance characteristics (for .NET)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros<\/strong>\n<ul class=\"wp-block-list\">\n<li>You don\u2019t manage cluster, disks, replication, or scaling.<\/li>\n\n\n\n<li>Good latency + decent throughput for typical enterprise workloads.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Cons<\/strong>\n<ul class=\"wp-block-list\">\n<li>Hard throughput ceilings vs Kafka.<\/li>\n\n\n\n<li>Cost and latency depend on network round-trip to Azure.<\/li>\n\n\n\n<li>Less \u201craw\u201d tuning knobs compared to self-hosted RabbitMQ\/Kafka.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>Best fit<\/strong>: cloud-native enterprise .NET apps fully on Azure, where <strong>operational simplicity and reliability<\/strong> matter more than extreme throughput.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">4. RabbitMQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">4.1 What it is<\/h3>\n\n\n\n<p>RabbitMQ is an open-source, general-purpose message broker that implements the AMQP 0-9-1 protocol. Its core is built around <strong>exchanges<\/strong>, <strong>queues<\/strong>, and <strong>bindings<\/strong>.(<a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/p>\n\n\n\n<p>Key entities:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Exchange<\/strong> \u2013 routes messages based on routing key and bindings.<\/li>\n\n\n\n<li><strong>Queue<\/strong> \u2013 ordered buffer of messages (FIFO).(<a href=\"https:\/\/www.rabbitmq.com\/docs\/queues?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/li>\n\n\n\n<li><strong>Binding<\/strong> \u2013 rule connecting an exchange to a queue with a routing key.(<a href=\"https:\/\/medium.com\/%40pakhale.dipak95\/queues-exchanges-and-bindings-the-core-of-rabbitmq-9533ebfc49eb?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Medium<\/a>)<\/li>\n<\/ul>\n\n\n\n<p>Exchange types: direct, topic, fanout, headers.(<a href=\"https:\/\/medium.com\/%40mk.muhammadkhoirudin\/exchange-queue-rabbitmq-using-c-and-why-does-rabbitmq-need-both-exchange-and-queue-c81c423dab69?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Medium<\/a>)<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.2 Why use it?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You want <strong>low-latency messaging<\/strong> with flexible routing and patterns.<\/li>\n\n\n\n<li>You need <strong>classic queue semantics<\/strong> (competing consumers, priority queues).<\/li>\n\n\n\n<li>You prefer <strong>self-hosted control<\/strong> (or a managed RabbitMQ offering).<\/li>\n\n\n\n<li>You need <strong>language-agnostic<\/strong> support plus first-class .NET client.(<a href=\"https:\/\/www.rabbitmq.com\/client-libraries\/dotnet-api-guide?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4.3 Architecture &amp; flow in .NET<\/h3>\n\n\n\n<p>Conceptual architecture:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>.NET Producer \u2192 Exchange \u2192 Queue(s) \u2192 .NET Consumer(s)<\/p>\n<\/blockquote>\n\n\n\n<p>Flow example (topic exchange):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Producer<\/strong> publishes message to exchange <code>order_events<\/code> with routing key <code>order.created<\/code>.<\/li>\n\n\n\n<li>Bindings:\n<ul class=\"wp-block-list\">\n<li>Queue <code>billing_q<\/code> bound with pattern <code>order.*<\/code><\/li>\n\n\n\n<li>Queue <code>email_q<\/code> bound with pattern <code>order.created<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>RabbitMQ routes the message to both queues according to bindings.(<a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/li>\n\n\n\n<li>Each consumer group reads from its queue at its own pace.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">4.4 RabbitMQ .NET client basics<\/h3>\n\n\n\n<p>RabbitMQ provides a mature .NET client that supports:(<a href=\"https:\/\/www.rabbitmq.com\/client-libraries\/dotnet-api-guide?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Connection and channel management.<\/li>\n\n\n\n<li>Automatic topology recovery (connections, queues, bindings).<\/li>\n\n\n\n<li>Consumer-based receiving (push model).<\/li>\n<\/ul>\n\n\n\n<p>In practice you usually:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create one connection per app instance.<\/li>\n\n\n\n<li>Create channels per thread \/ logical unit.<\/li>\n\n\n\n<li>Use long-lived consumers with manual ack for reliability.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4.5 Performance characteristics<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Latency<\/strong> \u2013 very low for typical workloads (sub-millisecond inside LAN).<\/li>\n\n\n\n<li><strong>Throughput<\/strong> \u2013 high enough for most microservice scenarios; not as massive as Kafka at petabyte-scale.<\/li>\n\n\n\n<li><strong>Tuning knobs<\/strong> \u2013 prefetch, durable vs transient queues, acks, etc.<\/li>\n\n\n\n<li><strong>Clustering<\/strong> \u2013 good but you must understand queue placement &amp; HA (e.g., mirrored queues, quorum queues).(<a href=\"https:\/\/www.cloudamqp.com\/blog\/part1-rabbitmq-best-practice.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">CloudAMQP<\/a>)<\/li>\n<\/ul>\n\n\n\n<p><strong>Best fit<\/strong>: .NET microservices where you want <strong>fast, flexible, classical messaging<\/strong> (commands, RPC, events) without the full complexity of Kafka.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">5. Kafka (with ZooKeeper \/ KRaft)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">5.1 What it is<\/h3>\n\n\n\n<p>Apache Kafka is a <strong>distributed streaming platform<\/strong>. Instead of \u201cmessages in queues,\u201d think \u201cevents in a log.\u201d It\u2019s optimized for <strong>very high throughput<\/strong>, event sourcing, and stream processing.(<a href=\"https:\/\/kafka.apache.org\/intro?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Apache Kafka<\/a>)<\/p>\n\n\n\n<p>Key entities:(<a href=\"https:\/\/kafka.apache.org\/documentation\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Apache Kafka<\/a>)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Topic<\/strong> \u2013 named stream of records.<\/li>\n\n\n\n<li><strong>Partition<\/strong> \u2013 shard of a topic; messages are ordered within a partition.<\/li>\n\n\n\n<li><strong>Producer<\/strong> \u2013 app that appends messages to a topic.<\/li>\n\n\n\n<li><strong>Consumer Group<\/strong> \u2013 group of consumers that share the work of reading a topic.<\/li>\n\n\n\n<li><strong>Broker<\/strong> \u2013 Kafka server node.<\/li>\n\n\n\n<li><strong>ZooKeeper \/ KRaft<\/strong> \u2013 cluster coordination. (Older Kafka uses ZooKeeper; newer versions can use built-in KRaft for metadata management.)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5.2 Why use it?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You need <strong>hundreds of thousands to millions of messages per second<\/strong>.<\/li>\n\n\n\n<li>You want to <strong>replay<\/strong> events, not just consume them once.<\/li>\n\n\n\n<li>You\u2019re doing <strong>analytics, stream processing, event sourcing, CQRS<\/strong>.<\/li>\n\n\n\n<li>Many downstream consumers need to independently read full history.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5.3 Architecture &amp; flow in .NET<\/h3>\n\n\n\n<p>High-level architecture:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>.NET Producer \u2192 Kafka Topic (partitioned across brokers) \u2192 .NET Consumers (consumer groups)<\/p>\n<\/blockquote>\n\n\n\n<p>Flow example:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Producer (using Confluent.Kafka .NET client) sends a message to topic <code>orders<\/code>.(<a href=\"https:\/\/docs.confluent.io\/kafka-clients\/dotnet\/current\/overview.html?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">docs.confluent.io<\/a>)<\/li>\n\n\n\n<li>Kafka chooses partition based on key (e.g., <code>OrderId<\/code>), preserving order per key.<\/li>\n\n\n\n<li>Consumer group <code>order-processors<\/code> has N instances; Kafka assigns partitions to consumers.(<a href=\"https:\/\/www.instaclustr.com\/education\/apache-kafka\/apache-kafka-architecture-a-complete-guide-2025\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Instaclustr<\/a>)<\/li>\n\n\n\n<li>Each consumer reads and commits offsets; if one fails, another takes over its partitions.(<a href=\"https:\/\/www.instaclustr.com\/education\/apache-kafka\/apache-kafka-architecture-a-complete-guide-2025\/?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Instaclustr<\/a>)<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">5.4 Kafka .NET clients<\/h3>\n\n\n\n<p>The <strong>Confluent.Kafka<\/strong> client is the de-facto standard .NET client. It wraps <code>librdkafka<\/code> and is highly tuned for performance.(<a href=\"https:\/\/github.com\/confluentinc\/confluent-kafka-dotnet?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>)<\/p>\n\n\n\n<p>It supports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>High-performance producer\/consumer APIs.<\/li>\n\n\n\n<li>Admin APIs (create topics, etc.).(<a href=\"https:\/\/stackoverflow.com\/questions\/50063406\/how-to-create-a-kafka-topic-using-confluent-kafka-net-client?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Stack Overflow<\/a>)<\/li>\n\n\n\n<li>Integration with schema registry (Avro, Protobuf, JSON).(<a href=\"https:\/\/www.nuget.org\/profiles\/confluent?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">nuget.org<\/a>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5.5 Performance characteristics<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Throughput<\/strong> \u2013 extremely high due to partitioned log architecture.(<a href=\"https:\/\/www.datacamp.com\/tutorial\/kafka-partitions?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">DataCamp<\/a>)<\/li>\n\n\n\n<li><strong>Latency<\/strong> \u2013 usually a bit higher than RabbitMQ in small setups; still good.<\/li>\n\n\n\n<li><strong>Horizontal scaling<\/strong> \u2013 add brokers, add partitions, add consumer instances.<\/li>\n\n\n\n<li><strong>Storage<\/strong> \u2013 can keep data for days\/months for reprocessing.<\/li>\n<\/ul>\n\n\n\n<p><strong>Best fit<\/strong>: .NET systems that are <strong>event-stream heavy<\/strong>, integrate data pipelines, or require <strong>replayable history<\/strong> and massive scale.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">6. Event-Driven Architecture (EDA) with RabbitMQ<\/h2>\n\n\n\n<p>Now let\u2019s zoom in on <strong>Event-Driven Architecture<\/strong> using RabbitMQ, since you explicitly asked for that.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 What is EDA?<\/h3>\n\n\n\n<p>Event-Driven Architecture is a style where:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Services emit <strong>events<\/strong> when something happens (<code>OrderCreated<\/code>, <code>PaymentFailed<\/code>).<\/li>\n\n\n\n<li>Other services <strong>react<\/strong> to those events asynchronously.<\/li>\n\n\n\n<li>Communication is <strong>publish\/subscribe<\/strong>, not request\/response.<\/li>\n<\/ul>\n\n\n\n<p>Benefits:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Loose coupling \u2013 producers don\u2019t know who consumes their events.<\/li>\n\n\n\n<li>Extensibility \u2013 new consumers can be added without touching producers.<\/li>\n\n\n\n<li>Natural fit for microservices and domain events.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6.2 EDA building blocks in RabbitMQ<\/h3>\n\n\n\n<p>You can model EDA with RabbitMQ\u2019s AMQP model:(<a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">rabbitmq.com<\/a>)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Event exchange<\/strong> \u2013 e.g., <code>domain_events<\/code> (topic or fanout).<\/li>\n\n\n\n<li><strong>Event routing key<\/strong> \u2013 e.g., <code>order.created<\/code>, <code>invoice.paid<\/code>.<\/li>\n\n\n\n<li><strong>Event queues<\/strong> \u2013 per bounded context \/ service:\n<ul class=\"wp-block-list\">\n<li><code>billing_events_q<\/code><\/li>\n\n\n\n<li><code>shipping_events_q<\/code><\/li>\n\n\n\n<li><code>email_events_q<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Bindings<\/strong> \u2013 tie queues to exchange based on routing pattern:\n<ul class=\"wp-block-list\">\n<li><code>billing_events_q<\/code> \u2192 <code>domain_events<\/code> with <code>order.*<\/code><\/li>\n\n\n\n<li><code>email_events_q<\/code> \u2192 <code>domain_events<\/code> with <code>*.created<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6.3 Example EDA flow: \u201cOrder Created\u201d<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Order Service<\/strong> (producer)\n<ul class=\"wp-block-list\">\n<li>Handles HTTP <code>POST \/orders<\/code>.<\/li>\n\n\n\n<li>After persistence, publishes <code>OrderCreated<\/code> event to exchange <code>domain_events<\/code> with routing key <code>order.created<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Billing Service<\/strong>\n<ul class=\"wp-block-list\">\n<li>Has queue <code>billing_events_q<\/code> bound with pattern <code>order.*<\/code>.<\/li>\n\n\n\n<li>RabbitMQ routes <code>order.created<\/code> to <code>billing_events_q<\/code>.<\/li>\n\n\n\n<li>Billing service consumes the event; creates invoice; optionally publishes <code>InvoiceCreated<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Email Service<\/strong>\n<ul class=\"wp-block-list\">\n<li>Has queue <code>email_events_q<\/code> bound with <code>order.created<\/code> and <code>invoice.created<\/code>.<\/li>\n\n\n\n<li>Sends confirmation emails based on events.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Inventory Service<\/strong>\n<ul class=\"wp-block-list\">\n<li>Has queue <code>inventory_events_q<\/code> maybe bound with <code>order.*<\/code>.<\/li>\n\n\n\n<li>Reserved stock etc.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>No service calls another directly; they all react to the shared event stream propagated via RabbitMQ.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.4 EDA concerns in .NET<\/h3>\n\n\n\n<p>For .NET specifically:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a <strong>shared contract library<\/strong> with event DTOs (C# records).<\/li>\n\n\n\n<li>Choose a serialization format (JSON, Protobuf, etc.).<\/li>\n\n\n\n<li>Wrap raw RabbitMQ client with:\n<ul class=\"wp-block-list\">\n<li>Connection factory + health checks.<\/li>\n\n\n\n<li>Publisher abstraction with retry &amp; idempotency.<\/li>\n\n\n\n<li>Consumer abstraction with error handling, DLQ routing.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Advanced topics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Idempotent handlers<\/strong> \u2013 handle duplicate messages safely.<\/li>\n\n\n\n<li><strong>Dead-letter queues<\/strong> \u2013 for poison messages.<\/li>\n\n\n\n<li><strong>Outbox pattern<\/strong> \u2013 ensure DB transaction + message publish are consistent.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">7. Which is best for .NET application performance?<\/h2>\n\n\n\n<p>The honest answer: <strong>\u201cit depends on your workload and constraints.\u201d<\/strong> But we can give concrete guidance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7.1 Quick comparison table (performance + usage)<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Broker<\/th><th>Strengths for .NET performance<\/th><th>When to prefer it<\/th><\/tr><\/thead><tbody><tr><td><strong>Azure Service Bus<\/strong><\/td><td>Good throughput, strong reliability, managed service<\/td><td>You\u2019re all-in on Azure; want minimal ops; enterprise features &amp; security.<\/td><\/tr><tr><td><strong>RabbitMQ<\/strong><\/td><td>Very low latency, flexible routing, easy to tune<\/td><td>You need fast microservice messaging, classic queues, control over cluster<\/td><\/tr><tr><td><strong>Kafka<\/strong><\/td><td>Massive throughput, replay, partitioned scaling<\/td><td>You have high-volume events, analytics, event sourcing, stream processing<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">7.2 Decision by use-case<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Simple internal microservice messaging<\/strong> (commands, events, background jobs)\n<ul class=\"wp-block-list\">\n<li><strong>RabbitMQ<\/strong> often gives the best mix of <strong>latency, simplicity, and control<\/strong>.<\/li>\n\n\n\n<li>ASB also fine if you\u2019re on Azure and want managed service.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Enterprise integration across multiple domains, Azure-native<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Azure Service Bus<\/strong> \u2013 built-in security, topics\/subscriptions, transactions.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>High-volume data \/ event streaming, analytics, replay<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Kafka<\/strong> \u2013 optimized for <strong>throughput and partitioned scalability<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">7.3 Performance notes specific to .NET<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Client overhead<\/strong>\n<ul class=\"wp-block-list\">\n<li>Service Bus &amp; RabbitMQ clients are pure managed libraries; simple to use.(<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/service-bus-messaging\/service-bus-dotnet-get-started-with-queues?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">Microsoft Learn<\/a>)<\/li>\n\n\n\n<li>Kafka\u2019s Confluent client wraps a native C library; extremely fast but a bit more complex to configure.(<a href=\"https:\/\/github.com\/confluentinc\/confluent-kafka-dotnet?utm_source=chatgpt.com\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Serialization cost<\/strong>\n<ul class=\"wp-block-list\">\n<li>For high-throughput .NET apps, choose efficient serializers (e.g., MessagePack, Protobuf, System.Text.Json with source generators) and avoid huge payloads.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Connection &amp; channel management<\/strong>\n<ul class=\"wp-block-list\">\n<li>Reuse connections; don\u2019t create a connection per message (RabbitMQ, Service Bus, Kafka).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Batching<\/strong>\n<ul class=\"wp-block-list\">\n<li>All three brokers benefit from sending in batches when throughput matters.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>If you\u2019re building a <strong>performance-focused .NET microservices training\/demo<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use <strong>RabbitMQ<\/strong> for EDA examples and small latency benchmarks.<\/li>\n\n\n\n<li>Include <strong>Kafka<\/strong> to show throughput &amp; replay benefits.<\/li>\n\n\n\n<li>Show <strong>Azure Service Bus<\/strong> as your \u201cmanaged, enterprise, we\u2019re on Azure\u201d story.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">8. Extra questions you can add to the tutorial<\/h2>\n\n\n\n<p>To make this \u201ccomplete\u201d for your training, you can explicitly cover:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Reliability &amp; Delivery Semantics<\/strong>\n<ul class=\"wp-block-list\">\n<li>At-most-once vs at-least-once vs exactly-once.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Error handling<\/strong>\n<ul class=\"wp-block-list\">\n<li>Dead-letter queues, retry policies, poison message handling.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Security<\/strong>\n<ul class=\"wp-block-list\">\n<li>TLS, SAS \/ Entra roles (Service Bus), user\/virtual host permissions (RabbitMQ), ACLs (Kafka).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Operational aspects<\/strong>\n<ul class=\"wp-block-list\">\n<li>Monitoring, metrics, and tracing for each broker.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Migration &amp; coexistence<\/strong>\n<ul class=\"wp-block-list\">\n<li>How to integrate ASB \u2194 RabbitMQ \u2194 Kafka in hybrid systems.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>1. Big picture \u2013 why messaging in .NET? In modern .NET systems, you almost never want services talking to each other via direct HTTP calls only. Messaging brokers give you:&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-54286","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=54286"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54286\/revisions"}],"predecessor-version":[{"id":59902,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54286\/revisions\/59902"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}