DynamoDB Single-Table Design: Kapsamlı Modelleme Rehberi
DynamoDB single-table design'ı ilişkileri modelleme, GSI ve LSI seçimi, DAX optimizasyonu ve production NoSQL sistemlerinde yaygın hataları önleme konularında pratik örneklerle öğren.
Özet
Single-table design, DynamoDB için veri modelleme yaklaşımında temel bir değişimi temsil ediyor. Bu kapsamlı rehber, single-table pattern'leri ne zaman kullanacağını, one-to-one, one-to-many ve many-to-many ilişkileri nasıl modelleyeceğini, Global ve Local Secondary Index'ler arasındaki trade-off'ları, DAX caching entegrasyonunu ve pratik query optimizasyon tekniklerini ele alıyor. Çalışan TypeScript örnekleri, gerçek maliyet analizleri ve hot partition ile throttling sorunlarından kaçınmak için test edilmiş pattern'ler bulacaksın.
Single-Table Design Neden Önemli
DynamoDB ile çalışırken öğrendiğim en önemli ders, relational tablo mantığıyla düşünmenin sorun çözmekten çok sorun yarattığı oldu. Tipik yaklaşım - Users, Orders, Products için ayrı tablolar oluşturmak - birden fazla round-trip, karmaşık uygulama mantığı ve öngörülemeyen maliyetlere yol açıyor.
Single-table design, birden fazla entity type'ı generic partition ve sort key'ler kullanarak tek tabloda saklıyor. Bir customer'ı bir tablodan, order'larını başka bir tablodan çekmek yerine, her şeyi tek request'te alıyorsun. Bu sadece performansla ilgili değil; veri modellemeye yaklaşımını temelden değiştiriyor.
Temel İlkeler:
- Access pattern'ler önce: Schema'yı tasarlamadan önce her query'yi dokümante et
- Data locality: İlişkili veriyi aynı partition key kullanarak bir arada sakla
- Generic key'ler: Entity-specific isimler yerine
PKveSKkullan - Item collection'lar: İlişkili item'ları shared partition key'lerle grupla
- Attribute overloading: Aynı attribute'lar farklı entity type'ları boyunca farklı amaçlara hizmet eder
Single-Table Design Ne Zaman Kullanılmalı
Single-table design, ilişkili veriyi birlikte çekmen gerektiğinde mükemmel çalışıyor. Ne zaman iyi çalıştığı hakkında öğrendiklerim:
İyi Kullanım Senaryoları:
- Customer'ları order'larıyla birlikte çektiğin e-commerce sistemleri
- Post'ları comment ve like'larla birlikte alan sosyal platformlar
- Tenant isolation olan multi-tenant SaaS uygulamaları
- Hierarchical veri içeren content management sistemleri
- Cihaz bazında sensor reading'leri toplayan IoT platformları
Ne Zaman Kaçınmalı:
Ekiplerle çalışırken single-table design'ın her zaman doğru seçim olmadığını gördüm:
- Ekipte DynamoDB uzmanlığı yok (öğrenme eğrisi gerçek)
- Minimal ilişkili basit CRUD uygulamaları
- Ad-hoc reporting ve data warehouse senaryoları
- Tüm entity type'ları için strong consistency gerekiyor
- Farklı entity'lerin tamamen farklı access pattern'leri var
Rick Houlihan'ın 2024 güncellemesi vurguluyor: "Birlikte erişilen şeyler birlikte saklanmalı." İlgisiz veriyi sadece bir pattern'i takip etmek için tek tabloya zorlama.
Partition Key ve Sort Key Stratejileri
Single-table design'ın temeli, key'lerini nasıl yapılandıracağını anlamakta yatıyor.
Partition Key Pattern'leri
Kaçınılması Gereken Anti-Pattern:
Sort Key Pattern'leri
Sort key'ler range query'leri ve hierarchical organization'ı mümkün kılıyor:
Best Practice'ler:
- High-cardinality partition key'ler kullan (userId, orderId, productId)
begins_withveBETWEENile range query'leri destekleyecek sort key'ler tasarla- Chronological ordering için timestamp ekle
- Entity type'ları boyunca consistent prefix'ler kullan
İlişkileri Modelleme
Her ilişki türünü çalışan örneklerle nasıl modelleyeceğini göstereyim.
One-to-One İlişkiler
İlişkili veriyi aynı item collection'da farklı sort key'lerle sakla:
One-to-Many İlişkiler
Item collection'lar one-to-many ilişkileri basitleştiriyor:
Many-to-Many İlişkiler
Many-to-many ilişkileri modellemek için adjacency list pattern kullan:
Trade-off: Her iki yönü yazmak write operation'larını ikiye katlar ama Scan operation'ı olmadan her iki yönde de efficient query'leri mümkün kılar.
Denormalization Pattern
Bazen sık erişilen veriye ekstra query olmadan ihtiyacın var:
Trade-off Analizi:
- Daha hızlı read'ler: Customer detaylarını ayrıca fetch etmeye gerek yok
- Daha karmaşık write'lar: Customer name güncellemesi tüm order'larını güncellemeyi gerektirir
- Storage overhead: Customer verisi order'lar boyunca duplicate edilir
- Eventual consistency: Customer data güncellemeleri order'ları güncellemek için background job gerektirir
Denormalization'ı read sıklığı write sıklığından önemli ölçüde fazla olduğunda ve veri nadiren değiştiğinde kullan.
GSI vs LSI: Doğru Seçim
Global Secondary Index'ler ile Local Secondary Index'ler arasındaki farkları anlamak efficient access pattern'ler için kritik.
Local Secondary Index (LSI)
LSI, base table ile partition key'i paylaşır ama farklı sort key kullanır:
LSI Özellikleri:
- Table creation'da tanımlanmalı (sonradan eklenemez)
- Base table ile partition key paylaşır
- Strongly consistent read'leri destekler
- Base table ile throughput capacity paylaşır
- Partition key value başına 10GB limit
- Table başına maksimum 5 LSI
- Ek capacity planning gerektirmez
Global Secondary Index (GSI)
GSI farklı partition ve sort key'ler kullanır, tamamen yeni access pattern'leri mümkün kılar:
GSI Özellikleri:
- Table creation'dan sonra eklenebilir veya çıkarılabilir
- Base table'dan farklı partition ve sort key'ler
- Sadece eventually consistent (strong consistency yok)
- Provisioned mode'da independent throughput
- Size limit'i yok
- Table başına maksimum 20 GSI (5'ten artırıldı)
- Cross-partition query'leri mümkün kılar
Karar Matrisi
LSI Ne Zaman Kullanılmalı:
- Strong consistency gerektiğinde
- Aynı partition'ı alternative sort order ile query ederken
- Küçük dataset'ler (< 10GB per partition)
- Access pattern'ler table creation'da bilindiğinde
GSI Ne Zaman Kullanılmalı:
- Access pattern için farklı partition key gerektiğinde
- Cross-partition query'ler gerektiğinde
- Mevcut table'a yeni access pattern eklerken
- Eventually consistent read'ler kabul edilebilir olduğunda
- Büyük dataset'lerde
Sparse Index Pattern
Sadece GSI attribute'larına sahip item'lar index'e dahil edilir, storage maliyetlerini azaltır:
Maliyet Tasarrufu: Sadece %10 user active ise, sparse indexing GSI storage'ı %90 azaltır.
DynamoDB Accelerator (DAX) Entegrasyonu
DAX, read-heavy workload'lar için in-memory caching ile microsecond response time'ları sağlıyor.
DAX Ne Zaman Kullanılmalı
DAX Ne Zaman KULLANILMAMALI
DAX Implementasyonu
DAX Performance Metrikleri
Maliyet Analizi
Query Optimizasyon Teknikleri
Query ve Scan operation'ları arasındaki fark performans ve maliyeti dramatik şekilde etkiliyor.
Query vs Scan
Gerçek Dünya Etkisi
Milyonlarca user'lı sistemlerde çalışırken maliyet farkının dramatik olduğunu öğrendim:
Projection Optimizasyonu
Batch Operation'lar
Filtreleme için Composite Sort Key
Hot Partition'ları Önleme
Her DynamoDB partition 3,000 RCU ve 1,000 WCU destekler. Bu limitleri aşmak throttling'e neden olur.
Hot Partition Senaryoları
Önleme Stratejisi 1: Write Sharding
Önleme Stratejisi 2: Composite High-Cardinality Key'ler
Önleme Stratejisi 3: Deterministik Sharding
Bu yaklaşım aynı entity'nin her zaman aynı shard'a gitmesini sağlar, tüm shard'ları query etmeden consistent read'leri mümkün kılar.
Maliyet Optimizasyon Stratejileri
Provisioned vs On-Demand
Provisioned Ne Zaman Kullanılmalı:
- Öngörülebilir trafik pattern'leri
- Yüksek volume (günde >1M request)
- 7/24 production uygulamaları
- Budget-conscious senaryolar
- Reserved capacity'ye commit edilebilir (1-yıl %54 veya 3-yıl %77 tasarruf)
On-Demand Ne Zaman Kullanılmalı:
- Öngörülemez trafik
- Bilinmeyen yükü olan yeni uygulamalar
- Development/testing ortamları
- Spiky workload'lar (10x varyans)
- Küçük ölçekli uygulamalar (günde 1M'den az request)
Sparse Index Tasarrufu
Single-Table Maliyet Faydaları
Yaygın Hatalar ve Çözümler
Hata 1: Access Pattern'leri Önce Dokümante Etmemek
Deneyim gösteriyor ki query'leri anlamadan table tasarlamak yeniden tasarımlara yol açıyor:
Hata 2: Throttling için Error Handling Eksikliği
Hata 3: Item Size Limitlerini Görmezden Gelmek
Hata 4: Table Creation'da LSI Planlamama
Table creation'dan sonra LSI ekleyemezsin. Sonradan ihtiyacın olursa veri migration gerektirir:
Hata 5: Yanlış Capacity Mode
Single-Table Design NE ZAMAN Kullanılmamalı
Single-table design her zaman doğru seçim değil. Ne zaman kaçınmalı:
Ayrı Table'lar Ne Zaman Kullanılmalı:
- Farklı entity type'ları çok farklı consistency gereksinimlerine sahip
- Ekipte DynamoDB uzmanlığı yok (öğrenme eğrisi velocity'yi etkiler)
- Minimal ilişkili basit CRUD (overhead gerekçelendirilemiyor)
- Ad-hoc reporting ihtiyaçları (data warehouse pattern'leri daha uygun)
- Microservice'lerde service boundary'leri (servis başına ayrı table'lar)
- Farklı entity'lerin access pattern örtüşmesi yok
Rick Houlihan'ın 2024 rehberliği: "Configuration ve operational veriyi single table'da karıştırma. Service boundary'leri boyunca single table sürdürme."
Temel Çıkarımlar
DynamoDB single-table design ile çalışırken öğrendiklerim:
- Access pattern'ler önce: Schema tasarlamadan önce tüm query'leri dokümante et
- Data locality: İlişkili veriyi aynı partition key ile birlikte sakla
- Scan değil query: Her zaman Query operation'ları için tasarla (100-1000x daha ucuz)
- GSI vs LSI: Esneklik için GSI'lar, strong consistency için LSI'lar
- Hot partition'lar: High-cardinality partition key'ler kullan, gerektiğinde sharding implementasyonu
- DAX ROI: %90+ cache hit rate ile saniyede ~300 req'te break-even
- Maliyet optimizasyonu: Sabit trafik için provisioned mode (6-7x daha ucuz)
- Sparse index'ler: Subset'leri index'leyerek storage'da %50+ tasarruf
- Projection optimizasyonu: ALL yerine INCLUDE veya KEYS_ONLY kullan
- Limitleri bil: Item başına 400KB, LSI partition başına 10GB, partition başına 3,000 RCU
Type-Safe Implementation Kütüphaneleri
Single-table design pattern'lerini TypeScript ile implement ederken, raw AWS SDK yerine type-safe kütüphaneler kullanmak development hızını artırıyor ve runtime hatalarını önlüyor. İki popüler seçenek var:
DynamoDB Toolbox
DynamoDB Toolbox, AWS SDK v3 ile uyumlu, modern bir TypeScript kütüphanesi:
- Type Safety: Entity tanımlarından otomatik TypeScript tipleri
- Schema Validation: Runtime'da veri doğrulama
- Query Builder: Type-safe query ve update expression'ları
- Single-Table Desteği: GSI ve composite key pattern'leri için built-in support
- AWS SDK v3: Son SDK versiyonu ile tam uyumluluk
Raw AWS SDK ile yazdığın karmaşık AttributeValue mapping'leri yerine, temiz ve bakımı kolay entity tanımları kullanabilirsin. Detaylı implementation örnekleri ve production best practice'leri için DynamoDB Toolbox rehberini incele.
OneTable
OneTable, single-table design için özel olarak tasarlanmış alternatif bir kütüphane:
- Schema-Driven: JSON schema ile model tanımlama
- Migration Support: Built-in schema migration desteği
- TypeScript Generation: Schema'dan otomatik type generation
- Developer Experience: Minimal boilerplate, sezgisel API
- Validation: JSON Schema standardı ile güçlü validation
OneTable, özellikle büyük ve karmaşık single-table design'larda schema evolution ve migration ihtiyaçları için güçlü araçlar sunuyor.
Hangisini Seçmeli?
DynamoDB Toolbox tercih et:
- AWS SDK v3'e migrate ediyorsan veya yeni başlıyorsan
- AWS ekosistemi ile daha sıkı entegrasyon istiyorsan
- Daha fazla AWS-native pattern kullanacaksan
- Sitede detaylı rehber mevcut
OneTable tercih et:
- Schema migration'lar sık yapıyorsan
- JSON Schema standardını tercih ediyorsan
- Daha fazla abstraction ve convention over configuration istiyorsan
- Hızlı prototyping yapıyorsan
Her iki kütüphane de production-ready ve aktif olarak maintain ediliyor. Seçim, team preference ve proje gereksinimlerine bağlı.
İlgili Konular
DynamoDB ile çalışmak keşfetmeye değer birkaç alana bağlanıyor:
- DynamoDB Toolbox ile TypeScript Geliştirme - Single-table design için type-safe entity tanımları ve schema validation
- AWS Lambda Guide 101: Cold Start Optimizasyonu - Serverless'ta verimli DynamoDB sorguları
- Serverless'tan CDK'ya Migration Rehberi - DynamoDB tablolarını CDK ile yönetme
- Serverless Architecture Pattern'leri - Event-driven sistemlerde DynamoDB
Single-table design, relational düşünmeden paradigma kaymasını temsil ediyor. Anahtar, önce access pattern'lerini anlamak, efficient query'leri destekleyecek key'ler tasarlamak ve workload'una uygun index'leri seçmek. Basit pattern'lerle başla, performansı ölç ve gerçek kullanıma göre tasarımını geliştir.