DynamoDB Atomik Sayaçlar
Atomik sayaç, tek bir UpdateItem çağrısıyla yerinde artırdığınız sayısal bir
niteliktir — önce okuma yok, oku-değiştir-yaz yarış durumu yok. DynamoDB her artışı
varış sırasında uygular ve iki yazarın asla birbirinin sayısını ezmesine izin vermez.
DynamoDB atomik sayaç nedir?
DynamoDB atomik sayaç, tek bir UpdateItem çağrısıyla bir ADD (ya da SET x = x + :n) güncelleme ifadesi kullanarak yerinde artırdığınız sayısal bir niteliktir. DynamoDB değeri sunucu tarafında okur, ekler ve yazar; böylece eşzamanlı yazarlar kayıp güncelleme olmadan seriye girer — ancak idempotent değildir, dolayısıyla yeniden denenen bir çağrı iki kez artırır.
- Tek çağrıda artırmak için
ADD(ya daSET x = x + :n) kullanın. DynamoDB sunucu tarafında okur, ekler ve yazar — eşzamanlı çağıranlar seriye girer, kayıp güncelleme yok. - Önce okuma yok. SQL'den geliyorsanız
SELECTsonraUPDATEyapardınız; burada okumayı tamamen atlarsınız ve işlem eşzamanlılık altında yine de güvenlidir. - Atomik sayaçlar idempotent değildir. Yeniden denenen bir
UpdateItemtekrar artırır. Fazla ya da eksik sayıma katlanamıyorsanız, koşullu bir güncelleme kullanın. - Eksik bir nitelik üzerinde
ADD, 0'dan başlar, böylece ilk artış öylece çalışır — tohum (seed) yazması gerekmez.
Oku-değiştir-yaz sorunu
Diyelim ki bir videodaki görüntülemeleri izliyorsunuz. SQL'den gelen saf içgüdü:
GetItem, uygulamanızda bir ekleyin, yeni toplamı geri PutItem edin.
İki izleyici aynı anda oynat'a basar. İkisi de views = 41 okur. İkisi de 42
yazar. İki değil, bir görüntüleme saydınız. Bu bir kayıp güncellemedir — klasik
eşzamanlılık tuzağı ve trafiğiniz olana kadar ortaya çıkmaz.
SQL'de bunu UPDATE videos SET views = views + 1 ile, aritmetiği veritabanına
iterek atlatırdınız. DynamoDB'nin aynı hamlesi vardır ve bir atomik sayacın tüm
amacı budur.
Tek çağrıda artırın
Video başına bir istatistik öğesi modelleyin. Bölüm anahtarı VID#<id>, sıralama
anahtarı 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şlemin
içinde yazar. Başka bir yazarın araya girmesi için bir pencere yoktur. On eşzamanlı
oynatma her seferinde +10 üretir — "atomik"in size satın aldığı şey budur.
Bu tam ifadeyi — adlar, değerler ve dört cümle türünün hepsi — DynamoDB Expression Builder ile oluşturup kopyalayabilirsiniz.
ADD, play_count henüz var olmasa bile çalışır: DynamoDB eksik bir sayısal
niteliği 0 olarak ele alır, böylece ilk oynatma onu 1'de oluşturur. Ayrı bir
tohum yazması yok. (AWS: Güncelleme ifadelerini kullanma)
ADD ile SET +: birini seçin
İki ifade aynı aritmetiği yapar. AWS genel kullanım için SET'i önerir çünkü diğer
SET eylemleriyle birleşir ve daha açık okunur. (AWS: Güncelleme ifadelerini
kullanma)
ADD play_count :one | SET play_count = play_count + :one | |
|---|---|---|
| Eksik nitelik | Oluşturur, 0'dan başlayarak | Hata verir — if_not_exists gerekir |
| Veri türleri | Yalnızca sayılar ve set'ler | Sayılar (ve SET ile daha fazlası) |
SET ile birleştirme | Ayrı cümle | Tek bir SET cümlesi, virgülle ayrılmış |
| AWS rehberi | Sayaçlar için uygun | Önerilen varsayılan |
Nitelik var olmayabiliyorsa ve SET istiyorsanız, onu koruyun:
SET play_count = if_not_exists(play_count, :zero) + :one. ADD ile bunu
atlarsınız — 0'dan bedava tohumlar.
Bunu DynoTable'da yapın
Öğeyi açın, play_count'u düzenleyin ve elle JSON yazmadan bir atomik artışın
inişini izleyebilirsiniz — güncelleme paneli ADD ifadesini sizin için üretir ve
işlendiği an yeni değeri gösterir.
Tuzak: sayaçlar idempotent değildir
İşte üretimde ekipleri ısıran kısım. Bir atomik sayaç, UpdateItem çalıştığı her
seferinde artırır. (AWS: Öğelerle çalışma)
Bir ağ kesintisi düşünün: artışı gönderirsiniz, yanıt geri gelmeden bağlantı düşer ve onun inip inmediğini bilmezsiniz. Yeniden denersiniz. İlk çağrı başardıysa, o oynatmayı şimdi iki kez saymış olursunuz.
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 atomik sayaçların kanonik kullanımı olarak adlandırır. (AWS: Öğelerle çalışma)
Kesin olması gereken hiçbir şey için uygun değildir: fazla satabileceğiniz envanter, çift harcayabileceğiniz krediler, bozabileceğiniz bir bakiye. Orada, koşullu bir güncellemeye uzanın.
Kesinliğe ihtiyacınız olduğunda: koşullu güncellemeler
Bir koşullu güncelleme, değiştirdiğiniz aynı nitelik üzerinde koşullandırırsanız
idempotenttir. play_count'u 42'ye artırın, ama yalnızca şu an 41 ise:
# UpdateItem
Key PK = "VID#9f3a", SK = "STATS#TOTAL"
UpdateExpression SET play_count = :next
ConditionExpression play_count = :current
Values :next = 42, :current = 41
Artık bir yeniden deneme güvenlidir: 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: Öğelerle çalışma)
Bedeli eşzamanlılıktır. Aynı koşulda yarışan iki yazar demek, birinin kazanması ve
birinin yeniden denemek için bir ConditionalCheckFailedException alması demektir —
koşulsuz sayacın verimini doğruluk için takas ettiniz. Kesin, çekişmeli sayaçlar
için doğru takas budur. Görüntüleme sayıları için fazlasıyla gereksizdir.
Tuzaklar
- Tek bir sıcak öğe. Tek bir sayaç satırı tek bir bölüm anahtarıdır.
VID#9f3a/STATS#TOTAL'ı döven viral bir video, bölüm başına bir yazma tavanına çarpabilir. Onu sharding'leyin: yazmalarıSTATS#TOTAL#0..N'e yayın ve okumada toplayın. - Toplu artış yok.
BatchWriteItemyalnızca put/delete'tir — güncelleme ifadeleri çalıştıramaz. SayaçlarUpdateItemüzerinden, çağrı başına bir öğe gider. ADDyalnızca sayılar ve set'lerdir. Dizelere ya da boolean'lara dokunmaz; o birSET'tir. Tam nitelik modeli için bkz. DynamoDB veri türleri.
Sonraki adımlar
Atomik sayaçlar bir yazma desenidir; toplamları nasıl geri okuduğunuz bir
modelleme sorusudur — istatistik öğelerini üst öğelerinin yanında tutmak için bkz.
tek tablo tasarımı ve sharding'lenmiş bir sayacı
toplamanın bir Query olarak kalması için Query vs Scan.
Artışı DynamoDB Expression Builder içinde taslaklayıp kopyalayın, ardından atomik güncellemeleri kendi tablolarınıza karşı çalıştırmak ve sayıların hareketini izlemek için DynoTable'ı deneyin.