DynamoDB Sıcak Bölümler: Nasıl Bulunur ve Düzeltilir
DynamoDB verilerinizi, her biri kendi verimlilik dilimine sahip birçok fiziksel bölüm arasında dağıtır. Bir sıcak bölüm, tek bir anahtarın dilimine hizmet edebileceğinden çok daha fazla okuma ya da yazma çekmesidir — böylece o anahtara gelen istekler throttle edilirken tablonun geri kalanı boş oturur.
DynamoDB sıcak bölümü nedir?
Bir DynamoDB sıcak bölümü, tek bir verimlilik diliminin sunabileceğinden çok daha fazla okuma ya da yazma emmesidir; böylece o anahtara gelen istekler throttle edilirken tablonun geri kalanı boş oturur. Sebep anahtar tasarımıdır — bir ünlü item, düşük kardinaliteli bir anahtar, bugünün tarihi — tablo boyutu değil. Çare yazmaları dağıtmaktır.
- Sebep anahtar tasarımıdır, tablo boyutu değil. Trafiği yoğunlaştıran tek bir
— bir ünlü kullanıcı, bir
status="OPEN"bayrağı, bugünün tarihi — tuzaktır. - Uyarlanabilir kapasite (adaptive capacity) yardım eder ama bir çözüm değildir. DynamoDB ısıyı otomatik olarak yeniden dengeler, yine de tek bir item ya da tek bir anahtar hâlâ bir bölümün sunabileceğini aşabilir.
- Çare yazmaları dağıtmaktır. Anahtara entropi ekleyin (yazma parçalama) ya da sıcak okuma yolunu daha iyi dağıtılmış bir erişim desenine taşıyın.
- SQL'den geliyorsanız bunun eşdeğeri yoktur. İlişkisel bir tablonun "bir satırın dizin değeri çok popüler" gibi bir kavramı yoktur — DynamoDB'nin düz anahtar başına verimlilik modelinin vardır.
Bölümler neden var
DynamoDB, tek düğümlü SQL modelini bölümlenmiş, yatay olarak ölçeklenen bir modelle takas eden 2007 Amazon Dynamo makalesinin üretim mirasçısıdır. Veri, bölüm anahtarının bir hash'iyle fiziksel depolama düğümleri arasında parçalanır.
Her bölüm sınırlı miktarda veri tutar ve sınırlı miktarda verimlilik sunar. AWS, saniyede bölüm başına 3.000 okuma birimi ve 1.000 yazma birimi olan sert bir tavan belgeler (AWS — bölüm davranışı).
O tavan bütün hikâyedir. Tablonuzun verimliliği, tüm bölümlerdeki toplamdır. Bir anahtarın item koleksiyonu tek bir bölümde başlar ve ısı için bölme, onu sıralama anahtarı sınırlarında birkaç bölüme ayırabilir — tablo bir LSI'ye sahip değilse ya da sıralama anahtarı sürekli artan değilse, ki bu onu tek bir bölüme sabitler.
Tuzağı adlandırın: tek bir anahtara yığılan trafik
Verimlilik yalnızca erişiminiz anahtarlar arasında eşit dağılıyorsa eşit paylaşılır. Bir anahtar orantısız trafik aldığı an, tablonun genel kapasitesi kullanılmadan dururken o anahtar tek başına throttle edilir.
Klasik sıcak anahtar biçimleri:
- Bir ünlü item — herkesin okuduğu tek bir kullanıcı, ürün ya da kiracı.
- Düşük kardinaliteli bir bölüm anahtarı —
status,country,type. Az sayıda farklı değer, tüm işi yapan az sayıda bölüm demektir. - Zaman kovalı bir anahtar —
PK = "2026-06-23". Bugünkü her yazma tek bir bölümü döver; dünkü sonsuza dek soğuktur.
SQL'den geliyorsanız bunların hiçbiri önemli olmazdı. Popüler bir değer üzerindeki bir B-ağacı dizini gayet iyidir. DynamoDB'de popüler değer, fiziksel yerleşimin biriminin ta kendisidir, bu yüzden popülerlik bir verimlilik uçurumuna dönüşür.
İşlenmiş bir örnek: ünlü lider tablosu
Diyelim küresel bir oyun lider tablosu işletiyorsunuz. Skorlar şöyle anahtarlanan bir tabloda yaşar:
PK = "BOARD#global"
SK = "PLAYER#<playerId>"
Okumalar skora göre ilk N'i alır; yazmalar her maçtan sonra bir oyuncunun
currentScore'unu artırır. Küresel tablodaki her satır tek bir bölüm anahtarını
paylaşır — BOARD#global — bu yüzden her okuma ve yazma tek bir bölüme iner.
Kendi sıralarında yenileme düğmesine basıp duran iki milyon canlı izleyicisi olan
bir yayıncı ekleyin ve o tek bölüm 3.000 okuma biriminin ötesine devrilir.
Tablodaki her diğer tablo boş otururken küresel tabloda
ProvisionedThroughputExceededException alırsınız.
Ayağa sıkan silah BOARD#global çöküşüdür: tek bir mantıksal tabloyu tek bir
fiziksel anahtar olarak modellediniz.
Yazmaları dağıtın: anahtarı parçalama
Çözüm kardinalite imal etmektir. Tek bir mantıksal tablo N fiziksel bölüme yayılsın diye bölüm anahtarına bir shard son eki ekleyin:
PK = "BOARD#global#<shard>" -- shard = playerId mod 10
SK = "PLAYER#<playerId>"
Yazmalar artık biri yerine on bölüme dağılır — on katı yazma alanı. Bedeli: hiçbir
tek Query shard sınırlarını aşamadığı için tüm tablonun bir okuması on shard'ın
hepsine çarpıp birleştirmelidir. Okuma sadeliğini yazma dağıtımı için takas
edersiniz.
Farkı kendiniz görün. Aşağıdaki görselleştiriciye tek bir tekrarlanan anahtar
yapıştırın ve her yazma tek bir kovaya iner — sıcak bölüm. Bir shard son eki
(BOARD#global#0 … #9) ekleyin ve aynı yazmalar eşit biçimde yayılır:
Bu, sezgi için öğretici bir hash'tir, DynamoDB'nin gerçek iç hash'i değildir — gerçek işlev ve bölüm sınırları AWS iç yapısıdır. Bunu, bir anahtarın hangi fiziksel bölüme ineceğinin bir tahmini olarak değil, "eşit dağılıma karşı çarpıklık" olarak okuyun.
AWS buna yazma parçalama (write sharding) der ve tam da yüksek hızlı, düşük kardinaliteli anahtarlar için önerir (AWS — yazma parçalamayı kullanma).
Bu, single-table tasarımı ardındaki aynı iç güdüsüdür — anahtarı, verinin "doğal olarak" oturduğu biçime göre değil, erişim desenine göre şekillendirirsiniz.
Kolay kısmı uyarlanabilir kapasiteye bırakın
DynamoDB, re:Invent 2018 oturumu "Amazon DynamoDB Under the Hood" (DAT401) içinde ele alınan uyarlanabilir kapasite (adaptive capacity) ile gelir. Bir tablonun verimliliğini ısı alan bölümlere doğru sürekli olarak yeniden dağıtır ve sürekli sıcak bir anahtarı kendi bölümüne izole eder (anahtar düzeyinde izolasyon, AWS — bursting ve uyarlanabilir kapasite).
Anlıktır ve bedavadır — ama fizikle sınırlıdır (uyarlanabilir kapasite nasıl çalışır). Uyarlanabilir kapasite ısıyı anahtarlar arasında taşıyabilir ve ısı için bölme, sıcak bir item koleksiyonunu bir sıralama anahtarı sınırında bile bölebilir. Bölüm başına tavan yalnızca tek bir sıcak item, sürekli artan bir sıralama anahtarı ya da bir LSI'li tablo için mutlak kalır — burada bir ünlü anahtar hâlâ throttle eder. Parçalama deterministik çözümdür; ısı için bölme yavaş ve fırsatçıdır, bu yüzden onu beklemeyin.
İşte meşgul bir anahtarda throttle'lar gördüğünüzde karar yolu:
Çoğu sıcak bölüm ya "anahtarı parçala" ya da "uyarlanabilir kapasitenin emmesine izin ver" ile çözülür — diyagram sadece hangi dalda olduğunuzu gösterir.
Yeniden tasarlamadan önce teşhis edin
Göremediğinizi düzeltemezsiniz. Throttling, CloudWatch'ta
ProvisionedThroughputExceededException (provisioned) olarak ya da
ThrottledRequests, ReadThrottleEvents/WriteThrottleEvents ve
ReadThrottleEventsForKeyRange/WriteThrottleEventsForKeyRange — bölüm sınırına
özgü sayımlar — olarak görünür
(AWS — CloudWatch metrikleri).
Tablo düzeyindeki maliyet için fiyatlandırma hesaplayıcısını kullanın.
Bunu, en çok erişilen anahtarlarınızı doğrudan sıralayan DynamoDB için CloudWatch Contributor Insights ile eşleştirin — bir ünlü anahtarı ismiyle doğrulamanın en hızlı yolu (AWS — Contributor Insights belgeleri). Ve sıcak bir anahtarın sebep olup olmadığından henüz emin değilseniz — DynamoDB dört ayrı sebeple throttle eder — kısıtlama rehberinden başlayın ve gerçekte hangi sınıra çarptığınızı metriklerin söylemesine izin verin.
Parçalanmış okuma yolunu test ederken, her shard için KeyConditionExpression'ı
elle kuruyor olacaksınız. Bunları yazım hatası olmadan
DynamoDB Expression Builder ile üretin — her
shard için tam PK = :pk AND begins_with(SK, :sk) biçimini yayar.
Kaçınılması gereken tuzaklar
- Sürekli artan sıralama anahtarları. Monoton bir sıralama anahtarı (bir zaman damgası, bir sıra numarası) her yeni yazmayı tek bir item koleksiyonunun aynı ucuna zorlar ve ısı için bölme yardım edemez — koleksiyon 1.000 yazma biriminde sınırlı kalır. Sıralama anahtarına entropi ekleyin ya da bölüm anahtarını parçalayın.
- Okuma ağırlıklı yolu gereksiz yere parçalamak. Okumalar baskınsa ve item küçükse, bir önbellek ya da daha iyi dağıtılmış bir anahtarlı bir GSI çoğu zaman parçalamanın topla-dağıt okuma maliyetini yener.
- Sıcak bölümü yavaş bir
Scanile karıştırmak. BirScanher şeyi okuduğu için yavaştır; bir sıcak bölüm tek bir anahtar aşırı yüklendiği için throttle eder. Farklı problemler — bkz. Query ile Scan.
Sonraki adımlar
Parçalanmış anahtarları eskizleyin, sonra okuma yolunu gerçek veriye karşı kanıtlayın. Shard başına koşulları DynamoDB Expression Builder içinde kurun ve onları kendi tablolarınıza karşı çalıştırıp hangi bölümlerin gerçekten ısı aldığını izlemek için DynoTable'ı indirin.