Lanjutan6 menit baca

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. UpdateTable membangun 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:

PKSKattributes
WS#a91METAname, tier
WS#a91DOC#2026-04-01#x7title, author, body
WS#a91DOC#2026-04-02#k2title, 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:

PKSKattributes
WS#a91DOC#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:

GSI1PKGSI1SK
MEMBER#u442026-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).

UpdateTable: tambah GSI1Status indeks: CREATINGBackfill item yang adaStatus: ACTIVEQuery GSI1 aman

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:

StrategiCara kerjanyaPakai saat
LazySaat baca item lama, tulis balik atribut baruItem lama sering dibaca; cicil biayanya
SweepSebuah Scan terpaginasi memperbarui tiap item lama sekaliAnda 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.

Memaginasi sebuah tabel di DynoTable untuk mendeteksi item yang kehilangan atribut indeks baru selama backfill.
Memaginasi sebuah tabel di DynoTable untuk mendeteksi item yang kehilangan atribut indeks baru selama backfill.

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/SK sebuah 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.

Diperbarui