Penyimpanan objek adalah lapisan penyimpanan yang menopang data lake, tempat berkas data mentah menumpuk sebelum diolah lebih lanjut. Topik ini membahas model datanya, yaitu objek, bucket, dan kunci, kemudian melanjutkan ke skema partisi yang membuat kumpulan objek tetap dapat dijelajahi pada skala besar. Pola penelusuran objek per partisi didemonstrasikan dengan simulasi penyimpanan di dalam memori yang dijalankan langsung, sehingga perilakunya terlihat tanpa perlu akun cloud.
Objek, bucket, dan kunci#
Satu objek terdiri atas data beserta metadata yang mengelilinginya, dan keduanya disimpan sebagai satu kesatuan yang tidak dapat diubah sebagian. Isi datanya bisa berupa apa saja, mulai dari berkas CSV, Parquet, gambar, hingga arsip cadangan, sedangkan metadatanya mencatat urusan seperti ukuran, tipe konten, dan waktu terakhir diubah. Objek ditempatkan di dalam bucket, yakni wadah bernama yang menjadi ruang nama (namespace) atas seluruh objek di dalamnya, dan nama bucket wajib unik pada layanan penyimpanan itu.
Penempatan dan pengambilan objek seluruhnya dilakukan lewat kunci (key), yaitu rangkaian karakter yang menjadi nama lengkap sebuah objek. Kunci seperti data/pengukuran/tahun=2024/bulan=05/pengukuran-01.csv memang tampak seperti jalur direktori, tetapi penyimpanan objek tidak mengenal direktori sungguhan. Yang ada hanyalah kumpulan kunci yang datar, dan garis miring di dalamnya hanyalah konvensi penamaan yang dijunjung seluruh alat di ekosistemnya.
Konvensi itu tetap berarti, karena operasi penelusuran objek (listing) menerima parameter prefix, yakni awalan kunci yang menyaring hasilnya. Listing dengan awalan data/pengukuran/tahun=2024/ hanya mengembalikan kunci yang berawalan demikian, dan itulah satu-satunya alat penjelajahan yang diberikan layanan ini. Bagian berikut menunjukkan bagaimana skema kunci yang tertata membuat alat sesederhana itu cukup untuk data dalam jumlah besar.
Metadata dan sifat tulis-ulang#
Metadata pada objek terbagi dua kelompok, yaitu metadata sistem yang dikelola layanan dan metadata pengguna yang ditetapkan saat objek ditulis. Metadata sistem mencakup ukuran, tipe konten (content type), waktu terakhir diubah, dan ETag, yakni tanda yang mewakili isi objek dan berubah ketika isinya berubah. Metadata pengguna berupa pasangan kunci dan nilai bebas, misalnya sumber data dan tanggal pemuatan, yang berguna untuk menyaring objek tanpa membaca isinya. Keduanya terbaca melalui API tanpa mengunduh data objeknya, sehingga inventaris besar dapat dipetakan dengan murah.
Sifat yang paling sering dilupakan adalah objek tidak dapat diubah sebagian. Menambah satu baris pada berkas CSV berarti menulis ulang seluruh objeknya, dan tidak ada operasi semacam menambah di akhir berkas. Pola yang cocok dengan kenyataan ini adalah menulis objek baru untuk setiap batch, misalnya satu objek per tanggal pemuatan, lalu membiarkan objek lama tetap utuh sebagai riwayat. Pipeline yang menimpa objek yang sama dengan isi baru kehilangan riwayat itu, dan kehilangan tersebut baru terasa ketika data lama justru dibutuhkan.
Skema partisi untuk data lake#
Skema partisi mengatur kunci objek menjadi segmen bertingkat, biasanya tahun, bulan, dan hari, sehingga setiap partisi dapat ditelusuri tanpa menyentuh yang lain. Struktur berikut adalah bentuk yang lazim untuk data pengukuran sensor.
data/
└── pengukuran/
└── tahun=2024/
├── bulan=04/
│ ├── pengukuran-01.csv
│ └── pengukuran-02.csv
├── bulan=05/
│ ├── pengukuran-01.csv
│ └── pengukuran-02.csv
├── bulan=06/
│ ├── pengukuran-01.csv
│ └── pengukuran-02.csv
└── bulan=07/
├── pengukuran-01.csv
└── pengukuran-02.csvPenamaan tahun=2024 dan bulan=05 mengikuti gaya Hive, yaitu pola kunci sama dengan nilai yang dikenali warehouse modern sebagai kolom partisi. Ketika sebuah tabel eksternal diarahkan ke struktur seperti ini, filter tanggal pada query langsung menjadi filter partisi, sehingga hanya sebagian kecil objek yang dibaca. Skema partisi dengan demikian menghubungkan dua dunia, yaitu listing pada penyimpanan objek dan pemangkasan partisi pada warehouse.
Granularitasnya adalah keputusan desain yang menyeimbangkan dua arah. Partisi per hari cukup halus untuk query rentang waktu, sedangkan partisi per menit melahirkan objek kecil yang jumlahnya meledak dan memperlambat segalanya. Pilih tingkatan mengikuti pola filter yang benar-benar dipakai, lalu biarkan segmen terkecilnya tetap memuat beberapa berkas utuh.
Demonstrasi listing per partisi#
Perilaku bucket dan listing prefix dapat disimulasikan dengan kelas Python sederhana yang menyimpan data di dalam memori, dan simulasi ini mengikuti model S3 yang sengaja disederhanakan. Skrip berikut menulis delapan objek pengukuran dengan kunci terpartisi, kemudian menampilkan daftar seluruh kunci, daftar kunci pada satu partisi, dan metadata salah satu objeknya.
class Bucket:
"""Simulasi penyimpanan objek sederhana di memori.
Setiap objek disimpan sebagai pasangan kunci dan isi, beserta metadata.
"""
def __init__(self, nama: str) -> None:
self.nama = nama
self.data: dict[str, bytes] = {}
self.metadata: dict[str, dict] = {}
def put(self, kunci: str, isi: bytes, tipe: str = "application/octet-stream") -> None:
self.data[kunci] = isi
self.metadata[kunci] = {"ukuran": len(isi), "tipe": tipe}
def list(self, prefix: str = "") -> list[str]:
return sorted(k for k in self.data if k.startswith(prefix))
def describe(self, kunci: str) -> dict:
return self.metadata[kunci]
bucket = Bucket("data-pengukuran")
# 1. tulis objek dengan kunci terpartisi tahun dan bulan
for bulan in ("04", "05", "06", "07"):
for urutan in (1, 2):
kunci = f"data/pengukuran/tahun=2024/bulan={bulan}/pengukuran-{urutan:02d}.csv"
isi = "sensor,suhu_c\nS-1,24.0\nS-2,25.5\n".encode()
bucket.put(kunci, isi, tipe="text/csv")
print(f"seluruh kunci ({len(bucket.list())} objek):")
for k in bucket.list():
print(" -", k)
# 2. listing dengan prefix satu partisi saja
prefix = "data/pengukuran/tahun=2024/bulan=05/"
print("kunci pada partisi bulan=05:")
for k in bucket.list(prefix):
print(" -", k[len(prefix):])
# 3. metadata salah satu objek
kunci = "data/pengukuran/tahun=2024/bulan=04/pengukuran-01.csv"
print("metadata:", bucket.describe(kunci))seluruh kunci (8 objek):
- data/pengukuran/tahun=2024/bulan=04/pengukuran-01.csv
- data/pengukuran/tahun=2024/bulan=04/pengukuran-02.csv
- data/pengukuran/tahun=2024/bulan=05/pengukuran-01.csv
- data/pengukuran/tahun=2024/bulan=05/pengukuran-02.csv
- data/pengukuran/tahun=2024/bulan=06/pengukuran-01.csv
- data/pengukuran/tahun=2024/bulan=06/pengukuran-02.csv
- data/pengukuran/tahun=2024/bulan=07/pengukuran-01.csv
- data/pengukuran/tahun=2024/bulan=07/pengukuran-02.csv
kunci pada partisi bulan=05:
- pengukuran-01.csv
- pengukuran-02.csv
metadata: {'ukuran': 32, 'tipe': 'text/csv'}Listing dengan prefix data/pengukuran/tahun=2024/bulan=05/ hanya mengembalikan dua objek dari delapan kunci yang ada, dan kunci lainnya tidak pernah disentuh. Pada penyimpanan objek sungguhan, mekanisme yang sama membuat penelusuran satu bulan tidak perlu mencacah seluruh bucket, dan biayanya sepadan dengan jumlah kunci yang dikembalikan, bukan jumlah objek di dalam bucket. Metadata yang dicetak pada bagian akhir menunjukkan ukuran dan tipe konten yang tersimpan di sisi layanan, sehingga informasi itu tersedia tanpa mengunduh isinya.
Kesalahan umum#
Kesalahan berikut muncul ketika penyimpanan objek diperlakukan seperti sistem berkas biasa, dan masing-masing menyertakan perbaikannya.
- Mengandalkan operasi yang tidak ada. Mengubah nama, menambah di akhir berkas, dan menyunting sebagian isi tidak tersedia di sini, sehingga kode yang mengasumsikan hal itu akan gagal atau menimpa data. Susun pola tulis objek baru untuk setiap batch, dan beri kuncinya nama unik, misalnya dengan tanggal pemuatan.
- Menulis kunci tanpa skema. Kunci seperti
unduhan/lampiran-20240510-abc.csvtanpa segmen partisi memaksa listing menyapu seluruh bucket ketika satu periode dicari. Tambahkan segmen tahun dan bulan pada kuncinya, sehingga penelusuran per periode menjadi murah. - Membuat partisi terlalu halus. Partisi per menit pada data yang terus mengalir menghasilkan ratusan ribu objek kecil per bulan, sehingga listing dan metadata membengkak. Pilih granularitas harian atau bulanan, kemudian gabungkan objek kecil secara berkala bila perlu.
Ringkasan#
- Objek terdiri atas data dan metadata yang tersimpan sebagai satu kesatuan, dialamatkan dengan kunci datar di dalam bucket sebagai ruang nama.
- Direktori pada kunci hanyalah konvensi prefix, dan listing dengan prefix menjadi satu-satunya alat penelusurannya.
- Skema partisi tahun dan bulan menghubungkan listing penyimpanan objek dengan pemangkasan partisi pada warehouse.
- Objek tidak dapat diubah sebagian, sehingga pola pipeline yang cocok adalah menulis objek baru untuk setiap batch.
Referensi#
- What is Amazon S3? — Amazon Web Services — Model data S3, yaitu bucket, objek, kunci, dan API dasarnya.
- Working with object metadata — Amazon Web Services — Metadata sistem dan metadata pengguna yang melekat pada objek.
- Listing objects in Amazon S3 — Amazon Web Services — Cara listing objek dengan prefix dan opsionalnya.