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 enabledGeneration 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=obj3. 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=2Strong 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:
| Operation | Guarantee |
|---|---|
| Read-after-write | Object available ngay lập tức sau upload thành công |
| Read-after-metadata-update | Metadata mới visible ngay lập tức |
| Read-after-delete | Object trả về 404 ngay lập tức sau delete |
| List-after-write | Object xuất hiện trong list ngay lập tức |
| List-after-delete | Object biến khỏi list ngay lập tức |
| Bucket list-after-create | Bucket visible ngay lập tức |
| Bucket read-after-metadata-update | Bucket 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 CDNNế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 backoff5. 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:
# 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 immediatelyVới distributed systems có multiple writers, preconditions là cơ chế đúng đắn:
# 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:
- Deletion cost: soft-deleted objects vẫn tốn storage cost trong retention window
- Restoration: có thể restore objects bị xóa nhầm trong window
- Lifecycle interactions: lifecycle delete rule vẫn soft-delete, không hard-delete ngay