DynamoDB Atomik Sayaçlar: ADD Nasıl Çalışır, Ne Zaman Çalışmaz
Bir atomic counter, tek bir UpdateItem çağrısıyla yerinde artırdığınız sayısal bir
attribute'tur — önce okuma yok, read-modify-write yarışı yok. DynamoDB her artışı geliş
sırasına göre uygular ve iki yazıcının birbirinin sayısını asla ezmesine izin vermez.
DynamoDB atomic counter nedir?
Bir DynamoDB atomic counter, tek bir UpdateItem çağrısıyla bir ADD (veya
SET x = x + :n) update expression kullanarak yerinde artırdığınız sayısal bir
attribute'tur. DynamoDB değeri sunucu tarafında okur, ekler ve yazar, böylece eşzamanlı
yazıcılar kayıp güncelleme olmadan serileşir — ancak idempotent değildir, bu yüzden
yeniden denenen bir çağrı iki kez artırır.
- Tek çağrıda artırmak için
ADD(veyaSET x = x + :n) kullanın. DynamoDB sunucu tarafında okur, ekler ve yazar — eşzamanlı çağıranlar serileşir, kayıp güncelleme yok. - Önce okuma yok. SQL'den gelirken
SELECTsonraUPDATEyapardınız; burada okumayı tamamen atlarsınız ve işlem eşzamanlılık altında yine de güvenlidir. - Atomic counter'lar idempotent değildir. Yeniden denenen bir
UpdateItemtekrar artırır. Fazla veya eksik saymaya tolerans gösteremiyorsanız, bir kullanın. - Eksik bir attribute üzerinde
ADD0'dan başlar, bu yüzden ilk artış öylece çalışır — tohum yazması gerekmez.
Read-modify-write'ın sorunu
Diyelim ki bir videodaki görüntülemeleri takip ediyorsunuz. Doğrudan SQL'den gelen
naif içgüdü şudur: GetItem, uygulamanızda bir ekleyin, yeni toplamı geri PutItem
yapın.
İki izleyici aynı anda oynata basar. İkisi de views = 41 okur. İkisi de 42 yazar.
Bir görüntüleme saydınız, ikiyi değil. Bu bir kayıp güncellemedir — klasik
eşzamanlılık ayak tuzağı, ve trafiğiniz olana kadar ortaya çıkmaz.
SQL'de bunu UPDATE videos SET views = views + 1 ile atlatır, aritmetiği veritabanına
iterdiniz. DynamoDB'nin aynı hamlesi var ve bir atomic counter'ın tüm amacı bu.
Tek çağrıda artırma
Video başına bir istatistik item'ı modelleyin. Partition key VID#<id>, sort key
STATS#TOTAL, sayısal bir play_count ile:
| PK | SK | play_count |
|---|---|---|
| "VID#9f3a" | "STATS#TOTAL" | 41 |
Bir oynatmayı kaydetmek için, bir ADD cümlesiyle tek bir UpdateItem gönderin:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression ADD play_count :one
Values :one = 1
DynamoDB play_count'u okur, 1 ekler ve sonucu tek bir sunucu tarafı işleminin
içinde yazar. Başka bir yazıcının araya girmesi için bir pencere yoktur. On eşzamanlı
oynatma her seferinde +10 üretir — "atomic"in sana satın aldığı budur.
Bu tam expression'ı — adlar, değerler ve dört cümle türünün tümü — DynamoDB Expression Builder ile oluşturup kopyalayabilirsiniz.
ADD, play_count henüz mevcut olmadığında bile çalışır: DynamoDB eksik bir sayısal
attribute'u 0 olarak ele alır, bu yüzden ilk oynatma onu 1'de oluşturur. Ayrı bir
tohum yazması yok. (AWS: Using update expressions)
ADD ve SET +: birini seçin
İki expression aynı aritmetiği yapar. AWS, genel kullanım için SET'i önerir, çünkü
diğer SET eylemleriyle bir araya gelir ve daha açık okunur. (AWS: Using update
expressions)
ADD play_count :one | SET play_count = play_count + :one | |
|---|---|---|
| Eksik attr | Oluşturur, 0'dan başlar | Hata — if_not_exists gerekir |
| Veri türleri | Yalnızca sayılar ve setler | Sayılar (ve daha fazlası) SET ile |
SET ile birleştir | Ayrı cümle | Tek SET cümlesi, virgülle ayrılmış |
| AWS rehberliği | Counter'lar için uygun | Önerilen varsayılan |
Attribute mevcut olmayabilirse ve SET istiyorsanız, onu koruyun:
SET play_count = if_not_exists(play_count, :zero) + :one. ADD ile bunu atlarsınız
— bedava 0'dan tohumlar.
Her artışın yazma maliyeti
us-east-1 bölgesinde on-demand modda, ADD içeren her UpdateItem, yazmadan
sonraki item boyutunun KB başına 1 WCU'su kadarını faturalandırır (yukarı
yuvarlanır). 900 baytlık bir istatistik satırı, kaydedilen her oynatma için
1 WCU tutar; on eşzamanlı oynatma yine toplamda 10 WCU olarak iner, bir
değil. Counter'ı partition'lar arasında shard'lamak, item başına WCU matematiğini
değiştirmeden verim tavanını yükseltir. Satırı
item boyutu hesaplayıcısı ile
boyutlandırın ve sıcak yolları
fiyatlandırma hesaplayıcısında ölçün.
Bunu DynoTable'da yapın
Canlı counter'ı incelemek için istatistik item'ını açın, sonra her STATS#TOTAL#0..N
satırı boyunca toplamı görmek için SQL Workbench'te SUM ve GROUP BY ile sharded bir
counter'ı toplayın. Artışın kendisini taslak olarak oluşturmak için, ADD UpdateItem
expression'ını adlar ve değerler dahil oluşturmak için web
DynamoDB Expression Builder'ı kullanın.
Tuzak: counter'lar idempotent değildir
İşte üretimde ekiplerin canını yakan kısım. Bir atomic counter, UpdateItem her
çalıştığında her seferinde artar. (AWS: Working with items)
Bir ağ kesintisi düşünün: artışı gönderirsiniz, yanıt geri gelmeden bağlantı kopar ve inip inmediğini bilmezsiniz. Yeniden denersiniz. İlk çağrı başarılı olduysa, o oynatmayı şimdi iki kez saydınız.
Video görüntülemeleri için bu sorun değil — bir milyon oynatmada birkaç çift-sayım kimseye zarar vermez ve AWS bu tam "ziyaretçi izleme" durumunu atomic counter'ların kanonik kullanımı olarak adlandırır. (AWS: Working with items)
Tam olması gereken hiçbir şey için sorundur: fazla satabileceğiniz envanter, iki kez harcayabileceğiniz krediler, bozabileceğiniz bir bakiye. Orada, koşullu bir güncellemeye başvurun.
Kesinliğe ihtiyaç duyduğunuzda: koşullu güncellemeler
Bir koşullu güncelleme, değiştirdiğiniz aynı attribute üzerine koşullandırırsanız
idempotent'tir. play_count'u 42'ye artırın, ancak yalnızca şu anda 41 ise:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression SET play_count = :next
ConditionExpression play_count = :current
Values :next = 42, :current = 41
Şimdi bir yeniden deneme güvenli: ilk yazma play_count'u zaten 42'ye taşıdıysa,
play_count = 41 koşulu ikinci seferde başarısız olur ve hiçbir şey değişmez. (AWS:
Working with items)
Maliyeti eşzamanlılıktır. Aynı koşulda yarışan iki yazıcı, birinin kazanması ve
birinin yeniden denemek için bir ConditionalCheckFailedException alması demektir —
koşulsuz counter'ın verimini doğruluk için takas ettiniz. Tam, çekişmeli counter'lar
için doğru takas budur. Görüntüleme sayıları için aşırıya kaçmaktır.
Tuzaklar
- Bir . Tek bir counter satırı bir partition key'dir.
VID#9f3a/STATS#TOTAL'ı çekiçleyen viral bir video, partition başına bir yazma tavanına çarpabilir. Onu shard'layın: yazmalarıSTATS#TOTAL#0..Nboyunca yayın ve okumada toplayın. - Toplu artış yok.
BatchWriteItemyalnızca put/delete'tir — 'ları çalıştıramaz. Counter'lar çağrı başına bir item ileUpdateItemüzerinden gider. Birkaç counter'ı atomik olarak artırmanız gerekiyorsa,TransactWriteItems, kabaca iki katı yazma maliyetiyle, tek bir istekte 100 item'a kadar Update eylemi çalıştırır. ADDyalnızca sayılar ve setlerdir. String'lere veya boolean'lara dokunmaz; o birSET'tir. Tam attribute modeli için DynamoDB veri türleri sayfasına bakın.
Sonraki adımlar
Atomic counter'lar bir yazma modelidir; agregasyonları nasıl okuduğunuz bir modelleme
sorusudur — istatistik item'larını ebeveynlerinin yanında tutmak için
single-table design sayfasına ve sharded bir counter'ı
toplamanın bir Query olarak kalması için Query ve Scan
sayfasına bakın.
Artışı DynamoDB Expression Builder'da taslak olarak oluşturun ve kopyalayın, sonra kendi tablolarınıza karşı atomik güncellemeler çalıştırmak ve sayıların hareket etmesini izlemek için DynoTable'ı deneyin.