Skip to content

Object Model, Buckets, Generations & Consistency

Tại Sao Quan Trọng Trong Production

GCS không phải filesystem. Hiểu nhầm object semantics dẫn đến hai class lỗi nghiêm trọng: data races khi nhiều writers cùng ghi một object, và stale reads khi code assume eventual consistency trong khi GCS đã strong consistent — hoặc ngược lại, assume strong consistent trong các trường hợp ngoại lệ thực sự tồn tại. Phần lớn bug GCS trong production đến từ việc không hiểu generation numbers và consistency scope.


Internal Model — Cách GCS Thực Sự Vận Hành

Bucket Namespace — Global, Flat, Immutable

Bucket name trong GCS là global unique namespace — không phải per-project, không phải per-organization. Một bucket tên my-data chỉ tồn tại một trên toàn bộ GCS. Điều này có hệ quả trực tiếp:

  • Bucket name là immutable sau khi tạo. Không đổi tên bucket được, chỉ tạo mới và migrate.
  • Naming conflict là thật: nếu bucket name bị chiếm (kể cả bởi account đã xóa), không tạo lại được với cùng tên trong vòng vài phút đến vài giờ (soft-delete window).
  • Bucket chứa metadata về location, storage class, IAM, encryption — nhưng không chứa data. Data sống ở object layer.

Trong resource model của GCP, bucket được identify bằng projects/_/buckets/BUCKET_NAME (dấu underscore _ là wildcard cho project). Object được identify bằng projects/_/buckets/BUCKET_NAME/objects/OBJECT_NAME.

Object Model — Immutable Key-Value Pairs

Object trong GCS là immutable blob gắn với một key (tên object). Khi bạn "cập nhật" một object, GCS không patch in-place — nó replace toàn bộ object với một version mới và assign một generation number mới. Object cũ (nếu versioning bật) trở thành noncurrent version.

Điều này có ý nghĩa quan trọng:

# Không tồn tại khái niệm "append" native trên GCS object
# Mọi write đều là full object replacement
PUT /bucket/object → tạo generation mới, thay thế generation cũ

Object có hai loại metadata:

  • Object data: raw bytes, bất biến với generation
  • Object metadata: Content-Type, custom metadata fields, hệ thống metadata như storageClass, size, timeCreated — có thể update độc lập với generation

Generation Numbers — Fingerprint Của Mỗi Version

Mỗi object khi được tạo (upload, compose, copy, rewrite) đều nhận một generation number — số nguyên 64-bit microsecond timestamp. Generation number là định danh duy nhất toàn cầu cho một version cụ thể của một object.

# Object tại gs://my-bucket/data.json
# Lần upload đầu:
generation = 1360887697105000

# Replace bởi upload mới:
generation = 1360887759327000

# Cả hai version vẫn tồn tại nếu versioning enabled

Generation number có ba vai trò quan trọng trong production:

1. Precondition Guards — Tránh Data Race

GCS hỗ trợ conditional operations dựa trên generation:

# Chỉ upload nếu object chưa tồn tại (generation = 0)
PUT /bucket/obj?ifGenerationMatch=0

# Chỉ upload nếu đang replace đúng version này
PUT /bucket/obj?ifGenerationMatch=1360887697105000

# Chỉ update metadata nếu metadata chưa bị thay đổi
PATCH /bucket/obj?ifMetagenerationMatch=3

Đây là cơ chế optimistic locking của GCS. Nếu condition không match, GCS trả về 412 Precondition Failed. Đây là cách duy nhất implement read-modify-write an toàn trên GCS mà không cần external locking.

2. Versioning — Lịch Sử Thay Đổi

Khi object versioning bật, mỗi lần replace tạo ra một noncurrent version giữ nguyên generation cũ. Để truy cập noncurrent version:

# Truy cập version cụ thể
GET /bucket/obj?generation=1360887697105000

# List tất cả versions
GET /bucket/?versions=true&prefix=obj

3. Deletion Semantics

Khi xóa object không có versioning: object bị xóa vĩnh viễn (hoặc soft-deleted nếu soft delete enabled).

Khi xóa object có versioning: live version trở thành noncurrent với một delete marker — generation mới không có data được tạo để đánh dấu deletion. Object "disappears" cho reads thông thường nhưng vẫn có thể truy cập qua generation.

Metageneration — Version Của Metadata

Mỗi object còn có metageneration — counter tăng mỗi khi metadata của object thay đổi mà không thay đổi data. Ví dụ:

  • Upload object: generation = 123, metageneration = 1
  • Update Content-Type metadata: generation vẫn là 123, metageneration = 2
  • Replace object: generation = 456, metageneration = 1 (reset)

Metageneration dùng cho conditional metadata operations:

# Chỉ update metadata nếu không ai đã thay đổi trước
PATCH /obj?ifMetagenerationMatch=2

Strong Consistency Model Post-2021

Lịch Sử Và Tại Sao Thay Đổi

Trước tháng 11/2020, GCS implement eventual consistency cho list operations và read-after-delete. Điều này nghĩa là sau khi upload một object, một list request ngay lập tức có thể không thấy object đó. Đây là nguồn gốc của nhiều race condition trong pipeline.

Từ tháng 11/2020, GCS chuyển sang strong consistency cho tất cả operations, kể cả multi-region buckets.

Theo Google Cloud documentation: "When you write an object to Cloud Storage, such as when you upload, compose, or copy an object, the object is immediately available for reading and metadata operations" sau khi nhận success response.

Các Operation Được Đảm Bảo Strong Consistent

GCS guarantee strong consistency cho:

OperationGuarantee
Read-after-writeObject available ngay lập tức sau upload thành công
Read-after-metadata-updateMetadata mới visible ngay lập tức
Read-after-deleteObject trả về 404 ngay lập tức sau delete
List-after-writeObject xuất hiện trong list ngay lập tức
List-after-deleteObject biến khỏi list ngay lập tức
Bucket list-after-createBucket visible ngay lập tức
Bucket read-after-metadata-updateBucket metadata cập nhật ngay lập tức

Điều này áp dụng kể cả cho dual-region và multi-region buckets — ngay cả khi data chưa được replicate hoàn toàn sang tất cả regions.

Cơ Chế Đảm Bảo Consistency

GCS achieve strong consistency thông qua một metadata service tập trung quản lý directory listing và object existence. Khi bạn nhận success response từ upload, metadata service đã commit thông tin về object. Reads sau đó đi qua cùng metadata service này — không có stale cache path cho authenticated requests.

Điều này giải thích tại sao strong consistency work ngay cả với multi-region: metadata service commit xảy ra trước khi response trả về client, đảm bảo reads sau đó thấy đúng state. Data replication sang các regions khác có thể xảy ra asynchronously, nhưng metadata (existence, generation, size, checksum) đã consistent.

Khi Nào Không Có Strong Consistency — Edge Cases Quan Trọng

GCS documentation liệt kê các trường hợp ngoại lệ mà strong consistency không hoàn toàn áp dụng:

1. Cached Public Objects

Objects được serve qua Cloud CDN hoặc cache HTTP không nhất thiết reflect strong consistency. Cache lifetime (TTL) kiểm soát khi nào update visible. Đây là behavior đúng — không phải bug.

# Object với Cache-Control: public, max-age=3600
# Sau khi replace object, users có thể thấy version cũ
# trong tối đa 1 giờ qua CDN

Nếu cần invalidate ngay: sử dụng Cloud CDN cache invalidation API.

2. HMAC Key State Changes

Khi thay đổi trạng thái HMAC key (enable/disable), có delay lên đến 3 phút trước khi state change có hiệu lực. HMAC keys được dùng với HMAC-SHA256 authentication cho XML API compatibility (tương tự AWS S3 HMAC auth).

3. Bucket Configuration Propagation

Một số bucket configuration changes (như bật object versioning) cần ít nhất 30 giây trước khi effective. Nếu code bật versioning rồi ngay lập tức xóa objects, race condition có thể xảy ra.

4. Regional Failure Scenario

Trong tình huống hiếm gặp khi original region fail trước khi replication hoàn thành sang secondary region, GCS trả về retryable 500 error thay vì serve stale data. Đây là trade-off có chủ đích: better to fail than serve wrong data.

# Khi region fail và replication chưa xong:
# GCS trả 500 (retryable) — KHÔNG trả stale data
# Client nên retry với exponential backoff

5. Batch Operations Không Atomic

Batch API của GCS không phải atomic transaction — operations trong batch có thể partially fail. Không có rollback mechanism.

Implication Cho Application Design

Sự chuyển đổi sang strong consistency có nghĩa là nhiều workaround viết trước 2021 giờ không cần thiết — nhưng cũng có thể có hidden assumptions trong legacy code:

python
# Anti-pattern (legacy): sleep sau upload để "đảm bảo" availability
client.upload(bucket, object_name, data)
time.sleep(2)  # Không cần thiết nữa kể từ 2020

# Correct pattern hiện tại:
response = client.upload(bucket, object_name, data)
# Sau khi nhận success response, object guaranteed available
client.download(bucket, object_name)  # Safe to read immediately

Với distributed systems có multiple writers, preconditions là cơ chế đúng đắn:

python
# Pattern an toàn cho read-modify-write
current_obj = client.get_object_with_generation(bucket, name)
new_data = transform(current_obj.data)

# Chỉ write nếu không ai đã thay đổi object
client.upload(
    bucket, name, new_data,
    if_generation_match=current_obj.generation
)
# Nếu 412: retry từ đầu (read lại → modify → write)

Constraints & Failure Modes

Object Size Limits

  • Tối đa 5 TiB per object với resumable upload
  • Simple upload (non-resumable): 5 MiB limit
  • Composite object: tối đa 1024 component objects, kết quả tối đa 5 TiB

Với file lớn hơn 5 MiB, resumable upload là bắt buộc. Resumable upload tạo một upload session URL, cho phép resume nếu connection bị đứt — GCS checksum từng chunk.

Bucket Limits

  • Tối đa 1000 buckets per project (soft limit, có thể tăng)
  • Không giới hạn số objects trong bucket
  • Metadata per object: tối đa 8 KiB (tên + metadata + ACLs gộp lại)

Object Name Constraints

Object name tối đa 1024 bytes UTF-8. Các ký tự cần tránh trong production:

  • # — gây nhầm lẫn với URL fragment
  • [, ], *, ? — shell glob expansion
  • Ký tự control (newline, tab...)
  • .. prefix — risk với tools assume filesystem semantics

Soft Delete

Kể từ 2024, GCS có soft delete — objects bị xóa được retain trong 7 ngày (configurable 7–90 ngày) trước khi permanently deleted. Điều này ảnh hưởng đến:

  1. Deletion cost: soft-deleted objects vẫn tốn storage cost trong retention window
  2. Restoration: có thể restore objects bị xóa nhầm trong window
  3. Lifecycle interactions: lifecycle delete rule vẫn soft-delete, không hard-delete ngay

References