İçeriğe atla
Ayhan Sipahi Ayhan Sipahi

AWS Kinesis: Tek İsim Altında Dört Servis

Kinesis tek bir servis değil, dört ayrı AWS servisidir. Dördünün ayrımı, altındaki Data Streams shard motoru, maliyet şekli ve ne zaman başka bir şey seçmeli.

“Kinesis”, AWS’deki en fazla anlam yüklenmiş isimlerden biridir. Tek bir ürün değil, farklı problemleri çözen dört ayrı servisi kapsayan bir markadır; bu yüzden konsoldaki bir açılır listeden “Kinesis” seçen bir ekip, çoğu zaman seçtiği servisin varsaydığı işi yapamadığını sonradan fark eder. Bir mühendis “bunu Kinesis’e koyarız” dediğinde neredeyse her zaman Data Streams’i kasteder: shard tabanlı, sıralı ve yeniden okunabilen ham log’u. Diğer üçü bir teslim borusu, bir akış işleme motoru ve bir video servisidir. Aşağıdaki bölümler önce dördünü ayrıştırır, sonra commit etmeden önce bilmen gereken Data Streams mekaniğine, maliyet şekline ve karar sınırlarına derinlemesine iner.

Dört servisin ayrımı

Dördün ikisi hâlâ “Kinesis” önekini taşır; diğer ikisi bu önekten uzaklaştırılarak yeniden adlandırıldı ama eski API’lerini korudu. Aşağıda her biri, var olma sebebi olan tek işiyle birlikte birer paragrafta açıklanıyor.

Amazon Kinesis Data Streams ham gerçek zamanlı veri akışıdır. Shard tabanlıdır, bir shard içinde sıralıdır ve bir saklama penceresi içinde yeniden okunabilir. Producer’ları ve consumer’ları sen yazarsın; dayanıklılığı ve (isteğe bağlı olarak) kapasiteyi AWS yönetir. “Kinesis” denildiğinde nitelemeden kastedilen servis budur ve aşağıdaki derinlemesine incelemenin konusudur.

Amazon Data Firehose (eski adıyla Amazon Kinesis Data Firehose, 2024-02-09’da yeniden adlandırıldı) tamamen yönetilen bir teslim ve ETL borusudur. Akışları yakalar, isteğe bağlı olarak dönüştürür ve S3, Redshift, OpenSearch, Splunk ve Snowflake gibi hedeflere teslim eder. Yönetilecek shard yoktur ve teslimat tamponlanır: alt saniye varış değil, bir tampon aralığının ya da boyutunun dolması beklenir. “Bu verinin sadece S3’e veya bir veri ambarına düşmesini istiyorum” gereksiniminde buna uzan. Firehose kaynağı olarak bir Data Stream’i de tüketebilir, yani ikisi rakip değil, birbirini tamamlar.

Amazon Managed Service for Apache Flink (eski adıyla Amazon Kinesis Data Analytics, 2023-08-30’da yeniden adlandırıldı) durumlu (stateful) akış işleme için serverless Apache Flink’tir: pencereli toplamalar, join’ler ve akışlar üzerinde SQL veya not defteri tabanlı analitik. Akışı sadece taşımak değil, üzerinde hesaplama çalıştırmak istediğinde buna uzan.

Amazon Kinesis Video Streams oynatma, analitik ve makine öğrenmesi için medyayı (video, ses ve diğer zaman kodlu verileri) alır, saklar ve işler. Data Streams’ten ayrı bir API yüzeyi ve fiyatlandırması vardır. Aileden ayrı düşendir: JSON kayıtları değil, medya.

Bir ayrıntı insanları yanıltır. 2024 ve 2023 yeniden adlandırmaları yalnızca konsola, dokümantasyona ve pazarlamaya dokundu. API’ler, CLI komutları, IAM eylem adları ve CloudWatch metrik isim alanları eski tanımlayıcılarını korudu. Yani aws firehose ve kinesisanalytics API adları yeni konsol etiketlerine göre hâlâ “yanlış” görünür. Bu bir hata değil, beklenen durumdur.

ServisAldığı veriBölümlemeyi kim yönetirTipik çıktıBunu kastediyorsan söyle
Kinesis Data StreamsJSON veya ikili kayıtlarSen (partition key, shard’lar)Senin consumer’ların”sıralı, yeniden okunabilir gerçek zamanlı akış”
Amazon Data FirehoseKayıtlar (veya bir Data Stream)Tamamen yönetilenS3, Redshift, OpenSearch, Snowflake”şunu sadece bir hedefe düşür”
Managed Service for Apache FlinkBir akış (Kinesis, Kafka)Tamamen yönetilenToplamlar, türetilmiş akışlar, hedefler”akış üzerinde hesaplama çalıştır”
Kinesis Video StreamsMedya (video, ses)Tamamen yönetilenOynatma, ML, medya analitiği”video al ve işle”

Aşağıdaki her şey ilk satır hakkındadır.

Data Streams nasıl çalışır: shard’lar ve kapasite

Bir Data Stream, shard’lardan oluşan bir kümedir. Shard, kapasite birimidir ve katı limitleri vardır. Provisioned modda shard başına saniyede 1 MB veya 1.000 kayıt (hangi tavan önce dolarsa) yazabilir, GetRecords üzerinden saniyede 2 MB veya 2.000 kayıt okuyabilirsin; bu okuma bütçesi tüm paylaşımlı throughput consumer’ları arasında bölüşülür. Kapasite shard sayısıyla doğrusal ölçeklenir: on shard, on katı throughput verir. Bir akışı boyutlandırmak, beklenen throughput’unu bir shard sayısına çevirmek demektir.

Boyutlandırma için birkaç API limiti önemlidir. Tek bir kaydın veri bloğu 10 MiB’a kadar olabilir (eski 1 MB sınırından yükseltildi); Kinesis aralıklı 1-10 MiB kayıtlar için burst kapasitesi kullanır. Bu kayıt başına sınırı, shard başına saniyelik yazma hızıyla karıştırma; “1 MB” throughput tavanıdır, kayıt boyutu sınırı değil. PutRecords istek başına 500 kayıt veya 10 MiB’a kadar toplar. GetRecords çağrı başına 10.000 kayıt veya 10 MB döndürür, shard başına saniyede 5 okuma işlemi ile; bir çağrı tam 10 MB döndürürse, izleyen 5 saniye içindeki çağrılar ProvisionedThroughputExceededException fırlatır.

Partition key, hash ve shard yerleşimi

Bir producer kayıt yazdığında bir partition key (bir string) verir. Kinesis bu anahtarı MD5 ile 128 bitlik bir tamsayı hash anahtar uzayına hash’ler. Her shard bu uzayın bitişik bir aralığına sahiptir, böylece belirli bir anahtar her zaman aynı shard’a düşer. Sıralamayı çalıştıran kural budur: kayıtlar bir shard içinde, yani partition key başına sıralıdır, asla tüm akış genelinde değil.

alt aralık

orta aralık

üst aralık

Partition key (string)

MD5 ile 128-bit hash

Hangi aralık hash'e sahip?

Shard 1

Shard 2

Shard 3

İki farklı anahtarı aynı shard’a zorlaman gerekirse, yerleşimi bir ExplicitHashKey ile geçersiz kılabilirsin. Bu, her gün kullanılan bir ayar değil, bilinçli bir bir-arada-konumlandırma aracıdır.

Sıcak shard (hot shard) problemi

Yerleşim anahtarı takip ettiği için, çarpık bir anahtar dağılımı orantısız trafiği tek bir shard’a gönderir. O shard kısıtlanır (WriteProvisionedThroughputExceeded) ama akış toplamda az kullanılmış görünür; yani yalnızca akış düzeyindeki toplamlara bakan panolar bolca boş alan gösterir. Bu, en sık yapılan Data Streams tasarım hatasıdır. country veya tenant_id gibi bir partition key, bir ülke ya da bir büyük tenant baskın çıkana kadar makul görünür. Çözüm, daha yüksek kardinaliteye sahip, daha iyi dağılan bir anahtardır. Tenant başına sıralamaya gerçekten ihtiyacın varsa, sıcak bir tenant’ın kendi shard bütçesine ihtiyaç duyacağını kabul et ve ortalamaya değil, en yoğun anahtara göre boyutlandır.

Yeniden bölümleme (resharding): split ve merge

Provisioned modda kapasiteyi yeniden bölümleyerek değiştirirsin. İki temel işlem vardır. SplitShard bir shard’ı iki çocuğa böler, kapasiteyi ve maliyeti yükseltir. MergeShards iki bitişik shard’ı tek bir çocukta birleştirir, ikisini de düşürür. Split ve merge her zaman ikişerlidir. Ana (parent) shard’lar kapanır, çocuklar hash aralığını devralır. Provisioned ölçekleme için UpdateShardCount, split ve merge’leri senin yerine hesaplayan üst düzey çağrıdır. On-demand mod bütün bunları otomatik yapar, yani resharding API’leri bir provisioned-mod meselesidir.

Resharding sırasında consumer’ları bir sıralama kuralı bağlar: bir consumer, çocuklarını okumadan önce bir ana shard’daki tüm kayıtları okumalıdır, yoksa partition key başına sıralama sınırda bozulur. Kinesis Client Library bunu otomatik halleder; elle yazılmış bir consumer buna uymak zorundadır.

Kapasite modları: provisioned ve on-demand

Provisioned mod, shard sayısını kendin belirlemen ve ölçeklemen demektir. Sabit, öngörülebilir ve yüksek throughput’ta en ucuz seçenektir, çünkü GB başına veri ücreti ödemezsin; karşılığında boyutlandırma ve resharding senin sorumluluğundadır.

On-demand mod, AWS’nin shard’ları yönetmesi ve senin yerine otomatik ölçeklemesi demektir. Yeni bir on-demand akış 4 shard (4 MB/s yazma, 8 MB/s okuma) ile başlar ve son 30 günde görülen tepe yazma throughput’unun iki katına kadar otomatik ölçeklenir. Ölçekleme tepkisel olduğu için, yaklaşık 15 dakika içinde önceki tepenin 2 katını aşan ani bir sıçrama yine de kısıtlanabilir. Varsayılan on-demand tavanı 200 MB/s yazma ve 400 MB/s okuma’dır; us-east-1, us-west-2 ve eu-west-1’de 10 GB/s yazma ve 20 GB/s okuma’ya yükselir (başka yerlerde daha yüksek katmanı bir destek talebi açar). Bir akışı 24 saatte iki kez modlar arasında değiştirebilirsin.

Artık on-demand hikâyesinin birinci sınıf bir parçası sayılması gereken üçüncü bir seçenek var. On-demand Advantage modu (2025-11-20’de duyuruldu), On-demand Standard’a göre GB başına yaklaşık %60 daha düşük fiyatlandırmaya ve daha yüksek bir enhanced fan-out consumer sınırına (20 yerine 50) sahip, hesap düzeyinde bir ayardır. Yüksek ve sabit on-demand hacim için güncel maliyet-ve-ölçek hamlesidir, maliyet bölümünde ele alınan bir püf noktasıyla: hesap düzeyinde bir minimum taahhüt.

İpucu: Trafiği bilinmeyen yeni bir akış için makul bir varsayılan on-demand’dir, sonra şekil belli olup oturunca provisioned’a geçmektir. Boyutlandırma kararlarını atlamak için GB başına primi ödemek başlangıçta değer; öngörülebilir, yüksek hacimli bir akışta bunu sonsuza kadar ödemek değmez.

Saklama, teslim ve sıralama

Varsayılan saklama 24 saattir. IncreaseStreamRetentionPeriod ile en fazla 8.760 saate (365 gün) kadar uzatabilirsin; minimum 24 saattir. 24 saatin ötesindeki saklama ücretlendirilir ve uzatılmış katman (24 saat - 7 gün) ile uzun vadeli katman (7 günden fazla - 365 gün) farklı fiyatlandırılır. Uzun vadeli saklama, harici bir arşiv olmadan geriye dönük test, geri doldurma (backfill) ve denetim amaçlı yeniden okumayı mümkün kılan özelliktir.

İki anlamsal gerçek, yazdığın her consumer’ı şekillendirmelidir. Teslim en az bir kez (at-least-once)‘tir, yani consumer’lar idempotent olmalıdır; yeniden denemelerde ve resharding civarında kopyalar oluşur. Producer’lar da PUT yeniden denemelerinde kopya oluşturabilir. Yalnızca bir shard içinde tutan sıralamayla birleşince sonuç somuttur: tekrarsızlaştırma (deduplication) ve sıralamaya duyarlı mantık, bir idempotency anahtarı ve bir dedup deposuyla, consumer tarafına aittir.

Consumer modelleri

Bir Data Stream’i okumanın dört yolu vardır ve aralarındaki fark çoğunlukla shard başına 2 MB/s okuma bütçesinin nasıl paylaşıldığıyla ilgilidir.

Paylaşımlı throughput polling varsayılandır. Her paylaşımlı consumer, shard başına o 2 MB/s’yi (ve saniyede 5 okuma işlemini) bölüşür. İkinci bir consumer ekle, her biri etkin olarak yaklaşık 1 MB/s alır. Üçüncüsünü ekle, açlığa düşmeye başlarlar: consumer’lar geri kaldıkça GetRecords.IteratorAgeMilliseconds yükselir. “Kinesis yavaş” şeklindeki yanlış sonucun arkasındaki mekanizma budur. Yavaş değildir; paylaşımlı okuma bütçesi bölünmektedir.

Kinesis Client Library (KCL), kendi yönettiğin consumer filoları içindir. Shard başına bir lease’i (kiralama) worker’lar arasında koordine eder, shard başına sequence number’ı bir DynamoDB tablosuna checkpoint’ler, shard’ları worker’lar arasında yük dengeler ve resharding’e ana shard’ları çocuklardan önce boşaltarak otomatik tepki verir. KCL 3.x (güncel ana sürüm) iki DynamoDB metadata tablosu daha (worker-metrics ve coordinator-state) ve okuma kapasitesi maliyetini düşürmek için leaseOwner üzerinde bir global secondary index ekler. Ayrıca zarif (graceful) lease devri ekler: bir worker, bir lease’i devretmeden önce checkpoint’lemeyi bitirir, bu da yeniden işlemeyi azaltır. Maliyet sonucuna dikkat: DynamoDB lease tablosu, ekiplerin bir KCL consumer’ı bütçelerken rutin olarak unuttuğu, gerçek ve ücretlendirilen bir yan bağımlılıktır.

Enhanced fan-out (EFO), kayıtlı her consumer’a shard başına ayrılmış 2 MB/s verir; polling yerine SubscribeToShard üzerinden HTTP/2 ile itilir (push) ve tipik olarak yaklaşık 70 ms içinde teslim edilir (AWS’nin yayımladığı rakamlara göre GetRecords’a kıyasla kabaca %65 daha düşük gecikme). Consumer’lar artık birbiriyle çekişmez. Kayıtlı consumer sınırı On-demand Standard ve Provisioned’da akış başına 20, On-demand Advantage’da akış başına 50’dir. EFO ekstra maliyetlidir (bir consumer-shard-saat ücreti artı GB başına bir alım ücreti, consumer başına eklenir), yani kabaca iki ya da üç consumer’ı geçince veya gecikme gerçekten önemli olduğunda hakkını verir.

Lambda’nın bir consumer olarak kullanımı, bir event source mapping (ESM) aracılığıyla, serverless varsayılandır. Lambda her shard’ı yoklar (standart iterator için saniyede yaklaşık bir kez) veya bir consumer ARN’i verirsen EFO ile abone olur, kayıtları toplar ve fonksiyonunu çağırır. Onu 5 dakikaya kadar bir toplama penceresi, 6 MB’a kadar bir yük ve 1 ile 10 arası bir ParallelizationFactor (shard başına eşzamanlı toplu işler, hâlâ partition key başına sıralı) ile ayarlarsın.

Lambda’nın hata davranışı, ezberlenmeye değer püf noktasıdır. Varsayılan olarak MaximumRetryAttempts ve MaximumRecordAgeInSeconds -1, yani sonsuzdur. Yani tek bir zehirli (poison-pill) toplu iş, shard’ını bloke eder ve o kayıtlar saklama süresinden düşene kadar yeniden dener; tek bir kötü kaydın arkasında tüm shard durur. Üç hafifletme önemlidir: BisectBatchOnFunctionError başarısız bir toplu işi bölerek kötü kaydı izole eder (ve retry kotasını tüketmez), sonlu MaximumRetryAttempts veya MaximumRecordAgeInSeconds durmayı sınırlar ve bir OnFailure hedefi (SQS, SNS veya S3) işlenemeyeni yakalar. O hedef hakkında bir uyarı: SQS ve SNS için Lambda yalnızca metadata (streamArn, shardId, startSequenceNumber, endSequenceNumber) gönderir, kayıt gövdelerini değil; yani dead-letter (DLQ) işleyicin, onları kurtarmak için akışı yeniden okumak zorundadır.

ModelShard başına okuma bütçesiGecikmeNe zaman kullanmalı
Paylaşımlı polling2 MB/s tüm consumer’lar arasında bölünürYoklama aralığıBir veya iki consumer, maliyete duyarlı
KCL 3.xPaylaşımlı (veya EFO)Yoklama veya pushCheckpoint ve dengeleme gerektiren kendi filon
Enhanced fan-outConsumer başına ayrılmış 2 MB/s~70 ms pushÜç veya daha fazla consumer, ya da gecikmeye duyarlı
Lambda ESMPaylaşımlı veya EFOYoklama (~1s) veya pushWorker çalıştırmadan serverless işleme

Minimal bir producer ve bir akış kontrolü

AWS SDK v3 JavaScript için sunucu tarafıdır, yani bir Lambda ya da servis producer’ı şöyle görünür. Shard’ı belirleyenin partition key olduğuna dikkat et.

import {
  KinesisClient,
  PutRecordCommand,
} from "@aws-sdk/client-kinesis";

const kinesis = new KinesisClient({ region: "us-east-1" });

export async function publishOrderEvent(order: {
  id: string;
  tenantId: string;
}) {
  await kinesis.send(
    new PutRecordCommand({
      StreamName: "order-events",
      // Yüksek kardinaliteli anahtar yükü shard'lara yayar.
      // Yalnızca tenantId kullanmak büyük bir tenant için sıcak shard riski taşır.
      PartitionKey: `${order.tenantId}#${order.id}`,
      Data: new TextEncoder().encode(JSON.stringify(order)),
    }),
  );
}

Deploy zamanında bir kez bir EFO consumer’ı kaydetmek için en basit yol CLI’dır:

aws kinesis register-stream-consumer \
  --stream-arn arn:aws:kinesis:us-east-1:123456789012:stream/order-events \
  --consumer-name analytics-efo
{
    "Consumer": {
        "ConsumerName": "analytics-efo",
        "ConsumerARN": "arn:aws:kinesis:us-east-1:123456789012:stream/order-events/consumer/analytics-efo:1719532800",
        "ConsumerStatus": "CREATING",
        "ConsumerCreationTimestamp": "2026-06-28T00:00:00+00:00"
    }
}

Bir akışın kapasite modunu ve shard sayısını tüm shard listesini ayrıştırmadan hızlıca okumak istediğinde, doğru çağrı describe-stream-summary’dir:

aws kinesis describe-stream-summary --stream-name order-events
{
    "StreamDescriptionSummary": {
        "StreamName": "order-events",
        "StreamARN": "arn:aws:kinesis:us-east-1:123456789012:stream/order-events",
        "StreamStatus": "ACTIVE",
        "StreamModeDetails": {
            "StreamMode": "ON_DEMAND"
        },
        "RetentionPeriodHours": 24,
        "OpenShardCount": 4,
        "ConsumerCount": 1,
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ]
    }
}

O boş ShardLevelMetrics bir hatırlatmadır: bir sıcak shard’ı asıl ortaya çıkaran shard başına metrikler, EnableEnhancedMonitoring ile isteğe bağlıdır ve ek CloudWatch özel metrikleri olarak ücretlendirilir. IncomingBytes, IncomingRecords ve GetRecords.IteratorAgeMilliseconds gibi akış düzeyi metrikleri varsayılan olarak bir dakika granülaritesinde yayınlanır, ama çarpıklığı gizlerler. Bir sıcak shard’dan şüpheleniyorsan, onu doğrulayacağın yer shard başına görünümdür.

Yaygın kullanım senaryoları

Alan etiketlerini soyduğunda, kanonik Data Streams kullanım senaryoları yukarıdaki mekanikten hep aynı üç özelliği satın alır: ölçekte saniye-altı alım, shard başına sıralama ve bağımsız consumer’lara yeniden okunabilir fan-out. AWS’nin kendi listesi (log alımı, gerçek zamanlı metrikler, gerçek zamanlı analitik ve karmaşık çok-aşamalı işleme) bu özelliklerin farklı kıyafetler giymiş halidir: içeri çok sayıda producer, ortada tek bir sıralı dayanıklı log, dışarı birkaç bağımsız okuyucu.

Kullanım senaryosuNeye dayanırAilede nereye oturur
Log ve event alımıproducer tarafında batch’leme olmadan saniye-altı alım, böylece front-end çökse de veri hayatta kalırData Streams içeri, Firehose ile ham log’ları S3’e düşür
Gerçek zamanlı metrik ve dashboardsıralama artı saniye altı put-to-get gecikmesiData Streams’ten Lambda ya da Managed Service for Apache Flink’e
Clickstream ve ürün analitiğireplay artı paralel, bağımsız çok-consumer okumaData Streams’ten enhanced fan-out ile aynı anda birkaç uygulamaya
IoT ve telemetri alımıpartition key ile cihaz başına sıralama, yüksek throughput’taData Streams, device id ile anahtarlanmış
Streaming ETL ve toplamadurumlu pencereli işleme, sonra düzenlenmiş veriyi düşürmeData Streams’ten Flink’e, Firehose ile bir veri ambarına
Çok aşamalı (DAG) işlemebir aşamanın çıktısı sonraki aşamanın akışını beslerData Streams, Data Streams’e zincirlenir

Şeklin ne sıklıkla tekrarlandığına dikkat et: sıralı, yeniden okunabilir log için Data Streams, üstündeki iş için Firehose ya da Flink. İşte dört servisin ayrı isimlerini bir kez daha hak etmesi, bu kez tanım tarafından değil, kullanım senaryosu tarafından.

Data Streams pratikte: CDC, routing ve idempotency

Mekanik, neredeyse her gerçek Data Streams kurulumunda beliren üç pattern’de karşılığını bulur: veritabanı değişikliklerini bir akış olarak yakalamak, kayıtları içeriğe göre yönlendirmek ve teslim tam-bir-kez değil en-az-bir-kez olduğu için onları idempotent tüketmek.

DynamoDB native CDC

İlişkisel DB AWS DMS ile

Kinesis Data Streams sıralı, yeniden okunabilir

EventBridge Pipes filtrele + zenginleştir

Materialize görünüm idempotent yazma

Arama indeksi

Firehose ile S3 denetim + backfill

Değişiklikleri (CDC) bir akışa yakalamak

Change data capture (CDC), bir veritabanındaki her insert, update ve delete’i sıralı bir event’e çevirir; Data Streams de bunlar için doğal bir evdir: shard başına sıralı, yeniden okunabilir ve aynı anda birçok consumer tarafından okunabilir. İki giriş yolu çoğu durumu kapsar ve her birinin, bağlamadan önce bilmeye değer bir record şekli ve birkaç ayarı vardır.

Doğrudan DynamoDB. Kinesis Data Streams for DynamoDB’yi açtığında tablo, her item-level değişiklik için değişiklik zamanını, item’ın birincil anahtarını ve item’ın hem önceki hem sonraki görüntüsünü taşıyan bir kayıt yayar. Yalnızca açtığın andan itibaren yakalar, yani geçmişi cutover’dan önce bir export ya da scan ile tohumla; backfill yoktur. Düz DynamoDB Streams’ten ayıran şey erişimdir: DynamoDB Streams 24 saat saklar ve kendi KCL adaptörü vardır, oysa Kinesis yolu 365 güne kadar saklama, enhanced fan-out ve consumer olarak Firehose ya da Managed Service for Apache Flink verir. Dokümanların doğrudan belirttiği iki davranış consumer’ını şekillendirir: kayıtlar sırasız gelebilir ve aynı değişiklik birden fazla kez görünebilir. İkisini de her kayıttaki ApproximateCreationDateTime damgasıyla (milisaniye ya da mikrosaniye hassasiyetine ayarlanabilir) çözersin. Bir keskin kenar daha: binary alanlar girişte ikinci kez base64’lenir, yani consumer’lar iki kez decode eder.

AWS DMS üzerinden ilişkisel veritabanları. Bir DMS görevi bir Data Stream’i hedef alır ve her satır değişikliğini bir JSON kaydı olarak yazar; ya da Firehose’un onu Athena için S3’e düşürmesini istediğinde tek satırlık JSON_UNFORMATTED olarak. Kaydı şekillendirir ve partition key’i object mapping ile seçersin. Endpoint ayarları ne kadar bağlamın eşlik edeceğine karar verir: IncludeTransactionDetails commit zaman damgasını ve transaction_id’yi ekler, IncludeTableAlterOperations add-column gibi DDL’i taşır ve before-image ayarları, bir consumer’ın eskiyle yeniyi karşılaştırabilmesi için satırın önceki değerlerini iliştirir. Throttling tuzağı somuttur: birincil anahtarla anahtarlar ve dar anahtarlı binlerce tablo aynı aralığı paylaşırsa, her tablodan aynı anahtar tek bir shard’a yığılır; PartitionIncludeSchemaTable bunu dağıtmak için partition değerine şema ve tablo adını ön ek olarak ekler. Throughput için DMS, CDC’yi 32’ye kadar ParallelApplyThreads ile uygular; bunu açtığında partition key, tablonun birincil anahtarına varsayılır, yani her satır yine tek bir shard’da serileşirken farklı satırlar paralel gider.

İkisinin altındaki kural aynıdır: varlık başına sıralama yalnızca bir shard içinde geçerlidir, yani partition key, varlığın birincil anahtarı olmalıdır. Değişiklikleri customerId ile anahtarla, bir müşterinin geçmişi tek bir shard’da sırada kalır; kaba bir şeyle anahtarla, bir delete onu izlemesi gereken insert’i geçebilir. Tek bir sıcak varlık o zaman sıcak bir shard olur ve aynı anahtarı hem kusursuz sıralayıp hem paralelleştiremezsin; aşağıdaki versiyon tabanlı idempotency’nin ara sıra olan bir sıra bozulmasını zararsız kılmasının nedeni de budur.

Routing: Kinesis böler, EventBridge yönlendirir

Data Streams içeriğe göre yönlendirmez. Tek yönlendirmesi, bir shard’ı seçen partition-key hash’idir; her consumer sahip olduğu shard’lardaki her kaydı okur ve neyi yok sayacağına kendisi karar verir. İhtiyaç “USD 1.000 üzerindeki siparişler şu handler’a, iadeler şuna” haline geldiği an, bu içerik yönlendirmesidir ve Kinesis’e değil EventBridge’e aittir.

EventBridge Pipes bağlayıcı dokudur ve ilk bakışta göründüğünden daha yapılandırılabilirdir. Bir pipe, bir Data Stream’e ya paylaşımlı-throughput consumer’ı ya da ayrılmış enhanced-fan-out consumer’ı olarak bağlanır, her shard’ı saniyede yaklaşık bir kez yoklar ve harekete geçmeden önce beş dakikalık bir pencereye ya da 6 MB’a kadar tamponlar. Shard başına on batch’e kadar paralel çalışabilir ve yine partition-key seviyesinde sırayı korur; kısmi batch hatalarını raporlar, böylece tek bir zehirli kayıt tüm batch’i yeniden denemeye zorlamaz; bu da consumer bölümündeki shard-bloklama probleminin bildirimsel (declarative) çözümüdür. Her kayıt pipe’a bir zarf olarak ulaşır (partitionKey, sequenceNumber, base64 data, approximateArrivalTimestamp); filtre aşaması bu alanlara bir EventBridge event pattern’i uygular ve eşleşmeyen kayıtları, herhangi bir zenginleştirme ya da hedef compute’una mal olmadan düşürür. data base64 olduğu için, derin içerik filtrelemesi genelde ham pattern yerine zenginleştirme adımına (bir Lambda ya da Step Functions akışı ya da 6 MB yanıtla sınırlı bir API çağrısı) dayanır.

Bir pipe tam olarak tek bir hedefe gider. Bir akışı içeriğe göre yönlendirilen birçok hedefe açmak için dokümante edilen şekil şudur: Kinesis’ten bir pipe’a, oradan hedef olarak bir EventBridge event bus’a; sonra bus kuralları ihtiyacın kadar hedefe yönlendirir. İşbölümü temizdir: akış, yeniden okuduğun dayanıklı sıralı log’dur; bus, replay olmadan içerik yönlendiricisi ve fan-out’tur; pipe ise ikisi arasındaki tek yönlü köprüdür.

AraçYönlendirme modeliReplayFaturalama
Kinesis Data Streamsiçeriğe göre değil, partition-key hash’i ile shard’aevet, saklama içindeshard-saati veya GB başına
EventBridge busçok hedefe içerik kuralları, fan-outhayırevent başına
EventBridge Pipestek kaynak, filtrele ve zenginleştir, tek hedef, sıra koruyanhayır, kaynaktan okuristek başına

Idempotency: en-az-bir-kez, çift kayıtları tasarıma katmak demektir

Data Streams en az bir kez teslim eder, dolayısıyla duplicate’ler bir kenar durum değil, sözleşmenin parçasıdır; ve CDC giriş yollarının gösterdiği gibi, kaynak kendi başına sırayı bozabilir ve tekrarlayabilir. Dört şey bunları üretir: bir producer zaman aşımından sonra PutRecord’u yeniden dener ve iki kez yazar; bir consumer bir batch’i işledikten sonra ama checkpoint’ten önce çöker ve yeniden başlayınca tekrar işler; bir reshard sınır civarındaki kayıtları yeniden oynatır; ve DynamoDB’nin kendi değişiklik akışının sırayı bozduğu ve tekrarladığı dokümante edilmiştir. Dördü için de planla.

Savunma, sabit bir kimliğe dayanan bir dedup kapısıdır. Her kayıt bir sequenceNumber taşır; bu, shard’ı içinde partition key başına benzersizdir, dolayısıyla stream genelinde benzersiz bir anahtar için onu shard id ile eşle (bu çift, yukarıdaki pipe zarfında gördüğün eventID’dir) ya da payload’daki bir iş idempotency anahtarını kullan; her ikisi de koşullu bir yazmayı anahtarlar: etkiyi uygulamak ve anahtarı kaydetmek atomik olur ve bir replay no-op’a döner. Apaçık olmayan kısım penceredir: bir stream tüm saklama süresi boyunca, 365 güne kadar yeniden okunabilir, yani bir saatlik TTL’li bir dedup tablosu, bir backfill daha eski geçmişi yeniden oynattığı an sessizce korumayı bırakır. TTL’i gerçekten çalıştıracağın en uzun replay’e göre boyutlandır ve tabloyu, olduğu şey olarak gör: gerçek, faturalanan bir bağımlılık.

CDC için bir adım daha git ve yazmayı yalnızca bir anahtara değil, bir versiyona göre idempotent yap; çünkü kayıtlar bir kez sırasını bozunca “bunu gördüm mü?” yanlış soru, “bu elimdekinden daha mı yeni?” doğru sorudur. Versiyon olarak DynamoDB’nin ApproximateCreationDateTime’ını ya da DMS’in commit zaman damgasını kullan ve bir değişikliği yalnızca depolanandan daha yeniyse uygula. Yeniden teslim edilen ya da sırasız daha eski bir değişiklik o zaman bayat veriyi diriltmek yerine no-op olarak iner.

import {
  DynamoDBClient,
  UpdateItemCommand,
  ConditionalCheckFailedException,
} from "@aws-sdk/client-dynamodb";

const db = new DynamoDBClient({ region: "us-east-1" });

// Bir CDC değişikliğini yalnızca elimizdekinden daha yeniyse uygula.
// Yeniden teslim edilen ya da sırasız bir kayıt koşulu geçemez ve atlanır.
async function applyChange(change: {
  entityId: string;
  version: number;
  state: string;
}) {
  try {
    await db.send(
      new UpdateItemCommand({
        TableName: "projection",
        Key: { id: { S: change.entityId } },
        UpdateExpression: "SET #s = :state, version = :v",
        ConditionExpression: "attribute_not_exists(version) OR version < :v",
        ExpressionAttributeNames: { "#s": "state" },
        ExpressionAttributeValues: {
          ":state": { S: change.state },
          ":v": { N: String(change.version) },
        },
      }),
    );
  } catch (err) {
    if (err instanceof ConditionalCheckFailedException) return; // duplicate veya bayat
    throw err;
  }
}

Pratikte iki ayrıntı ısırır. Producer’ların Kinesis Producer Library kullanıyorsa, o birçok kullanıcı kaydını tek bir Kinesis kaydına paketler ve KCL bunları açar; o yüzden Kinesis kaydı yerine kendi payload anahtarına göre dedup yap. Ve tüm bunları elle yazmak ağır geliyorsa, Managed Service for Apache Flink tam da bunun için: checkpoint’lemesi kendi state’i üzerinde exactly-once işleme verir; işlettiğin dedup deposunu, işlettiğin bir Flink uygulamasıyla takas edersin.

Aynı fikir genel durumu da kapsar; anahtarlar, pencereler ve depolama için daha tam bir ele alış istersen idempotency rehberine bak.

Maliyet modeli

Fiyatlandırma değişir, bu yüzden modeli kalıcı kısım, her dolar rakamını da tarihli bir çapa olarak ele al. Aşağıdaki tüm rakamlar US East (N. Virginia), AWS fiyatlandırma sayfasından, 2026-06-28’de alındı; güvenmeden önce güncelliğini doğrula, çünkü Kinesis fiyatlandırması değişir.

Provisioned mod şu kalemleri faturalandırır:

  • Shard saati: shard-saati başına USD 0,015 (bir shard 1 MB/s yazma, 2 MB/s okumadır).
  • PUT yük birimleri (payload units): milyon birim başına USD 0,014; bir birim, bir kaydın 25 KB’lık bir parçasıdır, yukarı yuvarlanır. 5 KB’lık bir kayıt 1 birim; 30 KB’lık bir kayıt 2 birim; 1 MB’lık bir kayıt 40 birimdir. Yüksek hızlı, küçük kayıtlı iş yüklerini ısıran kalem budur.
  • Uzatılmış saklama (24 saat - 7 gün): shard-saati başına ekstra USD 0,020.
  • Uzun vadeli saklama (7 günden fazla - 365 gün): GB-ay başına USD 0,023 depolama artı GetRecords üzerinden GB başına USD 0,021 alım.
  • Enhanced fan-out: consumer-shard-saati başına USD 0,015 artı alınan GB başına USD 0,013, kayıtlı her consumer için eklenir.

On-demand Standard farklı faturalandırır: stream-saati başına USD 0,040, artı alınan (ingest) GB başına USD 0,08 (1 KB yuvarlama ile), artı alınan (retrieved) GB başına USD 0,040; EFO ayrıca GB başına faturalanır. Sayılacak shard ve shard-saati yoktur.

On-demand Advantage (2025-11-20) alınan GB başına USD 0,032 ve alınan GB başına USD 0,016 faturalandırır, kabaca Standard’ın %60 altında; stream başına saatlik ücret yoktur ve EFO veri-çıkış oranına dâhildir. Püf noktası, hesap düzeyinde 25 MB/s ingest artı 25 MB/s retrieval’lık bir minimum taahhüttür. O minimum, Advantage’ı küçük akışlar için bir varsayılan değil, tam olarak yüksek-sabit-throughput hamlesi yapan şeydir.

Adım adım örnek hesap

Yaklaşık 1.000 kayıt/s ve her biri kabaca 3 KB olan bir iş yükü düşün; bu yaklaşık 3 MB/s ingest demektir. Aşağıdaki aritmetik yöntemdir; kendi rakamların için güncel fiyatlarla yeniden hesapla.

Provisioned modda, 3 MB/s throughput ceil(3 / 1) = 3 shard gerektirir (saniyede 1.000 kayıt/shard sınırı burada bağlayıcı kısıt değil, byte hızı bağlayıcı). İki EFO consumer’ı ekle.

KalemHesapAylık
Shard saatleri3 shard x USD 0,015 x 730 sa~USD 32,85
PUT yük birimleri~2,63 milyar birim x USD 0,014/milyon~USD 36,80
EFO consumer-shard saatleri2 x 3 shard x USD 0,015 x 730 sa~USD 65,70
EFO + alımüstüne GB başına alımhacimle artar

Aynı 3 MB/s, On-demand Standard altında ayda yaklaşık 7,78 TB alır; bu GB başına USD 0,08 ile sadece ingest ücretinde, alım hariç, kabaca USD 622 eder. Bu fark, bütün mesele: provisioned sabit, öngörülebilir yükte kazanır; on-demand ani ya da bilinmeyen yükte kazanır. Geçiş noktası gerçek ve büyüktür, yani kapasite-modu seçimi yalnızca operasyonel değil, bir maliyet kararıdır.

Servisler arasında faturanın şekli, kesin rakamlardan daha fazla değişir. Data Streams provisioned throughput (shard-saatleri) veya GB başına (on-demand) ücretlendirir. SQS istek başına ücretlendirir (Standard, bu tarihte us-east-1’de kabaca milyon istek başına USD 0,40; doğrula) ve sıfıra ölçeklenir, ama FIFO dışında sıralama, yeniden okuma ve tek bir kuyruktan bire-çok fan-out sunmaz. MSK, boştayken bile faturalanan bir küme (broker-saatleri artı depolama) için ücretlendirir; karşılığında Kafka semantiği ve daha yüksek bir taban verir. İş yükü şekline göre seç, fatura da şekli takip eder.

Data Streams ne zaman doğru cevap, ne zaman değil

Sıralı, yeniden okunabilir, çok consumer’lı gerçek zamanlı bir akışa ihtiyacın olduğunda ve Kafka işletmeden yönetilen, shard ile boyutlandırılan bir servis istediğinde Kinesis Data Streams’e uzan. Onun tatlı noktası budur ve akış kullanım durumu içinde mantıklı varsayılandır. O üç özellikten (sıralama, yeniden okuma, birden çok bağımsız consumer) biri gerçekten gerekli olmadığı anda, daha basit bir servis genellikle kazanır.

Hayır, sadece işi ayrıştır

Hayır, olayları AWS hedeflerine yönlendir ve filtrele

Hayır, tablo değişikliklerine tepki ver

Evet, Kafka semantiği ya da taşınabilirlik gerek

Evet, AWS-yerel ve yönetilen

Sadece S3 ya da veri ambarına düşür

Üzerinde durumlu hesaplama çalıştır

Kendi consumer'larını bağla

Sıralama, yeniden okuma VE birden çok bağımsız consumer gerekli mi?

SQS iş kuyruğu

EventBridge

DynamoDB Streams

Amazon MSK

Kinesis Data Streams

Sonra ne?

Amazon Data Firehose

Managed Service for Apache Flink

Kendi KCL veya Lambda consumer'ların

Bu sınırlar bu sitede başka yerlerde zaten derinlemesine tartışıldı, bu yüzden burada yeniden açmak yerine: soru Kafka mı, bus mu ise, bkz. Kafka mı, event bus mı: geçiş sinyalleri. SNS ve SQS fan-out desenleri için bkz. SNS’ten SQS’e hesaplar arası fan-out ve İzole consumer hesaplarına event fan-out. Event sistemi seçeneklerinin daha geniş manzarası için bkz. Event-driven sistem araçları karşılaştırması.

Sık yapılan hatalar

Birkaç hata, ekiplerin Data Streams’le yaşadığı sıkıntının çoğunu açıklar.

  • Data Streams gerekirken Firehose seçmek ya da tersi. Firehose yalnızca tamponlanmış teslimdir; veriyi bir hedefe düşürür ve birçok bağımsız consumer bağladığın yeniden okunabilir bir log değildir. Tersine, Firehose (kaynağı olarak bir Data Stream’i tüketebilir) sıfır kodla halledecekken Data Streams üzerinde S3 teslimini elle yazmak.
  • Düşük kardinaliteli bir partition key’in sıcak shard yaratması. Anahtarı dağıt; explicit hash key’i yalnızca bir-arada-konumlandırma amacın olduğunda kullan.
  • Üçüncü veya dördüncü paylaşımlı consumer’ı ekleyip gecikme için Kinesis’i suçlamak, enhanced fan-out’a geçmek yerine.
  • En-az-bir-kez teslim altında idempotent olmayan consumer’lar, ki bu yeniden denemelerde ve resharding civarında çift işlemeye yol açar.
  • Başarısız bir Lambda toplu işinin shard’ını bloke edebileceğini unutmak, kayıtlar düşene kadar; BisectBatchOnFunctionError, sonlu retry’lar ya da bir on-failure hedefi yapılandırmamak.
  • Saklamanın bedava ve sınırsız olduğunu varsaymak. Uzatılmış ve uzun vadeli saklama ücretlendirilir ve iki katman farklı fiyatlandırılır.
  • Paylaşımlı modda shard çıkışını consumer başına sanmak. Paylaşımlı bir 2 MB/s’dir; yalnızca EFO onu consumer başına yapar.

Kapanış

Kinesis dört servistir ve çoğu zaman Data Streams’i kastedersin: kendi consumer’larını bağladığın, sıralı, yeniden okunabilir, shard ile boyutlandırılan bir akış. Throughput’u shard’lara çevirerek boyutlandır, partition key’i hiçbir tek shard sıcak çalışmayacak şekilde seç, kapasite modunu alışkanlıktan değil trafik öngörülebilirliğinden seç ve her consumer’ı idempotent yap, çünkü teslim en-az-bir-kez’dir. Sınır, en az varsayılan kadar önemlidir. Sıralama, yeniden okuma ve bağımsız çok-consumer fan-out’a birlikte ihtiyacın yoksa, bir iş kuyruğu, bir event yönlendirici ya da bir tablo akışı daha basit ve çoğu zaman daha ucuz cevaptır; Kafka ağırlıklı bir ortam ise MSK ile daha iyi hizmet alır. Commit etmeden önceki somut sonraki adım, beklenen tepe throughput’unu ve consumer sayını kâğıda yazmak ve ikisini de shard başına limitlere karşı kontrol etmektir; boyutlandırma bundan çıkar, fatura da öyle.

Kaynaklar

İlgili yazılar