Skip to content

Performance: Throughput Scaling & Parallel Operations

Tại Sao Quan Trọng Trong Production

GCS không phải block storage — throughput không phụ thuộc vào provisioned capacity. Thay vào đó, throughput phụ thuộc vào request rate patternobject naming strategy. Hiểu sai model này dẫn đến hai failure modes: hotspotting (request tập trung vào prefix nhỏ → throttle) và under-utilization (không parallelize đủ → 10x slower than achievable). Với ML training pipelines hay data processing at scale, chênh lệch có thể là vài giờ vs vài phút.


Internal Model — Auto-Scaling Request Handling

GCS Không Có "Provisioned Throughput"

Khác với Persistent Disk hay Filestore (cần provision IOPS), GCS auto-scale throughput dựa trên demand. Nhưng không phải vô hạn ngay lập tức — có baseline capacityscale-up mechanism.

Baseline capacity mặc định:

  • ~1,000 write requests/giây (per bucket)
  • ~5,000 read requests/giây (per bucket)

Với object size 1MB, điều này tương đương:

  • Write: ~1 GB/s
  • Read: ~5 GB/s

Baseline này apply cho tổng bucket, không phải per-prefix hay per-object.

Auto-Scaling Mechanism — Gradual Ramp-Up

Khi workload vượt baseline, GCS tự động scale bằng cách redistribute load across more servers. Nhưng quá trình này mất thời gian:

Theo GCP documentation: "Cloud Storage typically takes on the order of minutes to detect and accordingly redistribute the load."

Trong thời gian transition, requests vượt baseline có thể nhận:

  • Higher latency (server load tăng)
  • 429 Too Many Requests errors (temporary throttle)
  • 503 Service Unavailable (server overload)

Implication cho production: Không thể đột ngột spike từ 100 req/s lên 10,000 req/s. Cần gradual ramp-up:

# Recommended ramp-up pattern
# Tăng không nhanh hơn 2x mỗi 20 phút
Giờ 0:    100 req/s
Giờ 0:20  200 req/s
Giờ 0:40  400 req/s
Giờ 1:00  800 req/s
...

Với migration jobs hay batch processing lớn, bắt đầu từ số nhỏ và tăng dần.

Hierarchical Namespace (HNS) Buckets

Buckets với hierarchical namespace enabledbaseline cao hơn 8x:

  • Write: ~8,000 req/s initial
  • Read: ~40,000 req/s initial

HNS cũng enable atomic directory operations và better directory listing performance. Đây là default recommendation cho high-throughput workloads (AI/ML data pipelines, analytics).


Object Naming Strategy — Hotspot Avoidance

Cơ Chế Phân Tải Theo Prefix

GCS distribute load theo lexicographic prefix ranges. Internal sharding assign ranges của key space cho các servers:

Server A: "aaa..." - "mzz..."
Server B: "n..." - "zzz..."

Nếu tất cả objects của bạn có prefix 2024-01-01-, mọi requests đều đến cùng shard → hotspot.

Sequential Naming — Anti-Pattern

# Hotspot pattern:
log-2024-01-01-000001.gz
log-2024-01-01-000002.gz
log-2024-01-01-000003.gz
...
# Tất cả bắt đầu bằng "log-2024-01-01-" → cùng shard

Sequential names (timestamps, counters) tập trung traffic vào narrow prefix range → single shard bị overwhelm.

Random Prefix — Cách Đúng

python
import hashlib
import time

def distributed_object_name(base_name: str) -> str:
    # Tính MD5 hash của tên gốc
    hash_prefix = hashlib.md5(base_name.encode()).hexdigest()[:6]
    return f"{hash_prefix}-{base_name}"

# Output:
# "a3f2c1-log-2024-01-01-000001.gz"  → shard 'a'
# "b7d4e2-log-2024-01-01-000002.gz"  → shard 'b'
# "f1a8c3-log-2024-01-01-000003.gz"  → shard 'f'

Với single hex character prefix, có 16 possible prefixes → distribute across ~16 shards. Hai hex characters → 256 prefixes → tốt hơn.

Tradeoff: Object listing không còn sequential theo thời gian — cần metadata (BigQuery table, Firestore) để track nếu cần ordered access.

Khi Sequential Naming Acceptable

Nếu write rate thấp (< 1000 req/s) và objects có distribution tự nhiên đủ rộng, sequential naming không nhất thiết gây vấn đề. Chỉ cần random prefix khi:

  • Write rate cao (> 1000 req/s)
  • Nhiều objects chia sẻ long common prefix
  • Cần maximum throughput

Parallel Operations

Parallel Uploads — Multipart và Composite Objects

Resumable uploads (cho files > 5MB) upload từng chunk sequentially qua HTTP. Single-stream throughput bị giới hạn bởi:

  • Network latency (RTT)
  • TCP window size
  • Một connection duy nhất

Parallel upload pattern: Chia file thành nhiều chunks, upload song song, compose thành object cuối:

python
from google.cloud import storage
import concurrent.futures

def parallel_upload(bucket_name: str, object_name: str, file_path: str, chunk_size_mb: int = 32):
    client = storage.Client()
    bucket = client.bucket(bucket_name)
    
    # Đọc file và chia thành chunks
    chunks = read_chunks(file_path, chunk_size_mb * 1024 * 1024)
    part_names = []
    
    def upload_chunk(i, data):
        part_name = f"{object_name}.part.{i:04d}"
        blob = bucket.blob(part_name)
        blob.upload_from_string(data)
        return part_name
    
    # Upload song song
    with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor:
        futures = {executor.submit(upload_chunk, i, data): i
                   for i, data in enumerate(chunks)}
        for future in concurrent.futures.as_completed(futures):
            part_names.append(future.result())
    
    # Sort parts theo thứ tự
    part_names.sort()
    
    # Compose thành final object
    destination = bucket.blob(object_name)
    sources = [bucket.blob(name) for name in part_names]
    destination.compose(sources)
    
    # Cleanup parts
    for name in part_names:
        bucket.blob(name).delete()

Composite Objects là GCS feature cho phép compose tối đa 1024 component objects thành 1 object. Mỗi component tối đa 5 TiB → total composite object tối đa 5 TiB.

composeserver-side operation — không cần download và re-upload data. GCS concatenate components on server. Tuy nhiên, composed object có một limitation: không có MD5 checksum (do GCS không biết tổng checksum khi compose). CRC32c checksum vẫn available.

Parallel Downloads

Download throughput scale bằng cách:

1. Multiple parallel requests cho different objects:

python
def parallel_download(objects: list, local_dir: str):
    with concurrent.futures.ThreadPoolExecutor(max_workers=32) as executor:
        futures = [
            executor.submit(download_object, obj, local_dir)
            for obj in objects
        ]
        for f in concurrent.futures.as_completed(futures):
            f.result()

2. Range requests cho single large object:

python
def download_large_object(bucket_name: str, object_name: str, output_path: str):
    client = storage.Client()
    blob = client.bucket(bucket_name).blob(object_name)
    
    size = blob.size
    chunk_size = 64 * 1024 * 1024  # 64MB chunks
    
    def download_range(start, end):
        with blob.open("rb") as f:
            f.seek(start)
            return f.read(end - start)
    
    chunks = []
    with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
        futures = [
            executor.submit(download_range, start, min(start + chunk_size, size))
            for start in range(0, size, chunk_size)
        ]
        chunks = [f.result() for f in futures]
    
    with open(output_path, "wb") as f:
        for chunk in chunks:
            f.write(chunk)

GCS support range reads (Range: bytes=start-end header) — không cần download toàn bộ object chỉ để đọc một portion.


Performance Ceilings Thực Tế

Per-Object Throughput

Một single object download bị giới hạn bởi:

  • Single TCP connection bandwidth
  • Network egress bandwidth của VM
  • GCS per-object streaming rate

GCS không publish per-object cap chính thức, nhưng trong practice:

  • Regional bucket, same region VM: ~1-2 Gbps per connection
  • Multi-region bucket: lower và variable

Để maximize throughput cho single large object: dùng parallel range reads.

Aggregate Bucket Throughput

Với đủ parallelism và tốt object naming, aggregate bucket throughput của GCS có thể đạt hundreds of Gbps. Điều này không phải cap mà là practical limit dựa trên:

  • Number of parallel requests
  • Object size distribution (nhỏ → overhead cao hơn)
  • Network capacity của client

Client-Side Bottlenecks

Thường bottleneck không phải GCS mà là:

1. Network bandwidth của VM:

n1-standard-4: ~10 Gbps (burst), ~2 Gbps sustained
c2-standard-8: ~32 Gbps

Nếu cần > 10 Gbps throughput từ GCS, cần nhiều VMs hoặc VMs với high-bandwidth.

2. CPU cho checksum computation:

CRC32c được hardware-accelerated trên modern CPUs (ARM và x86 với SSE4.2). MD5 không được hardware-accelerated → có thể bottleneck ở CPU với high-throughput downloads.

3. Disk I/O:

Write speed của local disk thường là bottleneck cho download pipelines. Local SSD (~800MB/s) vs standard HDD (~200MB/s).


Best Practices Summary

SituationRecommendation
> 1000 req/s write rateRandom prefix cho object names
Large file upload (> 100MB)Parallel upload + compose
Many objects downloadThreadPoolExecutor với 16-64 workers
Single large downloadParallel range requests
Gradual scale-upDouble request rate mỗi 20 phút
High-throughput AI/MLBuckets với HNS enabled
On-prem dataTransfer Service + dedicated agents

References