HN user

shikhar

256 karma

Making durable streams serverless

shikhar@s2.dev

Posts37
Comments92
View on HN
github.com 10d ago

Show HN: Async NFS client library for Rust, without an OS mount point

shikhar
4pts0
www.opbox.dev 15d ago

Opbox: Real-time sync for plaintext files

shikhar
2pts0
s2.dev 22d ago

Serving Local AI on My Jetson Through Durable Streams

shikhar
3pts0
github.com 1mo ago

Show HN: RePlaya – self-hosted browser session replay with live tailing

shikhar
50pts8
txt.box 2mo ago

Shareable text box

shikhar
4pts0
s2.dev 4mo ago

Video Conferencing with Durable Streams

shikhar
3pts0
s2.dev 4mo ago

Coordinating Adversarial AI Agents

shikhar
2pts0
github.com 6mo ago

Show HN: S2-lite, an open source Stream Store

shikhar
77pts20
github.com 10mo ago

Read-through cache for object storage

shikhar
3pts0
github.com 10mo ago

Show HN: Cachey, a Read-Through Cache for S3

shikhar
3pts2
www.catherinejue.com 11mo ago

Reliable

shikhar
2pts1
s2.dev 1y ago

Multi-Player Durable Stream Playground

shikhar
9pts4
s2.dev 1y ago

Why Agents Need Granular Streams

shikhar
1pts0
github.com 1y ago

Durable, multi-player pseudo-terminal

shikhar
3pts0
github.com 1y ago

Remote log implementation for XTDB using s2.dev

shikhar
3pts1
s2.dev 1y ago

Multi-player, serverless, durable terminals

shikhar
2pts0
s2.dev 1y ago

Streams as access-controlled web resources

shikhar
1pts0
s2.dev 1y ago

Keeping Time on a Stream

shikhar
5pts0
s2.dev 1y ago

Deterministic simulation testing for async Rust

shikhar
107pts10
blog.sequinstream.com 1y ago

Streaming changes from Postgres: the architecture behind Sequin

shikhar
1pts0
www.hytradboi.com 1y ago

Serverless primitives for the shared log architecture [video]

shikhar
4pts0
s2.dev 1y ago

Fast IoT data pipeline for infrared monitoring

shikhar
4pts0
s2.dev 1y ago

One weird trick to durably replicate your KV store

shikhar
3pts0
blog.schmizz.net 2y ago

Designing Serverless Stream Storage

shikhar
4pts0
erikbern.com 2y ago

Software infrastructure 2.0: a wishlist (2021)

shikhar
12pts0
blog.schmizz.net 2y ago

Designing Serverless Stream Storage

shikhar
7pts0
www.gomomento.com 2y ago

Fighting off faux-serverless bandits with the true definition of serverless

shikhar
1pts0
maheshba.bitbucket.io 2y ago

The leadership myth in replicated databases (2023)

shikhar
60pts3
maheshba.bitbucket.io 2y ago

The leadership myth in replicated databases (2023)

shikhar
1pts0
aws.amazon.com 2y ago

Amazon Time Sync Service now supports microsecond-accurate time

shikhar
52pts23

OpenReplay is much more mature and full-featured, RePlaya is just the core session capture, listing, and replay functionality. OpenReplay has more dependencies, so self-hosting means running a full stack: Postgres, ClickHouse, Redis, and its backend services. RePlaya is one stateless Node process plus S2 (or self-hosted s2-lite).

Thanks! And agreed, session replays can be really useful to understand user behaviour such as product edge cases.

On cost, it's running the collector Node app (I'd expect a few $ per month at low volume), and the S2 stream backend.

If you use the S2 cloud service, cost is basically just the rrweb bytes. The rates are $0.075/GiB to write, $0.05/GiB-month to store, $0.10/GiB to read back over the internet. See s2.dev/pricing.md for an agent-friendly summary.

Assuming a typical few-minute session is ~1 MiB of events, ingesting it, storing it a month, and replaying it a couple of times (unlikely!):

1k sessions/mo ≈ $0.35

10k sessions/mo ≈ $3.50

100k sessions/mo ≈ $35

Personally I'd add an application level hash to protect the integrity of the records but that's just me.

The durability is for being able to replay the stream, a hash will not let you reconstruct the original message(s).

If you just need ephemeral comms, making it persistent is indeed overkill. But reliability challenges often come up with seemingly ephemeral comms too – think streaming responses from an LLM. The last mile can be pretty flaky e.g. iOS will cancel connections when users background an app. Using a durable stream for persisting the tokens means a client can ask to resume from where it left off / from the beginning of the stream, and the data would be available without having to re-inference.

Can this be used as an embedded lib instead of a separate binary as an API?

Did not architect explicitly for that, but should be viable. You could use the `Backend` directly, is what the REST handlers call https://docs.rs/s2-lite/latest/s2_lite/backend/struct.Backen...

Happy to accept contributions that make this more ergonomic.

And am I understanding correctly that if I pointed 2 running instances of s2-lite at the same place in s3 there would be problems since slatedb is single writer?

SL8 will fence the older writer, thanks to S3 conditional writes. I think there would be potential for stale reads until the fencing happens...

ED: Fresh discussion in https://discord.com/channels/1232385660460204122/12323856609...

The stale read potential can be mitigated, https://github.com/s2-streamstore/s2/issues/91

We wanted S2 to be one API. Started out with gRPC, added REST - then realized REST is what is absolutely essential and what most folks care about. gRPC did give us bi-directional streaming for append/read sessions, so we added that as an optional enhancement to the corresponding POST/GET data plane endpoints (the S2S "S2-Session" spec I linked to above). A nice side win is that the stream resource is known from the requested URL rather than having to wait for the first gRPC message.

gRPC ecosystem is also not very uniform despite its popularity, comes with bloat, is a bit of a mess in Python. I'm hoping QUIC enables a viable gRPC alternative to emerge.

This is fair question. A stream here == a log. Every write with S2 implementations is durable before it is acknowledged, and it can be consumed in real-time or replayed from any position by multiple readers. The stream is at the granularity of discrete records, rather than a byte stream (although you can certainly layer either over the other).

ED: no k8s required for s2-lite, it is just a singe binary. It was an architectural note about our cloud service.

Shoutout to CodesInChaos for suggesting that instead of a mere emulator, should have an actually durable open source implementation – that is what we ended up building with s2-lite! https://news.ycombinator.com/item?id=42487592

And it has the durability of object storage rather than just local. SlateDB actually lets you also use local FS, will experiment with plumbing up the full range of options - right now it's just in-memory or S3-compatible bucket.

So I'd try so share as much of the frontend code (e.g. the GRPC and REST handlers) as possible between these.

Right on, this is indeed the case. The OpenAPI spec is also now generated off the REST handlers from s2-lite. We are getting rid of gRPC, s2-lite only supports the REST API (+ gRPC-like session protocol over HTTP/2: https://s2.dev/docs/api/records/overview#s2s-spec)

Jepsen: NATS 2.12.1 7 months ago

It seemed like the kind of Jepsen outcome where folks would be considering alternatives, but yeah maybe it was not appropriate to plug here.

Jepsen: NATS 2.12.1 8 months ago

If you are looking for a serverless alternative to JetStream, check out https://s2.dev

Pros: unlimited streams with the durability of object storage – JetStream can only do a few K topics

Cons: no consumer groups yet, it's on the agenda

Postgres is a way better fit than Kafka if you want a large number of durable streams. But a flexible OLTP database like PG is bound to require more resources and polling loops (not even long poll!) are not a great answer for following live updates.

Plug: If you need granular, durable streams in a serverless context, check out s2.dev

Yes, currently it has its own /fetch endpoint that then makes S3 GET(s) internally. One potential gotcha depending on how you are using it, an exact byte "Range" header is always required so that the request can be mapped to page-aligned byte range requests on the S3 object. But with that constraint, it is feasible to add an S3 shim.

It is also possible to stop requiring the header, but I think it would complicate the design around coalescing reads – the layer above foyer would have to track concurrent requests to the same object.

How we run it:

Auto-scaled Kubernetes deployments, one for each availability zone, currently on m*gd instances which give us local NVMe. The pods are able to easily push GiBps with 1-2 CPUs used — network is the bottleneck so we made it a scaling dimension (thanks KEDA).

On the client side, each gateway process uses kube.rs to watch ready endpoints in the same zone as itself, and frequently polls /stats exposed by Cachey for recent network throughput as a load signal.

To improve hit rates with key affinity, clients use rendezvous hashing for picking a node, with bounded load (https://arxiv.org/abs/1608.01350) – if a node exceeds a predetermined throughput limit, the next choice for the key is picked.

We may move towards consistent hashing – it would be a great problem to have, if we needed so many Cachey pods in a zone that O(n) hashing was meaningful overhead! An advantage with the current approach is it does not suffer from the cascaded overflow problem (https://arxiv.org/abs/1908.08762).