Pub/Sub to BigQuery: Ingesta de Streaming sin Servidores con Terraform
Cómo diseñar una arquitectura de streaming en Google Cloud que conecte Pub/Sub directamente con BigQuery, eliminando un pipeline de procesamiento cuando no aporta valor y manteniendo control sobre IAM, esquemas, errores, observabilidad y FinOps.
Lo que aprenderás
El objetivo no es simplemente crear una suscripción, sino saber cuándo esta arquitectura es correcta y cuándo introduce un límite técnico que justifica Dataflow u otro componente de procesamiento.
Conecta Pub/Sub con una tabla BigQuery sin desplegar un consumidor.
Diseña permisos para el servicio de Pub/Sub siguiendo mínimo privilegio.
Controla contratos de datos, columnas y metadatos de los eventos.
Incorpora DLQ, Terraform, observabilidad y decisiones de FinOps.
Stack tecnológico
Una arquitectura mínima, declarativa y orientada a servicios gestionados.
La decisión arquitectónica: ¿BigQuery Subscription o Dataflow?
La pregunta correcta no es "¿qué servicio es más potente?", sino "¿necesito procesamiento entre el evento y el almacenamiento analítico?".
| Patrón | Latencia | Procesamiento | Complejidad operativa | Coste / FinOps | Uso recomendado |
|---|---|---|---|---|---|
| Pub/Sub → BigQuery Subscription | Streaming | Mínimo | Baja | Menor superficie operativa | Ingesta directa y ELT posterior |
| Pub/Sub → Dataflow → BigQuery | Streaming | Alto | Media / Alta | Mayor infraestructura gestionada | Transformaciones, enriquecimiento y lógica compleja |
| Pub/Sub → Cloud Run → BigQuery | Streaming | Personalizable | Media | Depende del patrón de ejecución | Integraciones y lógica específica |
| Pub/Sub → Storage → BigQuery | Batch / micro-batch | Posterior | Media | Optimizable por volumen | Archivado, replay y cargas desacopladas |
Un error frecuente en arquitecturas de streaming es introducir Pub/Sub → Dataflow → BigQuery aunque el único requisito sea persistir el evento en BigQuery.
Esto añade un componente operativo, configuración, observabilidad, capacidad de ejecución y una superficie adicional de costes sin aportar necesariamente valor funcional.
Si no necesitas transformación antes de la persistencia, una BigQuery Subscription puede ser el camino más simple. Si necesitas joins, enriquecimiento, transformaciones complejas o procesamiento avanzado, entonces Dataflow vuelve a estar justificado.
La decisión arquitectónica debe basarse en la transformación requerida, no en la potencia del servicio.
Implementación de producción con Terraform
El siguiente ejemplo crea un topic, una tabla analítica, una suscripción BigQuery, metadata de eventos y un Dead Letter Topic.
terraform {
required_version = ">= 1.6.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 7.45.0"
}
}
}
variable "project_id" {
type = string
description = "Google Cloud project ID"
}
variable "region" {
type = string
default = "europe-southwest1"
}
provider "google" {
project = var.project_id
region = var.region
}
resource "google_project_service" "pubsub" {
service = "pubsub.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "bigquery" {
service = "bigquery.googleapis.com"
disable_on_destroy = false
}
resource "google_pubsub_topic" "events" {
name = "analytics-events"
depends_on = [
google_project_service.pubsub
]
}
resource "google_pubsub_topic" "dead_letter" {
name = "analytics-events-dlq"
depends_on = [
google_project_service.pubsub
]
}
resource "google_bigquery_dataset" "analytics" {
dataset_id = "streaming_analytics"
location = "EU"
depends_on = [
google_project_service.bigquery
]
}
resource "google_bigquery_table" "events" {
dataset_id = google_bigquery_dataset.analytics.dataset_id
table_id = "events"
deletion_protection = true
schema = jsonencode([
{
name = "event_id"
type = "STRING"
mode = "REQUIRED"
},
{
name = "event_type"
type = "STRING"
mode = "NULLABLE"
},
{
name = "customer_id"
type = "STRING"
mode = "NULLABLE"
},
{
name = "event_ts"
type = "TIMESTAMP"
mode = "NULLABLE"
},
{
name = "payload"
type = "JSON"
mode = "NULLABLE"
}
])
}
data "google_project" "current" {}
resource "google_project_iam_member" "pubsub_bigquery_writer" {
project = var.project_id
role = "roles/bigquery.dataEditor"
member = format(
"serviceAccount:service-%s@gcp-sa-pubsub.iam.gserviceaccount.com",
data.google_project.current.number
)
}
resource "google_pubsub_subscription" "bigquery" {
name = "analytics-events-to-bigquery"
topic = google_pubsub_topic.events.id
bigquery_config {
table = "${var.project_id}.${google_bigquery_dataset.analytics.dataset_id}.${google_bigquery_table.events.table_id}"
write_metadata = true
use_table_schema = true
}
dead_letter_policy {
dead_letter_topic = google_pubsub_topic.dead_letter.id
max_delivery_attempts = 10
}
depends_on = [
google_project_iam_member.pubsub_bigquery_writer
]
}
El bloque bigquery_config es la pieza clave: convierte la
suscripción en una ruta de entrega directa hacia BigQuery. Terraform
expone opciones como use_table_schema,
use_topic_schema, write_metadata,
drop_unknown_fields y una cuenta de servicio específica.
El detalle que rompe despliegues: IAM
La arquitectura puede ser correcta y aun así fallar porque Pub/Sub no tiene autorización para escribir en BigQuery.
Default Service Agent
Pub/Sub utiliza normalmente su Service Agent:
service-<PROJECT_NUMBER>@gcp-sa-pubsub.iam.gserviceaccount.com.
Ese principal necesita permisos adecuados sobre BigQuery,
habitualmente mediante roles/bigquery.dataEditor.
Cuenta gestionada por el equipo
Para un modelo de permisos más granular puede utilizarse una cuenta de servicio gestionada por el usuario.
Esto permite separar mejor quién puede crear la suscripción de quién posee permisos efectivos de escritura sobre la tabla.
Schema design: el contrato es parte de la arquitectura
"Streaming directo" no significa "schema libre". La compatibilidad entre el mensaje y la tabla es una de las principales condiciones para que la ruta sea fiable.
Use Table Schema
Permite utilizar el esquema de BigQuery como referencia de las columnas. Los mensajes deben estar publicados en formato JSON compatible con dicho esquema.
- Útil cuando BigQuery es el sistema de contrato.
- Facilita controlar explícitamente las columnas.
- Requiere disciplina de evolución de schema.
Use Topic Schema
Pub/Sub puede utilizar el schema asociado al topic y mapear los campos del mensaje con las columnas BigQuery compatibles.
- Centraliza el contrato cerca del productor.
- Favorece gobernanza de eventos.
- Exige compatibilidad de nombres y tipos.
drop_unknown_fields puede evitar que determinados campos
adicionales impidan una escritura cuando se utiliza schema de topic
o tabla, pero no debe utilizarse como sustituto de una estrategia
formal de evolución de contratos.
En un sistema empresarial, la compatibilidad debe validarse antes de publicar cambios. El objetivo es evitar que un productor despliegue una versión que convierta el backlog de Pub/Sub en una cola de errores.
Patrones de diseño para producción
01. Event Contract First
Define primero el contrato del evento: identificador, timestamp, tipo, entidad, payload y atributos. Después diseña la tabla.
02. Raw → Curated
Mantén la ingesta lo más cercana posible al evento original y realiza transformaciones analíticas posteriormente cuando no sean necesarias durante el transporte.
03. Dead Letter by Default
Los errores de escritura no deberían convertirse en mensajes perdidos ni en reintentos infinitos. Configura una DLQ y monitoriza su crecimiento.
04. Terraform as Control Plane
Topics, subscriptions, datasets, tablas, IAM y políticas deben formar parte de infraestructura declarativa versionada.
05. Least Privilege
Evita permisos excesivos a nivel de proyecto cuando una autorización más granular sobre dataset o tabla sea suficiente.
06. Dataflow cuando existe lógica
Cuando el pipeline necesita joins, enriquecimiento, transformación compleja o procesamiento avanzado, no fuerces una BigQuery Subscription más allá de su propósito.
Framework de implementación empresarial
Una secuencia práctica para pasar de un topic de eventos a una ruta de streaming gobernada.
Define el caso de uso
Determina si necesitas únicamente persistencia analítica o si existe procesamiento obligatorio antes de escribir.
Diseña el contrato
Define schema, tipos, campos obligatorios, estrategia de compatibilidad y evolución.
Crea la tabla BigQuery
Diseña tipos, particionado, clustering y retención en función de los patrones reales de consulta.
Configura IAM
Autoriza al principal que realizará la escritura y evita conceder permisos globales innecesarios.
Implementa la BigQuery Subscription
Configura destino, schema, metadata, política de dead lettering y propiedades de entrega.
Observa el sistema
Monitoriza backlog, errores, throughput, latencia, DLQ y costes. Un pipeline sin observabilidad no está terminado.
Prueba evolución y fallo
Simula schema incompatible, pérdida de permisos, mensajes inválidos y recuperación desde DLQ antes de producción.
Checklist de arquitectura
- ¿La transformación antes de BigQuery es realmente necesaria?
- ¿Existe un contrato de evento explícito?
- ¿La tabla BigQuery tiene un schema compatible?
- ¿El Pub/Sub Service Agent tiene permisos mínimos suficientes?
- ¿Está configurado un Dead Letter Topic?
- ¿Se ha decidido conscientemente si escribir metadata?
- ¿Terraform controla la infraestructura?
- ¿Existe observabilidad sobre backlog y errores?
- ¿Se ha probado la evolución del schema?
- ¿Existe una estrategia para replay y recuperación?
- ¿La arquitectura evita componentes que no aportan valor?
- ¿El coste esperado ha sido evaluado a escala de producción?
Preguntas frecuentes
¿Se puede conectar Pub/Sub con BigQuery sin Dataflow?
Sí. Una BigQuery Subscription permite que Pub/Sub escriba directamente los mensajes recibidos en una tabla de BigQuery sin desplegar un consumidor independiente. Es especialmente adecuada cuando el objetivo es ingerir datos sin transformación compleja.
¿Cuándo debería usar Dataflow en lugar de una BigQuery Subscription?
Cuando el evento necesita procesamiento antes de llegar al modelo analítico: transformaciones complejas, enriquecimiento, joins, ventanas, lógica de negocio, normalización avanzada o pipelines que requieran capacidades propias de un motor de procesamiento.
¿Cómo configuro Pub/Sub to BigQuery con Terraform?
Utiliza google_pubsub_subscription y configura su
bloque bigquery_config. Debes especificar la tabla
destino y, dependiendo del diseño, opciones como
use_table_schema, use_topic_schema,
write_metadata, una cuenta de servicio y una política
de dead lettering.
Sobre el Autor: Eduardo Martínez Agrelo
Eduardo Martínez Agrelo es AI & Data Architect, especializado en arquitectura de datos, ingeniería de plataformas, cloud, inteligencia artificial y diseño de sistemas empresariales. Su enfoque combina profundidad técnica con decisiones arquitectónicas orientadas a escalabilidad, gobierno, rendimiento y eficiencia económica.
