Guide · Kinesis Data Streams Resharding

Kinesis Data Streams Resharding for MCP Servers — UpdateShardCount, On-Demand Mode, Hot Shard Remediation

Each Kinesis Data Streams shard handles 1 MiB/s ingest (up to 1,000 records/second via PutRecord, 500 records/s via PutRecords) and 2 MiB/s read for standard consumers. When your MCP probe pipeline grows beyond what the current shard count can handle — or when a poor partition key choice concentrates all traffic onto one shard — you need to resize the stream. Kinesis offers two paths: manual resharding via UpdateShardCount or SplitShard/MergeShards operations, and on-demand mode which auto-scales between 1 and 200 shards without any API calls. Understanding which to use, and how resharding interacts with your consumers (KCL's SHARD_END handling, Lambda ESM's child shard continuation), determines whether a capacity change is seamless or causes consumer lag spikes.

TL;DR

Use on-demand mode for new streams where traffic is unpredictable — it scales automatically up to 200 shards without operator action. Switch to provisioned mode when traffic is stable and predictable (lower cost) or when you need precise control over shard-level partition key routing. Use UpdateShardCount for bulk provisioned resizes; use SplitShard for targeted hot shard remediation by specifying the exact hash key range split point. After resharding, KCL consumers automatically detect child shards via lease table; Lambda ESM automatically discovers and begins processing child shards after parent shards reach SHARD_END. Monitor WriteProvisionedThroughputExceeded per shard to detect hot shards before they drop records.

Shard capacity limits and cost model

DimensionPer shard limitNotes
Write throughput1 MiB/s or 1,000 records/sWhichever is hit first
PutRecord calls1,000/sPer shard
PutRecords batch500 records or 5 MiB per callPutRecords calls count toward per-shard write limits per record in the batch
Read throughput (standard)2 MiB/s sharedShared across all GetRecords consumers on this shard
Read throughput (EFO)2 MiB/s per registered consumerDedicated per Enhanced Fan-Out consumer
GetRecords calls5 calls/s per shardShared across all standard consumers
Data retention24 hours to 365 daysExtended retention charged per GB-hour

For AliveMCP, the write side is the binding constraint: 5,000 MCP endpoints × 1 probe/60s = ~83 probe results/second at steady state, roughly 83 × 2 KB = 166 KiB/s — well within 1 shard. During a scan wave (all endpoints probed within a 10-second burst), that same volume arrives as ~500 records/second — still within 1 shard's 1,000 records/second limit. The 1 MiB/s write limit becomes a concern only if average probe result size exceeds ~2 KB at 500 req/s. At 10,000 endpoints, a 2-shard stream provides comfortable headroom.

On-demand mode: auto-scaling without operator action

On-demand mode eliminates shard capacity planning. Kinesis scales the stream up automatically when ingest exceeds the current capacity (up to a maximum of 200 shards), and scales down (with a 4-hour cooldown) when ingest decreases. The trade-off is cost: on-demand pricing is approximately 3× higher per GB than provisioned mode at steady-state load.

import { KinesisClient, UpdateStreamModeCommand } from '@aws-sdk/client-kinesis';

const client = new KinesisClient({ region: 'us-east-1' });

// Switch existing provisioned stream to on-demand
await client.send(new UpdateStreamModeCommand({
  StreamARN: 'arn:aws:kinesis:us-east-1:123456789012:stream/alivemcp-probe-results',
  StreamModeDetails: {
    StreamMode: 'ON_DEMAND',  // 'PROVISIONED' to switch back
  },
}));

On-demand mode constraints:

When to use on-demand vs provisioned

FactorOn-demandProvisioned
Traffic patternUnpredictable, bursty growthStable, predictable load
Cost at steady state3× higher per GBLower per GB
Hot shard controlKinesis chooses split pointYou choose hash key range split point
Operational burdenZero — no manual resizesMonitor and resize manually
Initial setupBest for new streamsBest for stable, known-load streams

UpdateShardCount: bulk provisioned resize

UpdateShardCount is the recommended way to resize a provisioned stream when you need to add or remove multiple shards at once. It targets a new shard count and executes the splits or merges needed to reach it:

import { UpdateShardCountCommand } from '@aws-sdk/client-kinesis';

// Scale from 4 shards to 8 shards
await client.send(new UpdateShardCountCommand({
  StreamName: 'alivemcp-probe-results',
  TargetShardCount: 8,
  ScalingType: 'UNIFORM_SCALING',  // Only supported value; scales evenly across hash key range
}));

Constraints on UpdateShardCount:

After UpdateShardCount completes, the parent shards are closed (no new writes) and child shards accept new writes. Parent shards continue to serve reads until all existing records age out of retention. KCL consumers automatically detect the new child shards via lease table updates. Lambda ESM automatically begins processing child shards after detecting SHARD_END on parent shards — no ESM configuration change required.

Hot shard detection and targeted SplitShard

A hot shard occurs when a disproportionate fraction of records hash to the same shard's hash key range. For AliveMCP, this could happen if probe results are keyed by endpoint owner ID and one owner has 1,000× more endpoints than others — all their traffic lands on the same shard.

Detecting hot shards with enhanced monitoring

Enable shard-level metrics to identify which specific shards are approaching capacity:

import { EnableEnhancedMonitoringCommand } from '@aws-sdk/client-kinesis';

await client.send(new EnableEnhancedMonitoringCommand({
  StreamName: 'alivemcp-probe-results',
  ShardLevelMetrics: [
    'IncomingBytes',       // Write bytes per shard
    'IncomingRecords',     // Write records per shard
    'OutgoingBytes',       // Read bytes per shard
    'WriteProvisionedThroughputExceeded',  // Throttled writes — the hot shard signal
    'ReadProvisionedThroughputExceeded',   // Throttled reads
    'IteratorAgeMilliseconds',             // Consumer lag per shard
  ],
}));

Alarm on WriteProvisionedThroughputExceeded > 0 per shard. Any non-zero value means records are being dropped on that shard — Kinesis rejects the PutRecord call with ProvisionedThroughputExceededException. Producers with automatic retry will retry with exponential backoff, but this adds latency to probe result delivery.

SplitShard: surgical hot shard remediation

When a specific shard is hot, SplitShard splits it at a chosen hash key midpoint, giving you control over where the split occurs (unlike UpdateShardCount which always splits uniformly):

import { SplitShardCommand, DescribeStreamSummaryCommand,
         ListShardsCommand } from '@aws-sdk/client-kinesis';

// Find the hot shard's starting and ending hash keys
const shards = await client.send(new ListShardsCommand({
  StreamName: 'alivemcp-probe-results',
}));
const hotShard = shards.Shards!.find(s => s.ShardId === 'shardId-000000000001')!;

// Split at the midpoint of the hot shard's hash key range
const startHash = BigInt(hotShard.HashKeyRange!.StartingHashKey);
const endHash = BigInt(hotShard.HashKeyRange!.EndingHashKey);
const midHash = ((startHash + endHash) / 2n).toString();

await client.send(new SplitShardCommand({
  StreamName: 'alivemcp-probe-results',
  ShardToSplit: 'shardId-000000000001',
  NewStartingHashKey: midHash,
}));

After the split, two child shards are created with hash ranges [startHash, midHash-1] and [midHash, endHash]. If the hot traffic is concentrated at one end of the hash range (e.g., most endpoint IDs hash to the upper half), adjust NewStartingHashKey to put the split asymmetrically — 75% of the range in the child that will receive less traffic, 25% in the child that will receive more.

Retention period: 24 hours to 365 days

Default retention is 24 hours. Extended retention (up to 365 days) is available at additional cost per GB-hour. Choose retention based on your replay and backfill needs:

RetentionCostUse case
24 hoursIncluded in shard-hour pricingReal-time processing only; no backfill requirement
7 days+$0.023/GB-hourStandard: covers weekends + on-call lag; allows DLQ replay window
30 days+$0.023/GB-hourMonthly audit trails; compliance requirements
365 days (Long-Term Retention)+$0.00323/GB-hour (discounted tier)Regulatory compliance; historical backfill for new analytics consumers

For AliveMCP, 7-day retention is the practical default. It covers the scenario where a new consumer (e.g., an analytics backfiller) comes online over a weekend and needs to catch up on the prior 7 days of probe results. Retention beyond 7 days makes sense only if probe results are not being archived to S3 or DynamoDB — if they are, Kinesis retention is redundant storage cost.

KDS vs SQS vs EventBridge vs MSK: when to use what

FactorKDSSQSEventBridgeMSK (Kafka)
Message orderingPer-shard ordering (by partition key)FIFO queues only (per message group)No ordering guaranteePer-partition ordering
Multiple consumersYes (EFO for independent bandwidth)No (each message consumed once)Yes (fan-out to multiple targets)Yes (consumer groups, independent)
Retention24h–365dUp to 14 daysNo retention (fire-and-forget)Configurable (default 7 days)
Max message size1 MB256 KB256 KB1 MB (default, configurable higher)
Replay capabilityYes (rewind to any position within retention)No (message deleted after consume)Archive + replay feature availableYes (rewind to any offset within retention)
Throughput ceiling1 MiB/s per shard (scalable)Unlimited (standard), 3,000 msg/s (FIFO)10,000 events/s default (quota-able)Scales with broker count
Best for MCP probe pipelinesMultiple consumers, ordered results, replaySimple work queue (one consumer)Event routing to multiple AWS servicesHigh-throughput, schema evolution

For AliveMCP's probe result pipeline: KDS is the right choice when you need multiple independent consumers (alerter, archiver, analytics, status-page) reading the same results simultaneously with full-speed delivery. Use SQS if you have a single consumer and message durability (DLQ) matters more than ordering or replay. Use EventBridge if you are routing probe events to different AWS services based on content filters (e.g., failed probes → SNS, schema-drift probes → DynamoDB). Use MSK if you already operate Kafka infrastructure and need schema evolution guarantees.

Common failure modes

SymptomCauseFix
ProvisionedThroughputExceededException on writesShard write limit (1 MiB/s or 1,000 rec/s) exceededAdd shards (UpdateShardCount) or enable on-demand mode; fix hot partition key
Records missing after UpdateShardCountProducer still writing to closed parent shardProducer SDK retries automatically against child shards; flush retry backlog
Consumer stuck after reshardingKCL or ESM not detecting SHARD_END on parentEnsure shardEnded calls checkpoint(); ESM auto-detects after parent drains
All records on same shard despite multiple shardsNon-random partition key (e.g., constant string, monotonic ID)Use random high-cardinality partition key (endpointId UUID); or prefix with random bucket
UpdateShardCount rejected with LimitExceededExceptionExceeding 2× scale-up or 10 calls/24h limitChain multiple UpdateShardCount calls with 30-minute wait between each doubling
High cost on on-demand stream at steady-state trafficOn-demand pricing 3× provisioned at sustained loadSwitch to provisioned mode after traffic stabilizes