Readyset: A MySQL and Postgres wire-compatible caching layer
github.com
github.com
Be aware that there are hundreds of open issues[0] and dozens of pull requests [1], some of which involve clients being unable to connect or not supporting all components of the SQL language. Just because your database supports something, doesn't mean your caching layer will.
It gets really ugly when a new version of your database comes out, with brand new features and language enhancements, and the caching layer doesn't support it. It may take months, or in some cases years, before the caching layer is feature-complete with the underlying database. If you want to use some of those language enhancements, then your app may have to maintain two connection strings - one for the caching layer, and one for direct database queries that the caching layer doesn't support.
Your support teams need to learn how to diagnose problems with the caching layer. For example, this issue [2] talks about the level of work involved with understanding why newly inserted data isn't showing up in selects.
I hope they succeed and deliver the concept, because it's one of the holy grails of databases.
[0]: https://github.com/readysettech/readyset/issues [1]: https://github.com/readysettech/readyset/pulls [2]: https://github.com/readysettech/readyset/issues/39
This would be more complex if the feature you are using does not return a normal table of results back (e.g. the pub/sub support in Postgres).
As we expand query support, we allow users to cache more and more queries.
A caching layer can do that, and I'd be surprised if serious ones don't. It might not be perfect when moving between DB versions though: the new version might perhaps introduce syntax that is mistaken for something else which the layer _thinks_ it understands. While this can be tested for to a large extent by the devs having access to alph/beta/rc versions, but I can still see things slipping through and you are relying on people keeping their versions of the caching layer as up-to-date as everything else which is not a given.
Because sometimes it's not about the query you pass in - it's about a new data type, for example. The layer may think it understands the query, but may not be able to handle the format of the results, or may cache them incorrectly.
For example, when SQL Server added the JSON data type, one of my customers found that the caching layer mangled it for some clients, but not others, or would return the correct result the first time, but the cached result was formatted incorrectly.
Another problem can be the connection itself, like when SQL Server added support for Always Encrypted, an end-to-end encryption method.
Having said that, the way they work with pull requests is unlike anything else I've seen. I see that they are using a merge bot, but apart from that all branch names are completely illegible. As a lot of the team seems to be present in this thread, it would be interesting to get some details about that.
Our internal Changelists in Gerrit get synced to GitHub as those PRs you are seeing (the branch names correspond to Gerrit change-ids), and any community PRs get copied to our Gerrit first before going through CI and then being merged and synced with GitHub.
But, what I'd worry about are situations where an application needs to cache an object that's expensive to build. (And perhaps expensive to build because the programmer doesn't understand how to optimize SQL.)
Readyset is basically reimplementing a full database, at the absolute bleeding edge of db research, enabling global partial replication of any kind of data.
A solution desperately needed, as databases grow.
You can think of it as an intelligent LRU cache in front of your database. An important step towards fast globally distributed applications.
I hope this project will get more publicity and adoption - it's very well deserved.
edit: Here's[1] a video where he talks about the concept
[0]: https://www.youtube.com/@jonhoo [1]: https://www.youtube.com/watch?v=GctxvSPIfr8
I really love this space and have been impressed with Materialize, but even if you can make some intermediate state incremental, if your workload is largely dynamic you end up needing to jump the whole way to OLAP platforms. I’m hopeful that we’re closer and closer to having our cake and eating it here, and that the operational data warehouse is only round the corner.
Given that Readyset was co-founded by Jon Gjengset (but has apparently since departed the company), who authored the paper on Noria[1], I would assume that Readyset is the continuation of that research. I wouldn't call that "just" incremental view maintenance, as it's a lot more involved than the simplest implementation of IVM (though obviously that is the end-goal).
So it shares some roots with Materialize. They have a common conceptual ancestry in Naiad, where Materialize evolved out of timely-dataflow.
[0]: https://docs.readyset.io/concepts/streaming-dataflow
[1]: https://jon.thesquareplanet.com/papers/osdi18-noria.pdf
(It turns into Nokia results part way through page 2, but still a lot of submissions!)
Different where clauses (sets of parameters) would map to different query-caches and currently need to be cached separately.
Aggregates supported by Readyset[1] will also be automatically maintained, but depending on the query, they may be handled by post-processing after retrieving results from a cache
[1] https://docs.readyset.io/reference/features/queries#aggregat...
Concurrency. ClickHouse works best with a relatively small number of concurrent queries: hundreds to low thousands, not 10s of thousands or more. That allows each query to hog more resources and get done quickly.
Imagine a legacy system that has a method that dynamically query-builds a massive query based on several method parameters (say 10 or 20), this method is used in two dozen places or more. The underlying tables are used in a million other places. Rewriting the query building method or, even worse, changing the underlying data model, would be expensive.
Now imagine that you could speed up some of these queries WITHOUT changing your code or model or rolling your own cache solution (the invalidation of which is always a real PITA). All this basically for free.
I don't think "why a developer would adopt something like this over a database like Clickhouse" is the right take. They do not compete. It's not about "adopting a database", that decision has been typically made a long time ago in a galaxy far far away and by someone else than you. Of course unless you work on green field projects or small enough projects that "adopting a different database" is even a question. I'd love some of that stuff :) ... one of the biggest systems I worked on for several years had close to 700 mysql tables (yea, not colums, tables), basically anything that was anywhere near the core of the system took ages to change and test. I can't possibly imagine the investment it would require to move that system from mysql to something else while not making a billion bugs along the way. I could imagine using something like Readyset, especially if it handles cache invalidation for you based on underlying model data changes.
The key difference is that Noira/ReadySet supports partial materialization and can reconstruct data on-demand, whereas Naiad/Differential Dataflow/Materialize must keep a complete materialization up to date. ReadySet can partially evict parts of the data flow and bring them back later if needed.
In practical terms if you have a materialized view you want to maintain, in ReadySet you pay O(part of the materialized data flow you actually need), which is less than O(entire materialized view) you’d pay with Materialize.
Partial materialization is indeed Noria's major contribution to dataflow technology, and it's impressive stuff. But I want to call out that there are a number of techniques that folks use with Materialize to avoid paying for O(entire materialized view). The two most common techniques are demand-driven queries using lateral joins [0] and temporal filters [1]. Noria's approach to partial materialization is automatic but gives the user less explicit control; Materialize's approach is manual, but gives the user more explicit control.
The other major divergence between Materialize and Noria is around consistency. Noria is eventually consistent, while Materialize is strongly consistent. There is a caveat to Materialize's consistency guarantees today: we don't offer strong consistency across your upstream {Kafka, PostgreSQL, MySQL} and Materialize. You only get strong consistency within Materialize itself. But we've got an improvement for that in the works that'll be rolling out in the next few months.
[0]: https://materialize.com/blog/lateral-joins-and-demand-driven...
[1]: https://materialize.com/docs/transform-data/patterns/tempora...
The one thing it can’t handle however is range update queries or native queries that perform updates.
You can just avoid them in your architecture… OR maybe this is the solution we’ve been looking we’ve been looking for! definitely going to give this a spin!
Documentation looks very complete and I like there’s a UI to view the query cache.
If I have a front end, I would hope that the formated response is what were caching. Be that HTML or JSON.
If I cant read from that cache then I should be reading from fresh data all together? right?
After an initial query seen by their proxy, you can configure all future queries of the same kind to be pre-computed.
So I think it makes more sense to think of it like an auto-updating materialized view available with the click of a button rather than a cache.
There are some more under-the hood details here: https://docs.readyset.io/concepts/overview#how-does-readyset...
Efective Cache: Request -> (less)work -> cache
This Product: Request -> work -> work.. -> query/cache
I understand the concept of caching at a boundary layer. I fail to see the point of cache at THIS boundary layer. You have all the problems of a cache with fewer benefits (you're not going to fix a thundering Hurd at this level).
No you don't. You have next to none of the problems of a cache (especially as you directly have to opt-in individual queries to it) like cache invalidation, etc., with all the benefits. It's about as free as performance benefits can be (from a implementations standpoint).
I understand that for many use-cases caching at the response level may be preferable, but there are also many use-cases that are read-heavy but also involve a lot of computed values that are updated and have to be recomputed regularly, where this dataflow-based approach has been shown to be one of the least compute intensive and efficient solutions.
Yes after all the data + work/compute
>> there are also many use-cases that are read-heavy but also involve a lot of computed values that are updated and have to be recomputed regularly, where this dataflow-based approach has been shown to be one of the least compute intensive and efficient solutions.
From a comp sci, from a programing, from an engineering perspective I get this. But at the end of the day those are just the hammers and nails of the business. I am wondering where the actual, in production use case, with business need requires this. I can think of a dozen technical fuck ups where this solution is appealing but that's just stacking irresponsibly...
It (Redis/Memcache caching) adds a huge amount of complexity to your application, and the risk of defects is very, very real.
ReadySet basically gives you a magic "stick this thing between your database and application and we'll do the caching for you." It totally eliminates a time consuming and error-prone part of your application.
If you want to, they go into details here: https://blog.readyset.io/dont-use-kv-stores/
If it was possible to just slap a cache in between you and the db and magically make shit fast, DB vendors would have done that 20 years ago. Billions of dollars a year is put into relational db development. Papers are published every week, from theoretical ways to model and interact with data to practical things like optimizing query execution plans.
Unless Readyset can point to a patent or a paper that has fundamentally revolutionized how database will be built from today forward it is going to be crap and will burn you.
Once we used a distributed caching system in a startup which was open source. Then the open source version got cut features we needed, so we bought a license. Then the startup was bought up by a large software company and the license costs went 10x YoY with a one week notice. As our migration away from this tech was not done, because it was very complicated and tied into our application we had to pay. Luckily we also had been bought and the very large costs were not a problem. I would never again use something from a company that is crucial to our operations.
A read-replica doesn't give you perfect transactional guarantees as well. Read operations to the replica after a write operation to the leader might still give you stale data (lagging by a few milliseconds).
[1]: https://planetscale.com/blog/how-planetscale-boost-serves-yo...
> It will be interesting to see if any of these introduce some form of write support over time
Writes performed by your application in Readyset are automatically proxied(redirected) to your database.
The advantages is that reading from a cache will be faster than from a read replicas. The benefits increase even further if you have to perform computation on the fetched data.
What does this mean?
Most commonly the restrictions prevent you from launching a competing offering. In their case, you can't offer database-as-a-service using their code.
BSL typically also restricts production use - though it looks like ReadySet has relaxed that restriction.
Finally, BSL reverts to a traditional open source license after a set period of time - in their case Apache 2 after 4 years. This means that code written today is licensed under BSL for 4 years, then automatically reverts to Apahce 2 thereafter.
In practice I would count on either using software in compliance with BSL restrictions (which are generous) or seek commercial license