Skip to main content

Step 4: Route to Storage

Route each table's data to organized cloud storage paths with compression and appropriate storage classes.

The Goal

  • Route records to table-specific paths
  • Organize by date for easy recovery
  • Compress with Parquet for cost efficiency
  • Use Nearline storage class for backups

Implementation

step-4-route.yaml
output:
switch:
cases:
# Orders table
- check: this._table == "orders"
output:
gcp_cloud_storage:
bucket: '${GCS_BACKUP_BUCKET}'
path: 'backups/orders/${!this._backup_metadata.backup_date}/orders-${!timestamp_unix()}.parquet'
content_type: application/octet-stream
storage_class: NEARLINE
batching:
count: 10000
period: 60s
parquet_encoding:
compression: SNAPPY

# Inventory table
- check: this._table == "inventory"
output:
gcp_cloud_storage:
bucket: '${GCS_BACKUP_BUCKET}'
path: 'backups/inventory/${!this._backup_metadata.backup_date}/inventory-full.parquet'
content_type: application/octet-stream
storage_class: NEARLINE
batching:
count: 50000
period: 120s
parquet_encoding:
compression: SNAPPY

# Order items table
- check: this._table == "order_items"
output:
gcp_cloud_storage:
bucket: '${GCS_BACKUP_BUCKET}'
path: 'backups/order_items/${!this._backup_metadata.backup_date}/items-${!timestamp_unix()}.parquet'
content_type: application/octet-stream
storage_class: NEARLINE
batching:
count: 10000
period: 60s
parquet_encoding:
compression: SNAPPY

# Fallback for unknown tables
- output:
gcp_cloud_storage:
bucket: '${GCS_BACKUP_BUCKET}'
path: 'backups/unknown/${!this._table}/${!this._backup_metadata.backup_date}/data-${!timestamp_unix()}.json'
content_type: application/json
storage_class: NEARLINE
batching:
count: 1000
period: 30s

Understanding the Code

ComponentPurpose
switch.casesRoute based on _table field
${!this._backup_metadata.backup_date}Dynamic path from record
${!timestamp_unix()}Unique file suffix
storage_class: NEARLINEAuthored storage-class choice
parquet_encoding.compression: SNAPPYAuthored codec choice

Choose a Storage Class

Provider pricing changes by region, operation, retention period, retrieval pattern, and contract. Use the current provider calculator and your measured access pattern; this repository does not pin a price table.

Evaluate Parquet

Measure object size, encode/decode behavior, restore behavior, and downstream query plans with representative records before choosing an encoding. This example supplies no compression or query benchmark.

Path Organization

gs://backup-bucket/
└── backups/
├── orders/
│ ├── 2024-01-14/
│ │ ├── orders-1705190400.parquet
│ │ └── orders-1705194000.parquet
│ └── 2024-01-15/
│ └── orders-1705276800.parquet
├── inventory/
│ └── 2024-01-15/
│ └── inventory-full.parquet
└── order_items/
└── 2024-01-15/
└── items-1705276800.parquet

Production Considerations

AWS S3 Alternative

output:
aws_s3:
bucket: '${S3_BACKUP_BUCKET}'
path: 'backups/orders/${!this._backup_metadata.backup_date}/orders-${!timestamp_unix()}.parquet'
storage_class: GLACIER_IR # Similar to Nearline
batching:
count: 10000

Encryption at Rest

Enable server-side encryption:

gcp_cloud_storage:
# GCS encrypts by default, but for customer-managed keys:
kms_key_name: 'projects/.../cryptoKeys/backup-key'

Retention with Object Lifecycle

# Set via gsutil (delete after 1 year)
gsutil lifecycle set lifecycle.json gs://${GCS_BACKUP_BUCKET}

Complete Pipeline

You've built all 4 backup steps! See the complete configuration: