---
cuppy_hub: gcp
cuppy_path: guides/parity/messaging.md
cuppy_section: docs
cuppy_doc: RWQS-QMW5
cuppy_doc_uuid: 5f6d2cd1-bcf1-447e-aa71-975cd657cee7
cuppy_permalink: https://cuppy.io/gcp/d/RWQS-QMW5
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/gcp/docs/guides/parity/messaging
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 1c1995597b5911315c100699ee0d2ff541da0495a1f2aea921c6988c36f86a4c
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Messaging parity

## 1. The names, and the one-to-many problem

| Google Cloud | AWS | Azure |
|---|---|---|
| **Pub/Sub** | SNS + SQS; Kinesis Data Streams; Amazon MQ | **Service Bus**, **Event Grid**, **and Event Hubs** — Microsoft's table gives all three |
| Pub/Sub BigQuery / Bigtable / Cloud Storage subscriptions | Kinesis Data Firehose | Event Hubs Capture, Stream Analytics |
| **Cloud Tasks** | SQS + Lambda event-source mapping; EventBridge Scheduler | Storage queues, Service Bus scheduled enqueue |
| **Eventarc** | **EventBridge** | **Event Grid** |
| Cloud Scheduler | EventBridge Scheduler | Azure Logic Apps, Functions timer triggers |
| Workflows | Step Functions | Logic Apps, Durable Functions |

**Microsoft maps Pub/Sub to three different Azure services in three separate rows.** That is not sloppiness; it
is the shape of the difference. Pub/Sub is one product covering durable queuing, publish/subscribe fan-out and
high-volume ingestion, where Azure splits those across Service Bus, Event Grid and Event Hubs and AWS splits
them across SNS, SQS and Kinesis.

**Estimate consequence, both directions:**

- **to Google Cloud:** two or three messaging products collapse into one. One IAM surface, one client library,
  one set of operational dashboards. Count the removed products as a line.
- **from Google Cloud:** one Pub/Sub estate fans out, and the split is **per topic**, decided by whether that
  topic is really a queue, a fan-out or an ingestion firehose. Do that triage during the estimate, because the
  target product determines the client rewrite.

## 2. There is no partition count to size — and that cuts both ways

| | Google Cloud | AWS Kinesis | Azure Event Hubs |
|---|---|---|---|
| throughput unit | none to configure; **per-message parallelism** | **shards** | **partitions** + throughput units |
| ordering | **ordering keys**, opt-in, per key | per shard, inherent | per partition, inherent |
| consumer parallelism ceiling | per message | one per shard (per consumer group) | one per partition |

**Two readings.**

1. **Moving a Kafka, Kinesis or Event Hubs workload onto Pub/Sub deletes a capacity-planning exercise.** No
   shard count, no partition count, no rebalancing. That is real saved design time and real saved operational
   surface.
2. **But ordering changes shape.** On a partition-based system ordering is free and parallelism is capped by
   partition count. On Pub/Sub parallelism is free and **ordering costs you serialisation per key**. So:
   - if the source used partitions *only* for throughput → the migration simplifies;
   - if it used partitions *for ordering* → you need a high-cardinality ordering key, and a low-cardinality
     one recreates a single-partition topic (`reference/messaging/errors.md` §4).

Going the other way, every Pub/Sub topic needs a partition or shard count invented for it, and that number has
to come from measured throughput.

## 3. Three subscription types delete a consumer service

Pub/Sub's **BigQuery**, **Bigtable** and **Cloud Storage** subscriptions write messages into those services
with no code. The nearest counterparts are Kinesis Data Firehose on AWS and Event Hubs Capture or Stream
Analytics on Azure — and those are **separate services** with their own configuration, their own IAM and, in
two cases, their own bill.

**Estimate consequence.** Look through the source architecture for a consumer whose only job is "read from the
queue, write to the warehouse / the lake / the table". On Google Cloud that is a subscription property. Each
one found is a service deleted — code, deployment, monitoring and on-call — and it is the most commonly missed
saving in a messaging migration.

## 4. Cloud Tasks bundles what the other clouds separate

A Cloud Tasks **queue** is "a managed set of tasks with the same target type and configuration", carrying
**rate limits**, **retry parameters** and **scheduled delivery times**.

| Requirement | Google Cloud | AWS | Azure |
|---|---|---|---|
| per-item HTTP dispatch with a rate limit | **one queue** | SQS + a Lambda event-source mapping with concurrency controls, or a worker | Storage queue or Service Bus + a worker |
| "run this at 14:30 tomorrow" | **a task's scheduled delivery time** | EventBridge Scheduler, or a delayed SQS message (bounded) | Service Bus **scheduled enqueue** |
| dispatch to an **on-premises** endpoint | an HTTP/S target — documented | possible, via a worker | possible, via a worker |

**The estimate line:** one Google Cloud queue often replaces a queue **plus** a scheduler **plus** a worker.
And the documented on-premises HTTP target is useful in a *partial* migration — the queue can move before the
thing it dispatches to does.

## 5. Eventarc against EventBridge and Event Grid

All three route platform events as a managed service, and Eventarc uses the open **CloudEvents** format, which
helps a consumer port.

The row worth carrying: Eventarc's **Cloud Audit Logs** source makes nearly anything audited into a trigger —
the compute family records "90+ event sources through Cloud Audit Logs". Where a source-cloud design has a
hand-written watcher per service, the Google Cloud equivalent may be a trigger. And **Eventarc Advanced**'s
transformation, filtering and schema conversion can replace a function whose only job is reshaping an event
between two systems.

Both are component removals rather than cost moves, which is exactly the kind of row a like-for-like estimate
misses.

## 6. Pricing dimension (never a price)

| | Google Cloud | AWS | Azure |
|---|---|---|---|
| messaging | **data volume** published and delivered, plus storage for retained messages | SNS/SQS: **per request**; Kinesis: **shard-hours** plus payload units | Service Bus: per operation by tier; Event Hubs: **throughput units** plus ingress events |
| task queues | operations | SQS requests | operations |
| event routing | **per event** | per event published | per operation |

**The structural trap:** Google Cloud meters Pub/Sub largely on **bytes**, where SQS and Event Grid meter on
**requests** and Kinesis and Event Hubs on **provisioned capacity**. A messaging estimate converted by message
count alone will be wrong in a direction that depends on message size — small messages are relatively cheaper
on Pub/Sub, large ones relatively dearer than a per-request model. You need the **average message size**, and
`guides/parity-and-migration-method.md` lists it as a required input.

## 7. What this guide cannot tell you

Whether a given consumer is idempotent. Pub/Sub's default is at-least-once, so that question has to be answered
per consumer before a migration, and no table answers it.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 91 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/gcp/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
