HN user

Sirupsen

1,121 karma

https://sirupsen.com

co-founder of https://turbopuffer.com

Posts26
Comments72
View on HN
turbopuffer.com 4mo ago

Rust zero-cost abstractions vs. SIMD

Sirupsen
24pts4
strn.cat 4mo ago

SpacetimeDB: A Short Technical Review

Sirupsen
9pts0
turbopuffer.com 5mo ago

A distributed queue in a single JSON file on object storage

Sirupsen
171pts55
turbopuffer.com 7mo ago

Vectorized MAXSCORE over WAND, especially for long LLM-generated queries

Sirupsen
4pts0
aws.amazon.com 1y ago

Amazon S3 Adds Put-If-Match (Compare-and-Swap)

Sirupsen
524pts160
turbopuffer.com 2y ago

Turbopuffer: Fast search on object storage

Sirupsen
379pts64
sirupsen.com 3y ago

Index Merges vs. Composite Indexes in Postgres and MySQL

Sirupsen
175pts38
sirupsen.com 5y ago

Is max MySQL transactions per second = max fsyncs per second?

Sirupsen
10pts1
sirupsen.com 6y ago

Is max MySQL transactions per second = max fsyncs per second?

Sirupsen
3pts0
sirupsen.com 6y ago

Adjacent Possible: Model for Peeking into the Future

Sirupsen
1pts0
github.com 9y ago

What happens to webserver capacity when browsers refresh fast?

Sirupsen
1pts0
sirupsen.com 10y ago

Shopify's Employees Only Podcast

Sirupsen
1pts0
bouk.co 11y ago

Monkey Patching in Go

Sirupsen
82pts22
www.youtube.com 11y ago

Docker at Shopify: From This-Looks-Fun to Production

Sirupsen
3pts0
github.com 12y ago

Github Walrus Emoji

Sirupsen
21pts9
charlie.bz 13y ago

Recovering from segfaults in Ruby

Sirupsen
3pts1
www.kickstarter.com 13y ago

Kickstarter: Forced, Diablo III meets Left 4 dead

Sirupsen
2pts1
www.ioi2012.org 13y ago

Tasks for the 24th International Olympiad in Informatics held this week in Italy

Sirupsen
3pts0
sirupsen.com 15y ago

Paperless with Evernote

Sirupsen
18pts1
sirupsen.com 15y ago

Stop relying on your ORM and learn SQL

Sirupsen
13pts4
sirupsen.com 15y ago

Get started right with RVM

Sirupsen
69pts21
sirupsen.com 16y ago

The switch to Github Pages

Sirupsen
3pts0
blog.sirupsen.dk 16y ago

A simple Imgur Bash screenshot utility

Sirupsen
2pts0
blog.sirupsen.dk 16y ago

What I wish a Ruby programmer had told me one year ago..

Sirupsen
63pts62
www.reddit.com 16y ago

Steam for linux testapp thingy

Sirupsen
20pts4
blog.sirupsen.dk 16y ago

Create your first Ruby Gem and release it to Gemcutter

Sirupsen
5pts0

(cofounder of tpuf here)

We don't have a relational database, otherwise that would work great for a queue! You can imagine us continuing to iterate here to Step 5, Step 6, ... Step N over time. The tradeoff of each step is complexity, and complexity has to be deserved. This is working exceptionally well currently.

Scaling HNSWs 8 months ago

Our query planner has that built in! We've spent a lot of time making high recall with any selectivity in the fitler work.

The short of it is that building a database on top of object storage has generally required a complicated, distributed system for consensus/metadata. CAS makes it possible to build these big data systems without any other dependencies. This is a win for simplicity and reliability.

tpuf’s ANN index uses a variant of SPFresh, yup. These are the only two production implementations I am aware of. I don’t think it is in production at MSFT yet

Yeah, thinking about this more I now understand Clickhouse to be more of an operational warehouse similar to Materialize, Pinot, Druid, etc. if I understand correctly? So bunching with BigQuery/Snowflake/Trino/Databricks... wasn't the right category (although operational warehouses certainly can have a ton of overlap)

I left that category out for simplicity (plenty of others that didn't make it into the taxonomy, e.g. queues, nosql, time-series, graph, embedded, ..)

Most production storage systems/databases built on top of S3 spend a significant amount of effort building an SSD/memory caching tier to make them performant enough for production (e.g. on top of RocksDB). But it's not easy to keep it in sync with blob...

Even with the cache, the cold query latency lower-bound to S3 is subject to ~50ms roundtrips [0]. To build a performant system, you have to tightly control roundtrips. S3 Express changes that equation dramatically, as S3 Express approaches HDD random read speeds (single-digit ms), so we can build production systems that don't need an SSD cache—just the zero-copy, deserialized in-memory cache.

Many systems will probably continue to have an SSD cache (~100 us random reads), but now MVPs can be built without it, and cold query latency goes down dramatically. That's a big deal

We're currently building a vector database on top of object storage, so this is extremely timely for us... I hope GCS ships this ASAP. [1]

[0] https://github.com/sirupsen/napkin-math [1]: https://turbopuffer.com/

Ideally, I would add three graphs to the post:

(1) Table size on the x-axis, and time on the y-axis for index merge vs composite index

(2) Number of columns on the x-axis, and time on the y-axis for both

(3) Number of final matches on the x-axis, and time on the y-axis for both

But ran out of time and decided to test with the table size of 10M rows, and a 100-ish result set. That's in my experience a decent representation for what you might be doing with a relational database.

I've added this to the article, thanks!

Composite index (int64, int64): ~70 MiB in Postgres, ~350 MiB in MySQL

Single index (int64): ~70 MiB in Postgres, ~240 MiB in MySQL

If you assume the majority of an index are index entries of (int64, int64, int64) where the third number is some sort of identifier for the record on the heap, you'd expect this to be ~230 MiB. So Postgres does some compression very well here, and MySQL has a bit more overhead for its indexes it seems.

You might be very right about that! It's been a while since I did the SSD benchmarks. Glad to hear it's most likely entirely accurate at 4 GiB/s then!

`madvise(2)` doesn't matter _that_ much in my experience with [1] on modern Linux kernels. SSD just can't read _quite_ as quickly as memory in my testing. Sure, SSD will be able to re-read a lot into ram, analogous to how memory reading will be able to rapidly prefetch into L1.

I get ~30 GiB/s for threaded sequential memory reads, but ~4 GiB/s for SSD. However, I think the SSD number is single-threaded and not even with io_uring—so I need to regenerate those numbers. It's possible it could be 2-4x better.

[1] https://github.com/sirupsen/napkin-math

Yes, sequential I/O bandwidth is closing the gap to memory. [1] The I/O pattern to watch out for, and the biggest reason why e.g. databases do careful caching to memory, is that _random_ I/O is still dreadfully slow. I/O bandwidth is brilliant, but latency is still disappointing compared to memory. Not to mention, in typical Cloud workloads, IOPS are far more expensive than memory.

[1] https://github.com/sirupsen/napkin-math

We spent a fair amount of time trying to get this executing fast on SQL. However, with spreadsheets you recursively compute a lot of values. You can do this in SQL with recursive CTEs, but it’s slow, they’re not optimized for this. They also of course won’t do smart caching and dependency management for the cache. Fundamentally, it’s possible, but then we’d need to start hacking on a DB engine to make it work as a sheet. We concluded it’s better to continue on our existing engine.

Yes, I didn't mean to imply we wouldn't go far to squeeze Go further! At some point the downside of the complexity of dropping down from Go to intrinsics, bypassing the GC, etc. might overwhelm the benefits of staying with Go. We've spent a while writing simulations like the ones in the post to understand Go's GC's behaviour under lots of pressure, and it won't be a bottleneck for a long time. I also think that doing all the pre-requisite work to make SIMD remotely possibly will yield _far_ more performance than SIMD itself.

Great question. The biggest reason is that Go was what the team was most familiar with when the engine moved from Javascript. The reason today is that the engine is 40K LOC of Go, so a full-blown rewrite would be a big deal. As the post goes into depth with, we have a lot of rope left before we need to get to SIMD/GPGPU. Once we hit those computational bottlenecks in Go, we're very open to changing our mind!

There is plans to support pretty much every database. The reason it’s not supported currently is because its md5 hashing is too slow, so we need to do something different for it, e.g. just sum for types that support it. It’s similar for databases we plan to support that don’t support MD5 too, for example ElasticSearch.

If anyone knows a dev on the MSSQL team we could speak to, we’d be eager to be connected

See https://github.com/datafold/data-diff/issues/51

I'm not completely sure I understand your comment, so pardon me if I misunderstand. I don't think a foreign data wrapper would fundamentally to be more efficient with whatever table is ~foreign~, especially for an OUTER JOIN? Unless you're basically implementing something similar to data-diff with an OUTER JOIN with FDW, which seems possible

If you're doing in-database diffs, however, a join-based approach will likely outperform data-diff though.

Ideally databases would have support a standard MERKLE TREE INDEX so we could get extremely fast comparisons.

(1) You can specify `--min-age` to exclude records in the replication lag window

(2) We can do that, as long as they have the same name and compatible-ish types. There isn't support for differently named columns yet (but it's on the list)

Cheers. Open an issue if you run into trouble!