Azure Event Hubs vs Service Bus vs Event Grid

When to Use Which — Complete Decision Framework


Introduction

Azure provides three distinct event and messaging services, each designed for different use cases. Understanding when to use each service is crucial for building efficient, scalable, and cost-effective cloud architectures.

This comprehensive guide covers:

  • Service definitions — What each service does
  • Detailed comparison — Features, capabilities, and limitations
  • Decision frameworks — How to choose the right service
  • Real-world patterns — Hybrid architectures combining multiple services
  • Migration strategies — Moving between services

Service Overview

Event Hubs

Azure Event Hubs is a fully managed, real-time event streaming platform designed for high-throughput data ingestion scenarios.

┌──────────────────────────────────────────────────────────────────┐
│                         EVENT HUBS                               │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐       │
│   │ Part 0  │    │ Part 1  │    │ Part 2  │    │ Part 3  │       │
│   │ ┌─────┐ │    │ ┌─────┐ │    │ ┌─────┐ │    │ ┌─────┐ │       │
│   │ │Msg 1│ │    │ │Msg 2│ │    │ │Msg 3│ │    │ │Msg 4│ │       │
│   │ │Msg 5│ │    │ │Msg 6│ │    │ │Msg 7│ │    │ │Msg 8│ │       │
│   │ └─────┘ │    │ └─────┘ │    │ └─────┘ │    │ └─────┘ │       │
│   └─────────┘    └─────────┘    └─────────┘    └─────────┘       │
│        │              │              │              │            │
│        └──────────────┴──────────────┴──────────────┘            │
│                             │                                    │
│                    ┌────────▼────────┐                           │
│                    │ Consumer Groups │                           │
│                    │ • Analytics     │                           │
│                    │ • Archive       │                           │
│                    │ • Processing    │                           │
│                    └─────────────────┘                           │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Key characteristics:

  • Throughput-oriented — Millions of events per second
  • Partition-based — Ordered within partitions
  • Kafka-compatible — Native Kafka protocol support
  • Capture — Built-in storage to ADLS Gen2

Service Bus

Azure Service Bus is an enterprise-grade message broker designed for reliable message queuing and pub-sub patterns with advanced features.

┌─────────────────────────────────────────────────────────────────────┐
│                       SERVICE BUS                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│                        ┌─────────────┐                              │
│                        │   Queues    │                              │
│   ┌──────┐    ───────▶ │  ┌─────────┐│                              │
│   │Sender│             │  │ Message ││──────▶┌─────────┐            │
│   └──────┘             │  └─────────┘│       │ Receiver│            │
│                        │  ┌─────────┐│       └─────────┘            │
│                        │  │ Message ││                              │
│                        │  └─────────┘│                              │
│                        └─────────────┘                              │
│                              │                                      │
│                        ┌─────────────┐                              │
│                        │   Topics    │                              │
│   ┌──────┐    ───────▶ │  ┌─────────┐│──────▶ Subscription 1        │
│   │Sender│             │  │ Message ││       (Filter: Region=US).   │
│   └──────┘             │  └─────────┘│                              │
│                        │             │──────▶ Subscription 2        │
│                        │             │       (Filter: Type=Order)   │
│                        └─────────────┘                              │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Key characteristics:

  • Reliability-first — 99.99% uptime SLA
  • Advanced features — Sessions, transactions, dead-lettering
  • Message guarantee — At-least-once delivery
  • Request-reply — Built-in correlation patterns

Event Grid

Azure Event Grid is an event routing service that enables event-driven, serverless architectures with near-real-time delivery.

┌──────────────────────────────────────────────────────────────────┐
│                       EVENT GRID                                 │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌──────────────┐      ┌──────────────┐      ┌──────────────┐   │
│   │   Sources    │      │    Topics    │      │   Handlers   │   │
│   │              │      │              │      │              │   │
│   │ • Storage    │─────▶│ • Custom     │─────▶│ • Functions  │   │
│   │ • IoT Hub    │      │ • System     │      │ • Logic Apps │   │
│   │ • Cosmos DB  │      │ • Domain     │      │ • Webhooks   │   │
│   │ • Container  │      │              │      │ • Hybrid     │   │
│   └──────────────┘      └──────────────┘      └──────────────┘   │
│                                                                  │
│   Events published ──▶ Filtered ──▶ Routed to handlers           │
│   (near real-time)    (by subject/type)   (multiple endpoints)   │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Key characteristics:

  • Event-driven — Push-based notification
  • Low latency — Near real-time delivery
  • Fan-out — Multiple subscribers per event
  • Filterable — Subject and type-based routing

Detailed Feature Comparison

Message Patterns Comparison

FeatureEvent HubsService BusEvent Grid
Core PatternEvent streamingMessage queuingEvent routing
Pub-SubVia consumer groupsVia topicsNative
QueueNot nativeFull supportNot supported
Request-ReplyNot supportedFull supportNot supported
Message SessionsNot supportedSupportedNot supported
TransactionsNot supportedMulti-messageNot supported
Dead Letter QueueVia separate entityNative supportNot supported

Delivery and Ordering

FeatureEvent HubsService BusEvent Grid
Delivery GuaranteeAt-least-onceAt-least-onceAt-least-once
Exactly-onceNot nativeVia duplicate detectionNot supported
OrderingPer-partitionPer-session or per-queueNone
Visibility TimeoutN/AConfigurableN/A
Max Retention7 days7 days24 hours
Message Size1MB (256KB body)256KB1MB

Protocol and SDK

FeatureEvent HubsService BusEvent Grid
AMQPYesYesVia relay
HTTP/RESTYesYesYes (events)
KafkaNativeNot supportedNot supported
.NET SDKAzure.Messaging.EventHubsAzure.Messaging.ServiceBusAzure.Messaging.EventGrid
Java SDKazure-messaging-eventhubsazure-messaging-servicebusazure-messaging-eventgrid
Python SDKazure-eventhubazure-servicebusazure-eventgrid

Scalability Comparison

FeatureEvent HubsService BusEvent Grid
Throughput Units1-20 (Basic/Premium)N/AN/A
Processing Units1-40 (Premium)N/AN/A
Namespace TiersStandard, Premium, DedicatedStandard, PremiumN/A
Auto-scaleYes (Premium)Yes (Premium)Automatic
Max Partition Count32 (Standard), 1024 (Dedicated)N/AN/A
Concurrent ReadersUnlimitedUnlimitedPer subscription

Decision Framework

When to Choose Event Hubs

Use Event Hubs for:

  1. High-volume telemetry ingestion

    • IoT device data streams
    • Application logs and metrics
    • Clickstream analytics
    • Financial transaction streams
  2. Real-time stream processing

    • Stream analytics jobs
    • Spark/Databricks consumption
    • Real-time dashboards
  3. Kafka workloads

    • Existing Kafka applications
    • Kafka ecosystem tools
    • Event sourcing with Kafka patterns
  4. Event capture for analytics

    • Long-term event storage
    • Batch analytics
    • Data warehousing

Example: IoT Telemetry Pipeline

// Event Hub producer for IoT devices
public class IoTDevicePublisher
{
    private readonly EventHubProducerClient _producer;
    
    public async Task SendTelemetryAsync(DeviceTelemetry telemetry)
    {
        var eventData = new EventData(
            Encoding.UTF8.GetBytes(JsonSerializer.Serialize(telemetry))
        )
        {
            PartitionKey = telemetry.DeviceId,
            ContentType = "application/json"
        };
        
        eventData.Properties["EventType"] = "Telemetry";
        eventData.Properties["DeviceType"] = telemetry.DeviceType;
        
        await _producer.SendAsync(new[] { eventData });
    }
}

// Event Hub consumer for analytics
public class TelemetryProcessor
{
    public async Task ProcessEventsAsync(
        PartitionContext context,
        IEnumerable<EventData> events)
    {
        foreach (var evt in events)
        {
            var telemetry = JsonSerializer.Deserialize<DeviceTelemetry>(
                Encoding.UTF8.GetString(evt.Body));
            
            await UpdateRealTimeDashboardAsync(telemetry);
            await StoreForAnalyticsAsync(telemetry);
        }
        
        await context.CheckpointAsync();
    }
}

When to Choose Service Bus

Use Service Bus for:

  1. Reliable queue-based processing

    • Order processing systems
    • Background job processing
    • Task distribution
  2. Request-reply patterns

    • HTTP to async conversion
    • RPC over messaging
    • Callback patterns
  3. Message ordering requirements

    • Session-based ordering
    • FIFO processing
    • Correlation IDs
  4. Complex workflows

    • Multi-message transactions
    • Dead letter handling
    • Duplicate detection

Example: Order Processing System

// Send order to queue
public class OrderService
{
    private readonly QueueClient _queueClient;
    
    public async Task SubmitOrderAsync(Order order)
    {
        var message = new ServiceBusMessage(
            JsonSerializer.Serialize(order))
        {
            ContentType = "application/json",
            MessageId = order.OrderId.ToString(),
            Subject = "NewOrder",
            ReplyTo = "order-response"
        };
        
        // Enable duplicate detection
        message.ApplicationProperties["DueDate"] = order.DueDate;
        
        await _queueClient.SendMessageAsync(message);
    }
}

// Process order with sessions
public class OrderProcessor
{
    public async Task ProcessMessageAsync(
        ServiceBusReceivedMessage message,
        ServiceBusMessageSession session)
    {
        var order = JsonSerializer.Deserialize<Order>(
            message.Body.ToString());
        
        try
        {
            await ValidateOrderAsync(order);
            await ProcessPaymentAsync(order);
            await ReserveInventoryAsync(order);
            
            await session.CompleteAsync(message.LockToken);
            
            // Send response to reply queue
            await SendOrderConfirmationAsync(order);
        }
        catch (Exception ex)
        {
            // Dead letter if max retries exceeded
            await message.DeadLetterAsync(
                reason: ex.Message,
                errorDescription: ex.StackTrace);
        }
    }
}

When to Choose Event Grid

Use Event Grid for:

  1. Event-driven triggers

    • Resource state changes
    • Database changes
    • Container lifecycle
  2. Serverless workflows

    • Logic Apps triggers
    • Azure Functions triggers
    • Webhook notifications
  3. Fan-out patterns

    • Multiple handlers per event
    • Cross-region replication
    • Audit logging
  4. Operational events

    • Cost alerts
    • Security notifications
    • Deployment events

Example: Cloud Resource Automation

// Subscribe to blob creation events
public class BlobEventHandler
{
    [FunctionName("ProcessUploadedBlob")]
    public async Task Run(
        [EventGridTrigger] EventGridEvent eventGridEvent)
    {
        var blobUrl = eventGridEvent.Data["url"]?.ToString();
        
        // Process based on blob type
        if (blobUrl.Contains("orders/"))
        {
            await ProcessOrderFileAsync(blobUrl);
        }
        else if (blobUrl.Contains("images/"))
        {
            await ResizeImageAsync(blobUrl);
        }
    }
}

// Subscribe to Cosmos DB changes
public class CosmosChangeHandler
{
    [FunctionName("HandleCosmosChange")]
    public async Task Run(
        [CosmosDBTrigger(
            databaseName: "orders",
            collectionName: "items",
            ConnectionStringSetting = "CosmosConnection",
            LeaseCollectionName = "leases")]
        IReadOnlyList<Document> documents)
    {
        foreach (var doc in documents)
        {
            var changeType = doc.GetPropertyValue<string>("operationType");
            
            if (changeType == "create")
            {
                await NotifyNewOrderAsync(doc);
            }
            else if (changeType == "update")
            {
                await UpdateOrderStatusAsync(doc);
            }
        }
    }
}

Hybrid Patterns

Combined Architecture Pattern

┌─────────────────────────────────────────────────────────────────────┐
│              HYBRID EVENT ARCHITECTURE                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌──────────────┐                                                   │
│  │  IoT Devices │──────┐                                            │
│  └──────────────┘      │                                            │
│                        ▼                                            │
│              ┌────────────────┐                                     │
│              │   Event Hubs   │  (High-throughput ingestion)        │
│              │   (Telemetry)  │                                     │
│              └───────┬────────┘                                     │
│                      │                                              │
│         ┌────────────┴────────────┐                                 │
│         │                         │                                 │
│         ▼                         ▼                                 │
│  ┌─────────────┐          ┌─────────────┐                           │
│  │ Stream      │          │  Event Grid │ (Real-time triggers)      │
│  │ Analytics   │          │             │                           │
│  │ (Batch)     │          │  • Alerts   │                           │
│  └─────────────┘          │  • Auditing │                           │
│                           └───────┬─────┘                           │
│                                   │                                 │
│                                   ▼                                 │
│  ┌─────────────┐          ┌─────────────┐                           │
│  │ Service Bus │          │ Logic Apps  │                           │
│  │ (Queued     │          │ (Workflows) |                           │
│  │  Processing)│          └─────────────┘                           │
│  └──────┬──────┘                                                    │
│         │                                                           │
│         ▼                                                           │
│  ┌─────────────┐                                                    │
│  │  Order      │                                                    │
│  │  Processor  │                                                    │
│  └─────────────┘                                                    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Implementation Example

// Layer 1: Event Hubs - High-volume ingestion
public class TelemetryIngestion
{
    private readonly EventHubProducerClient _eventHub;
    
    public async Task IngestTelemetryAsync(DeviceData data)
    {
        var eventData = new EventData(
            Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data)));
        
        eventData.Properties["Timestamp"] = DateTime.UtcNow.ToString("O");
        eventData.Properties["DeviceId"] = data.DeviceId;
        
        await _eventHub.SendAsync(new[] { eventData });
    }
}

// Layer 2: Event Grid - Real-time triggers
public class RealTimeTrigger
{
    // Automatically triggered when Event Hub captures data
    [FunctionName("ProcessRecentData")]
    public async Task Run(
        [EventGridTrigger] EventGridEvent evt)
    {
        // Get data from capture
        var blobUrl = evt.Data["fileUrl"]?.ToString();
        
        // Trigger alert if anomaly detected
        await CheckAnomalyAndAlertAsync(blobUrl);
    }
}

// Layer 3: Service Bus - Reliable processing
public class ReliableProcessor
{
    private readonly QueueClient _queueClient;
    
    // Function triggered by Event Grid
    public async Task QueueForProcessingAsync(ProcessRequest request)
    {
        var message = new ServiceBusMessage(
            JsonSerializer.Serialize(request))
        {
            MessageId = Guid.NewGuid().ToString(),
            Subject = "ProcessRequest",
            ScheduledEnqueueTime = DateTimeOffset.UtcNow.AddSeconds(30)
        };
        
        await _queueClient.SendMessageAsync(message);
    }
    
    // Background processor
    public async Task ProcessQueueMessageAsync(
        ServiceBusReceivedMessage message)
    {
        var request = JsonSerializer.Deserialize<ProcessRequest>(
            message.Body.ToString());
        
        await PerformProcessingAsync(request);
        await message.CompleteAsync(message.LockToken);
    }
}

Cost Comparison

Pricing Models

ServicePricing ComponentsFree Tier
Event HubsThroughput units + Ingress1M events/month
Service BusOperations (premium: namespace)13M ops/month
Event GridOperations25K events/month

Cost Optimization Strategies

ServiceStrategy
Event HubsUse reserved capacity, enable Capture for batch processing
Service BusUse sessions efficiently, implement dead letter cleanup
Event GridFilter events at subscription, use domain topics

Example Cost Scenarios

ScenarioEvent HubsService BusEvent Grid
100K events/day~$11/mo~$5/mo~$3/mo
1M events/day~$75/mo~$45/mo~$25/mo
10M events/day~$650/mo~$400/mo~$200/mo

Migration Between Services

From Event Hubs to Service Bus

Use when switching from streaming to queue-based processing:

// Before: Event Hubs
await eventHubClient.SendAsync(eventData);

// After: Service Bus
var message = new ServiceBusMessage(Encoding.UTF8.GetBytes(payload))
{
    MessageId = Guid.NewGuid().ToString()
};
await queueClient.SendMessageAsync(message);

From Event Grid to Event Hubs

Use when you need persistent event storage:

// Before: Event Grid (transient)
// Handler processes and discards

// After: Event Hubs (persistent)
await eventHubClient.SendAsync(new[] { eventData });
// Events retained for replay

Best Practices Summary

ScenarioRecommended Service
IoT telemetryEvent Hubs
Order processingService Bus
Resource monitoringEvent Grid
Real-time analyticsEvent Hubs
Long-running workflowsService Bus + Logic Apps
Cross-region replicationEvent Grid
Data pipeline triggersEvent Grid + Event Hubs

Azure Integration Hub - Advanced Level