Migrasi DynamoDB Tanpa Downtime
Datang dari SQL, sebuah migrasi adalah sebuah ALTER TABLE yang mengunci tabel
selagi ia menulis ulang setiap baris. DynamoDB tak punya skema untuk diubah —
item bersifat schemaless, jadi menambahkan sebuah atribut atau tipe entitas baru
itu gratis.
Bagian sulitnya adalah pola akses yang harus dilayani data baru, dan membentuk ulang data yang hidup untuk melayaninya tanpa penulisan ulang stop-the-world.
Bagaimana cara migrasi tabel DynamoDB tanpa downtime?
DynamoDB tidak memiliki ALTER TABLE, sehingga migrasi tidak pernah mengunci tabel. Anda menambahkan atribut, bentuk key baru, atau GSI baru secara online dengan UpdateTable, lalu membentuk ulang data yang hidup secara bertahap: backfill item lama saat baca (lazy) atau dengan sapuan yang dibatasi throttle, dan dual-write kedua format selama transisi. Tidak ada cutover flag-day.
- Tidak ada
ALTER TABLE. Item bersifat schemaless. Sebuah "migrasi" berarti menambah atribut, sebuah bentuk key baru, atau sebuah indeks baru — bukan menulis ulang himpunan kolom tetap. - Penulisan baru mudah; item lama adalah masalahnya. Baris yang ada tak membawa atribut baru, jadi indeks atau query baru apa pun diam-diam melewatkan mereka sampai Anda mem-backfill.
- Tambah indeks secara online, backfill secara lazy.
UpdateTablemembangun sebuah GSI pada tabel yang hidup; backfill item lama saat baca (lazy) atau dengan sapuan terkendali — tidak pernah cutover flag-day. - Dual-write sepanjang transisi. Selagi kedua bentuk hidup berdampingan, tulis format lama dan baru bersama agar tak ada jalur baca yang basi.
Bingkai sebagai pola akses, bukan sebuah kolom
Misalkan Anda menjalankan sebuah produk workspace SaaS pada satu tabel. Item
memakai PK = "WS#<id>" dan SK di-overload per entitas:
| PK | SK | attributes |
|---|---|---|
| WS#a91 | META | name, tier |
| WS#a91 | DOC#2026-04-01#x7 | title, author, body |
| WS#a91 | DOC#2026-04-02#k2 | title, author, body |
Kini produk menginginkan komentar pada dokumen, plus sebuah read baru: "daftarkan setiap komentar yang ditulis seorang member di seluruh workspace, terbaru dulu." Klausa terakhir itu adalah migrasinya. Sebuah tipe entitas baru saja itu sepele; melayani sebuah query yang key saat ini tak bisa jawab adalah kerjanya.
Tambahkan tipe entitas baru lebih dulu
Komentar hanyalah item baru di partition yang sama — tanpa upacara migrasi, tanpa tabel baru:
| PK | SK | attributes |
|---|---|---|
| WS#a91 | DOC#2026-04-01#x7#CMT#01HZ... | author, text, createdAt |
Sebuah Query pada PK = "WS#a91" dengan SK begins_with "DOC#2026-04-01#x7#CMT#"
sudah mendaftarkan komentar satu dokumen. Dokumen yang ada tak tersentuh. Paruh
ini rilis di hari pertama — lihat item collection dan key
ter-overload untuk mengapa partition yang sama
menampung keduanya.
Query baru butuh sebuah GSI
"Semua komentar oleh seorang member, terbaru dulu" tak bisa dilayani base table —
memberId bukan PK maupun sebuah prefix SK. Itu adalah sebuah indeks baru,
dan memilihnya dengan benar adalah keputusannya sendiri: lihat GSI vs
LSI (sebuah LSI harus ada saat pembuatan tabel, jadi untuk
migrasi pada tabel yang hidup sebuah GSI adalah satu-satunya opsi Anda).
Tambahkan sebuah GSI1 generik dan tulis atribut baru pada item komentar
baru:
| GSI1PK | GSI1SK |
|---|---|
| MEMBER#u44 | 2026-04-02T09:15:00Z |
Query GSI1 WHERE GSI1PK = "MEMBER#u44" dengan ScanIndexForward = false memberi
komentar terbaru-dulu per member.
Bangun indeks secara online
UpdateTable menambahkan sebuah GSI ke tabel yang hidup tanpa downtime. DynamoDB
mem-backfill item yang ada ke indeks di latar belakang; indeks melaporkan
CREATING/backfilling sampai selesai, lalu berbalik ke ACTIVE
(Managing GSIs).
Dua jebakan di sini. Pertama, AWS memperingatkan bahwa menambahkan sebuah GSI
bisa men-throttle penulisan base table jika key baru terdistribusi tak merata
— tambahkan ia di jendela traffic-rendah dan pantau CloudWatch. Kedua, indeksnya
eventually consistent bahkan setelah ia menjadi ACTIVE; sebuah penulisan
mungkin tak terlihat di GSI untuk sesaat. Lihat mengapa GSI eventually
consistent.
Backfill item lama
GSI hanya mengindeks item yang punya GSI1PK/GSI1SK. Komentar pra-migrasi
Anda — ditulis sebelum atributnya ada — tak pernah muncul, bahkan setelah
backfill selesai. Backfill GSI online menyalin item yang ada, tapi ia tak bisa
mereka-reka atribut yang tak ada pada mereka. Anda harus menambahkan nilainya.
Dua strategi:
| Strategi | Cara kerjanya | Pakai saat |
|---|---|---|
| Lazy | Saat baca item lama, tulis balik atribut baru | Item lama sering dibaca; cicil biayanya |
| Sweep | Sebuah Scan terpaginasi memperbarui tiap item lama sekali | Anda butuh GSI lengkap pada sebuah tenggat |
Untuk sweep, paginasi dengan Scan, dan untuk tiap komentar lama tambahkan
atribut indeks dengan sebuah UpdateItem kondisional agar Anda tak pernah
menabrak penulisan konkuren.
Kondisinya menjaga pada atribut yang belum ada. Bangun dan salin
ConditionExpression dan UpdateExpression yang persis dengan
DynamoDB Expression Builder alih-alih
mengetik sendiri attribute_not_exists(GSI1PK).
Dual-write sepanjang transisi
Sampai setiap item lama membawa atribut baru, dua bentuk hidup berdampingan. Jalur tulis harus mengisi format baru pada setiap penulisan — komentar baru dan pembaruan apa pun ke yang lama — sehingga celahnya hanya menyusut.
Pilih sebuah kondisi akhir backfill yang bisa Anda verifikasi: sweep memaginasi seluruh tabel, atau jalur lazy telah berjalan cukup lama sehingga item yang belum dikonversi basi by design. Baru kemudian Anda menghapus jalur baca lama. Melewatkan ini adalah bagaimana sebuah migrasi "selesai" sementara sebagian kecil query diam-diam mengembalikan hasil pendek.

Jebakan
- Menambah atribut ≠ ter-backfill. Sebuah GSI baru mulai kosong untuk item lama. Verifikasi cakupannya sebelum Anda mempercayai query-nya.
- Mengubah sebuah key di tempat bukanlah migrasi — itu sebuah penulisan ulang.
Anda tak bisa memutasi
PK/SKsebuah item; Anda menulis item baru di bawah key baru dan menghapus yang lama. Rencanakan ia sebagai copy-then-delete, dual-read di antaranya. - Tanpa cutover transaksional. Tak ada momen di mana seluruh tabel berbalik. Desain setiap langkah agar aman selagi kedua bentuk hidup.
Langkah berikutnya
Periksa kewarasan key baru dan collection yang ter-overload di single-table design, dan konfirmasi backfill-nya lengkap dengan memaginasi tabel yang hidup. Coba DynoTable untuk menjelajahi tabel Anda, mendeteksi item yang belum ter-backfill, dan menjalankan update kondisional terhadap data Anda sendiri.


