Orta7 dakikalık okuma

DynamoDB'de Singleton Item'lar

Bir singleton item, tüm uygulaman için durum tutan, sabit ve gömülü bir key'e sahip tek bir satırdır — kullanıcı başına ya da sipariş başına bir kayıt değil, bir kayıt, hepsi bu. Feature flag'ler, bir config blob'u, global bir acil durdurma anahtarı: ilişkisel bir uygulamanın tek satırlık bir ayarlar tablosunda tutacağı türden şeyler.

SQL'den geliyorsan, id = 1 ve bir SELECT * FROM config ile bir config tablosuna uzanırdın. DynamoDB'de aynı şeyi gömülü bir partition key ile yaparsın — ve o key'i her zaman bildiğin için, onu bir Query ya da Scan ile değil, bir GetItem ile okursun.

DynamoDB'de singleton item nedir?

Bir singleton item, kullanıcı ya da sipariş başına bir kayıt yerine tüm uygulamanın global durumunu tutan — feature flag'ler, bir config blob'u, sistem genelinde bir sürüm — sabit ve gömülü bir key altında depolanan tek bir DynamoDB satırıdır. Key'i her zaman bildiğin için, onu GetItem ile okur ve ile birlikte condition expression'larla güncellersin.

  • Bir singleton, sabit key'li tek bir item'dır. Bir kullanıcı ya da sipariş id'sini şablona koymak yerine PK/SK'yı (örn. CONFIG#GLOBAL) kodunda gömülü yazarsın.
  • Onu GetItem ile oku, asla Scan ile. Tam key'i her zaman bilirsin, dolayısıyla bir nokta okuma tek bir tutarlı, öngörülebilir RCU'dur — filtre yok, tablo gezme yok.
  • Tanımı gereği bir hot key'dir. Her istek aynı partition'a dokunabilir, dolayısıyla onu cache'le ve item'ı küçük tut; onu bir yazma darboğazı yapma.
  • Onu update + condition expression'larla güvenle değiştir, uygulamanda read-modify-write ile değil — kayıp-güncelleme yarışının yaşadığı yer orasıdır.

Deseni tanı

Veri herhangi bir entity'ye kapsamlanmadığında global durumun vardır. Birkaç işaret:

  • Herkes için aynı olan bir flag (signup_enabled = false).
  • Uygulamanın başlangıçta okuduğu bir ayarlanabilir parametre blob'u (rate limit'ler, varsayılan kotalar).
  • Satır başına değil, tüm sistem için bir sayaç ya da sürüm numarası.

Bir kullanıcıya, kiracıya ya da siparişe kapsamlanmış herhangi bir şey singleton değildir — o, o entity'nin id'siyle key'lenmiş sıradan bir item'dır. Singleton, başka gidecek yeri olmayan, artakalan global dilimdir.

Ona sabit bir key ver

Tüm desen tek bir karara dayanır: key bir literal'dir, bir şablon değil. Aşırı yüklü bir tek tablodaki global bir feature-flag item'ı için sabit bir prefix ve sabit bir değer seç:

PKSKattributes
SETTINGS#APPFLAGS#V1signup_enabled, maintenance_mode, ai_search_enabled

PK = "SETTINGS#APP" ve SK = "FLAGS#V1" koda gömülüdür. Kullanıcı id'si yok, kiracı id'si yok — uygulama her seferinde tam olarak bu item'ı ister. O öngörülebilirlik asıl mesele: bilinen bir key bir GetItem'dır ve bir GetItem, DynamoDB'nin sunduğu en ucuz, en tutarlı okumadır.

V1 son eki kasıtlıdır. Flag şeması ileride şekil değiştirirse, canlı olanı yerinde değiştirmek yerine bir FLAGS#V2 item'ı yazar ve okuyucuları ona geçirirsin. Singleton key'ini sürümlemek sana temiz bir taşıma dikişi kazandırır.

Onu GetItem ile oku

Key tamamen bilindiği için, bir singleton için asla Query yapmaz ve asla Scan yapmazsın. Bir Scan tüm tabloyu okur ve istemci tarafında filtreler — klasik Scan ayak kapanı — ve doğrudan adresleyebileceğin tek bir satırı çekmek için saçma bir aşırılıktır.

SETTINGS#APP / FLAGS#V1'e karşı bir GetItem, flag'leri tek bir güçlü ya da nihai tutarlı okumada döndürür. AWS, ≤ 4 KB'lık bir item'ın GetItem'ını nihai tutarlı için 0,5 RCU ya da güçlü tutarlı için 1 RCU olarak faturalandırır (AWS okuma/yazma kapasitesi dokümanları). Singleton'ı küçük tut, o maliyet sonsuza kadar düz kalsın.

Okuma yolu basitçe şu: uygulama başlar ya da bir istek gelir, sabit key'i GetItem edersin, sonucu cache'lersin. İşte akış.

evethayırUygulama / istekGetItem PK=SETTINGS#APPSK=FLAGS#V1Item bulundu mu?Flag'leri kullan, yerel cache'leGüvenli varsayılanlara geri dön

Sabit key, global bir aramayı yerleşik bir varsayılan yola sahip tek bir nokta okumaya dönüştürür.

hayır dalına dikkat et: eksik bir singleton seni asla çökertmemeli. Bir ilk-deploy boşluğu ya da kötü bir key açık değil de kapalı düşsün diye güvenli değere varsayılan yap (feature kapalı, bakım açık).

Onu yarış olmadan güncelle

Tuzak, bir singleton'ı uygulamanda read-modify-write ile güncellemektir: flag'leri GetItem edersin, birini bellekte değiştirirsin, sonra tüm şeyi geri PutItem edersin. İki eşzamanlı yazar da eski item'ı okur ve ikinci Put birincinin değişikliğini ezer. Kayıp güncelleme.

İki DynamoDB özelliği, uygulama tarafı kilitleme olmadan yarışı öldürür:

  • Update expression'lar sunucu tarafında tek bir attribute'ı değiştirir, gerisini el değmemiş bırakır. Tüm item'ı yeniden Put etmeye gerek yok.
  • Condition expression'lar yazmanın yalnızca item hâlâ beklediğin gibi görünüyorsa başarılı olmasını sağlar, dolayısıyla bayat bir yazma ConditionalCheckFailedException ile reddedilir (AWS condition expression dokümanları).

Tek bir flag'i değiştirmek için, yalnızca o attribute'ı bir SET ile hedefle ve eşzamanlı yazarların birbirini ezememesi için bir sürüm artışıyla koru:

# UpdateItem
Key                  PK=SETTINGS#APP  SK=FLAGS#V1
UpdateExpression     SET signup_enabled = :on, schema_version = :next
ConditionExpression  schema_version = :current

İki yazar yarışırsa, ikincinin schema_version = :current kontrolü başarısız olur ve taze değere karşı yeniden dener. Name'leri, value'ları ve tam bu expression şeklini koda bağlamadan önce DynamoDB Expression Builder içinde iskeletleyebilirsin. Operatörlere daha derin bir bakış için update-expression idiom'ları kılavuzuna bak.

Hot key'e dikkat et

Bir singleton, yapısı gereği bir hot key'dir — uygulamanın her parçası aynı partition'ı okuyabilir. Cache'lersen okumalar için bu sorun değil, ama desenin tek gerçek riski budur.

  • Agresif cache'le. Flag'leri her istekte değil, işlem başına (ya da N saniyede bir) bir kez oku. Singleton'ın değeri ezberlenecek en ucuz şeydir.
  • Onu bir yazma sıcak noktası yapma. Bir yöneticinin günde birkaç kez değiştirdiği bir flag hiçbir şeydir. Her istekte arttırdığın bir singleton bir partition-throughput darboğazıdır — o bir sayaç problemidir, bir singleton değil.
  • Onu küçük tut. Okuma maliyeti, item boyutuyla 4 KB'lık bloklar halinde ölçeklenir. Şişmiş bir config blob'u her başlangıcı gerektiğinden daha pahalı yapar.

Gerçekten yüksek-yazmalı global bir sayaca ihtiyacın varsa, singleton yanlış şekildir — onu N item'a parçala (shard) ve okumada topla. Bu farklı bir desendir.

Singleton vs entity başına item

Çizgi basitçe _verinin neye kapsamlandığı_dır.

Singleton itemEntity başına item
KeyGömülü sabit (SETTINGS#APP)Bir id ile şablonlanmış (USER#42)
Kaç taneTam olarak birKullanıcı / sipariş / kiracı başına bir
Tipik okumaBilinen key üzerinde GetItemEntity'ye göre GetItem ya da Query
KapsamTüm uygulamaTek bir entity
Şunun için kullanGlobal flag'ler, config, sistem sürümüProfiller, siparişler, id başına her şey

Aynı türden iki singleton istediğini fark edersen, bir singleton'ın yok — bir entity başına item'ın var ve key'lemeyi unuttuğun şey o entity (örneğin kiracı başına config).

Tuzaklar ve sonraki adımlar

  • Onun için Scan yapma. Key'i biliyorsun; onu doğrudan adresle.
  • Onu read-modify-write etme. Update + condition expression'lar kullan.
  • Onun sessizce kaybolmasına izin verme. Bir cache miss'inde güvenli değere varsayılan yap.
  • Onu yüksek-frekanslı yazmalarla aşırı yükleme. Bu bir parçalanmış-sayaç işidir.

Singleton bir single-table design içinde rahatça yaşar — entity satırlarının yanında sabit bir key'e sahip yalnızca bir item koleksiyonu daha.

Tablona göz atmak, singleton satırı sabit key'iyle bulmak ve yazma yolunu kurarken flag'leri elle düzenlemek için DynoTable'ı dene.

Güncellendi