Durability guarantee
S2 provides a strong durability guarantee:All acknowledged appends are durable on object storage before the acknowledgment is returned to the client.
- No acknowledged data loss: If you receive an ack, the data is durable
- No silent failures: Failed writes return errors, not acknowledgments
- Crash recovery: Server crashes cannot lose acknowledged data
- Consistent reads: Acknowledged writes are immediately visible to all readers
Write path durability
The append operation follows a strict durability protocol:Write implementation
From/home/daytona/workspace/source/lite/src/backend/streamer.rs:626-679:
- Atomic batch writes: All records in a batch are written together
- await_durable flag: Write only returns after durability is confirmed
- Tail position update: Included in the same atomic write
SlateDB durability
s2-lite uses SlateDB as its storage engine, which provides:- LSM-tree structure: Write-optimized log-structured merge tree
- Object storage backend: All data stored in S3-compatible object storage
- Write-ahead log: Changes are logged before being applied
- Flush intervals: Configurable intervals for flushing to object storage
/home/daytona/workspace/source/README.md:59-61):
It uses SlateDB as its storage engine, which relies entirely on object storage for durability. Just like s2.dev, data is always durable on object storage before being acknowledged or returned to readers.
Configuring flush intervals
SlateDB’s flush interval controls how often in-memory data is flushed to object storage:Storage layout
Records are stored in SlateDB with two keys per record: From/home/daytona/workspace/source/lite/src/backend/kv/mod.rs:87-98:
Record data
- Key: Stream ID + sequence number + timestamp
- Value: The encoded record (headers + body)
- Immutable: Never updated after write
- TTL: Respects retention policy
Record timestamp index
- Key: Stream ID + timestamp + sequence number
- Value: Empty (existence is sufficient)
- Purpose: Enables timestamp-based reads
- TTL: Same as record data
Tail position
- Atomically updated with each append
- Includes write timestamp for freshness tracking
- Used to determine the next sequence number
Retention and TTL
Records can be automatically trimmed based on age: From/home/daytona/workspace/source/lite/src/backend/streamer.rs:635-638:
- Age-based: Records expire after the configured duration
- Infinite: Records never expire automatically
- TTL enforcement: SlateDB handles expiration during compaction
Expired records are removed during SlateDB compaction, not immediately upon expiration.
Pipelining and performance
To achieve high throughput, s2-lite supports pipelined appends: From/home/daytona/workspace/source/lite/src/backend/streamer.rs:111-116:
- Multiple in-flight appends: Appends pipeline to object storage
- Ordered completion: Results are processed in order via
FuturesOrdered - Backpressure: Semaphore limits total in-flight bytes
/home/daytona/workspace/source/README.md:177-179):
Pipelining is temporarily disabled by default, and it will be enabled once it is completely safe.
For now, you can use S2LITE_PIPELINE=true to get a sense of what performance will look like.
Backpressure mechanism
From/home/daytona/workspace/source/lite/src/backend/streamer.rs:93-96:
/home/daytona/workspace/source/lite/src/backend/streamer.rs:464-476:
Failure scenarios
Client fails before receiving ack
Scenario: Client sends append, server writes to storage, but client disconnects before receiving ack. Result:- Records are durable and assigned sequence numbers
- Client doesn’t know if append succeeded
- Client can use
match_seq_numon retry to detect duplicate
Server crashes after write
Scenario: Server writes to object storage and crashes before sending ack. Result:- Records are durable on object storage
- On restart, server loads tail position from storage
- All durable records are visible to readers
Object storage write fails
Scenario: SlateDB write to object storage returns an error. Result:- Error propagated to streamer
- All pending appends for that write fail
- Client receives error, knows append did not succeed
- Client can safely retry
/home/daytona/workspace/source/lite/src/backend/streamer.rs:377-381:
Network partition
Scenario: Network partition between s2-lite and object storage. Result:- Writes fail and return errors
- No acknowledgments sent to clients
- No data loss occurs
- Service resumes when partition heals
Comparing with other systems
| System | Durability Model | Acknowledgment |
|---|---|---|
| S2 | Durable before ack | After object storage write |
| Kafka | Configurable | After replication (if acks=all) |
| Redis Streams | In-memory | Immediately (unless AOF sync) |
| Kinesis | Durable before ack | After multi-AZ replication |
| Pulsar | Configurable | After quorum write to bookies |
S2’s object storage backend provides 11 nines of durability (99.999999999%) with services like AWS S3.
Monitoring durability
Key metrics to monitor:Write latency
/home/daytona/workspace/source/lite/src/backend/streamer.rs:574:
- Measures time from append request to ack
- Includes durability confirmation
- Should correlate with object storage latency
Flush metrics
SlateDB exposes flush-related metrics:- flush_interval: Configured flush interval
- flush_duration: Actual time to complete flush
- flush_bytes: Bytes flushed per interval
Health checks
- Server is running
- Can accept requests
- SlateDB is operational
Best practices
- Trust the ack: Only consider writes successful when ack is received
- Handle errors: Implement retry logic for failed appends
- Use match_seq_num: Prevent duplicates on retry with optimistic concurrency
- Monitor latency: Watch write latency to detect object storage issues
- Configure flush interval: Tune based on latency/throughput requirements
- Test failure scenarios: Verify application handles partial failures correctly
Object storage options
S2-lite works with any S3-compatible object storage:AWS S3
Tigris, Cloudflare R2, etc.
Local disk
In-memory (testing)
In-memory mode has no durability - all data is lost on restart. Use only for testing.
Next steps
Deployment guide
Learn how to deploy s2-lite in production
API reference
Explore the complete API documentation