Menengah5 menit baca

Atomic Counter DynamoDB

Sebuah atomic counter adalah atribut numerik yang Anda naikkan di tempat dengan satu panggilan UpdateItem — tanpa baca dulu, tanpa race read-modify-write. DynamoDB menerapkan setiap kenaikan dalam urutan kedatangan dan tidak pernah membiarkan dua penulis menabrak hitungan satu sama lain.

Apa itu atomic counter DynamoDB?

Atomic counter DynamoDB adalah atribut numerik yang Anda naikkan di tempat dengan satu panggilan UpdateItem memakai update expression ADD (atau SET x = x + :n). DynamoDB membaca, menambah, dan menulis nilainya di sisi server, sehingga penulis konkuren ter-serialisasi tanpa update yang hilang — tetapi ia tidak idempoten, jadi panggilan yang di-retry menaikkan dua kali.

  • Gunakan ADD (atau SET x = x + :n) untuk menaikkan dalam satu panggilan. DynamoDB membaca, menambah, dan menulis di sisi server — pemanggil konkuren ter-serialisasi, tanpa update yang hilang.
  • Tanpa baca dulu. Datang dari SQL Anda akan SELECT lalu UPDATE; di sini Anda melewati pembacaan sepenuhnya dan operasinya tetap aman di bawah konkurensi.
  • Atomic counter tidak idempoten. Sebuah UpdateItem yang di-retry menaikkan lagi. Jika Anda tak bisa mentolerir over- atau undercounting, gunakan conditional update.
  • ADD pada atribut yang tidak ada mulai dari 0, jadi kenaikan pertama langsung jalan — tanpa penulisan seed.

Masalah dengan read-modify-write

Misalkan Anda melacak views pada sebuah video. Naluri naif, langsung dari SQL, adalah: GetItem, tambah satu di aplikasi Anda, PutItem total baru kembali.

Dua penonton menekan play sekaligus. Keduanya membaca views = 41. Keduanya menulis 42. Anda menghitung satu view, bukan dua. Itu adalah update yang hilang — jebakan konkurensi klasik, dan ia tak muncul sampai Anda punya lalu lintas.

Di SQL Anda akan mengelaknya dengan UPDATE videos SET views = views + 1, mendorong aritmetika ke dalam database. DynamoDB punya langkah yang sama, dan itulah inti seluruh atomic counter.

Naikkan dalam satu panggilan

Modelkan sebuah item stats per-video. Partition key VID#<id>, sort key STATS#TOTAL, dengan sebuah play_count numerik:

PKSKplay_count
"VID#9f3a""STATS#TOTAL"41

Untuk mendaftarkan sebuah play, kirim satu UpdateItem dengan klausa ADD:

# UpdateItem
Key               PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression  ADD play_count :one
Values            :one = 1

DynamoDB membaca play_count, menambah 1, dan menulis hasilnya di dalam satu operasi sisi-server. Tak ada jendela bagi penulis lain untuk menyelinap masuk. Sepuluh play konkuren menghasilkan +10, setiap kali — itulah yang dibeli "atomic".

Anda bisa membangun dan menyalin ekspresi yang persis ini — nama, nilai, dan keempat tipe klausa — dengan DynamoDB Expression Builder.

ADD bekerja bahkan saat play_count belum ada: DynamoDB memperlakukan atribut numerik yang hilang sebagai 0, jadi play pertama menciptakannya pada 1. Tanpa penulisan seed terpisah. (AWS: Using update expressions)

ADD vs SET +: pilih satu

Dua ekspresi melakukan aritmetika yang sama. AWS merekomendasikan SET untuk penggunaan umum karena ia menyatu dengan aksi SET lain dan membaca lebih eksplisit. (AWS: Using update expressions)

ADD play_count :oneSET play_count = play_count + :one
Atribut hilangMenciptakannya, mulai dari 0Error — butuh if_not_exists
Tipe dataNumber dan set sajaNumber (dan lainnya) via SET
Gabung w/ SETKlausa terpisahSatu klausa SET, dipisah koma
Panduan AWSOke untuk counterDefault yang direkomendasikan

Jika atributnya mungkin tidak ada dan Anda ingin SET, jaga ia: SET play_count = if_not_exists(play_count, :zero) + :one. Dengan ADD Anda melewatkan itu — ia menyemai dari 0 secara gratis.

Lakukan di DynoTable

Buka item-nya, sunting play_count, dan Anda bisa mengamati sebuah kenaikan atomic mendarat tanpa menulis JSON dengan tangan — panel update mengeluarkan ekspresi ADD untuk Anda dan menunjukkan nilai baru begitu ia ter-commit.

Jebakannya: counter tidak idempoten

Inilah bagian yang menggigit tim di produksi. Sebuah atomic counter menaikkan setiap kali UpdateItem berjalan. (AWS: Working with items)

Bayangkan sebuah blip jaringan: Anda mengirim kenaikan, koneksi putus sebelum respons kembali, dan Anda tak tahu apakah ia mendarat. Anda retry. Jika panggilan pertama memang berhasil, Anda kini telah menghitung play itu dua kali.

Untuk views video itu baik-baik saja — beberapa hitungan-ganda dalam sejuta play tak akan menyakiti siapa pun, dan AWS menyebut kasus "track visitors" yang persis ini sebagai penggunaan kanonik atomic counter. (AWS: Working with items)

Itu tidak baik-baik saja untuk apa pun yang harus persis: inventaris yang bisa Anda oversell, kredit yang bisa Anda double-spend, sebuah saldo yang bisa Anda rusak. Di sana, jangkau sebuah conditional update.

Saat Anda butuh ketepatan: conditional update

Sebuah conditional update idempoten jika Anda mengondisikan pada atribut yang sama yang Anda ubah. Naikkan play_count ke 42, tapi hanya jika ia saat ini 41:

# UpdateItem
Key                  PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression     SET play_count = :next
ConditionExpression  play_count = :current
Values               :next = 42, :current = 41

Kini sebuah retry aman: jika penulisan pertama sudah memindahkan play_count ke 42, kondisi play_count = 41 gagal kali kedua dan tak ada yang berubah. (AWS: Working with items)

Biayanya adalah konkurensi. Dua penulis beradu pada kondisi yang sama berarti satu menang dan satu mendapat ConditionalCheckFailedException untuk di-retry — Anda menukar throughput counter tak-bersyarat demi kebenaran. Untuk counter yang persis dan ter-contend itu adalah trade yang tepat. Untuk hitungan view itu berlebihan.

Jebakan

  • Satu item panas. Sebuah baris counter tunggal adalah satu partition key. Sebuah video viral yang menggempur VID#9f3a / STATS#TOTAL bisa mengenai batas tulis per-partition. Shard ia: sebar penulisan di seluruh STATS#TOTAL#0..N dan jumlahkan saat baca.
  • Tanpa batch increment. BatchWriteItem hanya put/delete — ia tak bisa menjalankan update expression. Counter melewati UpdateItem, satu item per panggilan.
  • ADD hanya number dan set. Ia tak akan menyentuh string atau boolean; itu sebuah SET. Lihat tipe data DynamoDB untuk model atribut lengkapnya.

Langkah berikutnya

Atomic counter adalah pola tulis; bagaimana Anda membaca agregat kembali adalah pertanyaan pemodelan — lihat single-table design untuk menyimpan item stats di samping induknya, dan Query vs Scan agar menggulung sebuah counter ter-shard tetap sebuah Query.

Draf dan salin kenaikan di DynamoDB Expression Builder, lalu coba DynoTable untuk menjalankan update atomic terhadap tabel Anda sendiri dan amati hitungan bergerak.

Diperbarui