Orta4 dakikalık okuma

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 da SET 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 SELECT sonra UPDATE yapardı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 UpdateItem tekrar 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:

PKSKplay_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 :oneSET play_count = play_count + :one
Eksik nitelikOluşturur, 0'dan başlayarakHata verir — if_not_exists gerekir
Veri türleriYalnızca sayılar ve set'lerSayılar (ve SET ile daha fazlası)
SET ile birleştirmeAyrı cümleTek bir SET cümlesi, virgülle ayrılmış
AWS rehberiSayaç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. BatchWriteItem yalnızca put/delete'tir — güncelleme ifadeleri çalıştıramaz. Sayaçlar UpdateItem üzerinden, çağrı başına bir öğe gider.
  • ADD yalnızca sayılar ve set'lerdir. Dizelere ya da boolean'lara dokunmaz; o bir SET'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.

Güncellendi