https://github.com/DiceDB/dice/blob/0e241a9ca253f17b4d364cdf... defines func ExpandID, which reads from cycleMap without locking the package-global mutex; and func NextID, which writes to cycleMap under a lock of the package-global mutex. So writes are synchronized, but only between each other, and not with reads, so concurrent calls to ExpandID and NextID would race.
This is all fine as a hobby project or whatever, but very far from any kind of production-capable system.
This PR attempted to fix the memory model violation I mentioned in the parent comment, but also added in an extra change that swapped the sync.Mutex to a sync.RWMutex. The PR description claimed 2 benefits: "Eliminates the data race, ensuring thread safety" -- correct! at least to some level; but also "Improves performance by allowing concurrent ExpandID calls, which is likely a common operation" -- which is totally unsubstantiated, and very likely false, as RWMutex is only faster than a regular Mutex under very narrowly-defined load patterns.
In any case, the PR had no kind of test or benchmark to validate either of these claims, so not a great start by the author. But then a maintainer chimed in with a comment that expressed concerns about edge-condition performance details, without any kind of data or evidence, and apparently didn't care about (or know about?) the much more important fixes that the PR made re: data races.
> I tried changing this, but I did not see any benefit in benchmark numbers.
No apparent understanding of the bugs in this code, nor how changes may or may not fix those bugs, nor really how performance is defined or can be meaningfully evaluated.
Again, hobby project or whatever, all good. But the authors and maintainers of this project are clearly, demonstrably, in over their heads on this one.
Looking at the diceDB code base, I have few questions regarding its design, I'm asking this to understand the project's goals and design rationale. Anyone feel free to help me understand this.
I could be wrong but the primary in-memory storage appears to be a standard Go map with locking. Is this a temporary choice for iterative development, and is there a longer-term plan to adopt a more optimized or custom data structure ?
I find the DiceDB's reactivity mechanism very intriguing, particularly the "re-execution" of the entire watch command (i.e re-running GET.WATCH mykey on key modification), it's an intriguing design choice.
From what I understand is the Eval func executes client side commands this seem to be laying foundation for more complex watch command that can be evaluated before sending notifications to clients.
But I have the following question.
What is the primary motivation behind re-executing the entire command, as opposed to simply notifying clients of a key change (as in Redis Pub/Sub or streams)? Is the intent to simplify client-side logic by handling complex key dependencies on the server?
Given that re-execution seems computationally expensive, especially with multiple watchers or more complex (hypothetical) watch commands, how are potential performance bottlenecks addressed?
How does this "re-execution" approach compare in terms of scalability and consistency to more established methods like server-side logic (e.g., Lua scripts in Redis) or change data capture (CDC) ?
Are there plans to support more complex watch commands beyond GET.WATCH (e.g. JSON.GET.WATCH), and how would re-execution scale in those cases?
I'm curious about the trade-offs considered in choosing this design and how it aligns with the project's overall goals. Any insights into these design decisions would help me understand its use-cases.
I was hoping for a response, but no one bothered. I had noted the following when I made that comment and will just wrap up from my end so this could be used by others for reference later.
I'm skeptical that the re-execution approach can scale for complex queries, the latency and throughput improvements would be offseted by the computational cost and bottlenecks introduced for achieving it via its reactivity mechanism (query subscription), this might not work at scale and serve niche use cases.
There are various ways throughput and latency for kv stores can be improved, so bar is really high here.
The messaging with Dice seems unclear and confusing to describe its purpose/use-cases over alternatives, or how it achieves them, which could just be how it's marketed. But it seems to be a collection of ideas and a WIP project.
I think reducing data fetching complexity and complex key dependencies for end clients could be appealing, and it would be great to have it at the KV store level, but there is no reason this type of reactivity can't be implemented on top of various clients for existing KV stores (like Redis). And basic WATCH with transactions are even offered out of the box in them.
Deno kv seem nice but its vendor locked, also there are many others like dragonfly, valkey etc, redis could still work, even something over sqlite can work, deno has a selfhosted kv on top of sqlite - https://github.com/denoland/denokv
From that and the thread so far it seems, they want to make some super cache by building a realtime multi-threaded kv store, improving latency and reducing its read load via its reactivity mechanism. Solving the problem of cache invalidation.
Not sure how this will be achieved but there is no harm in trying. From what is said and shared, rationale behind this design and its tradeoffs are not clear, code could be fixed/improved but providing clarity on this is essential for adoption.
I've seen this more and more with software landing pages, they are somehow so deep into developing/marketing that they totally forget to say what the thing actually is or does, that's why you show it to family and friends first to get some fresh eyes before publishing the site.
Looks like a Redis clone. The benchmarks compare it to Redis.
Description from GitHub:
> DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware. Commonly used as a cache, it offers a familiar interface while enabling real-time data updates through query subscriptions. It delivers higher throughput and lower median latencies, making it ideal for modern workloads.
DiceDB is an in-memory database that is also reactive. So, instead of polling the database for changes, the database pushes the resultset if you subscribe to it.
We have a similar set of commands as Redis, but are not Redis-compliant.
Even clicking through to the Github, after reading the "What is DiceDB?", I'm still not very clear. It feels more like marketing than information.
"What is DiceDB?
DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware. Commonly used as a cache, it offers a familiar interface while enabling real-time data updates through query subscriptions. It delivers higher throughput and lower median latencies, making it ideal for modern workloads."
From the benchmarks on 4vCPU and num_clients=4, the numbers doesn't look much different.
Reactive looks promising, doesn't look much useful in realworld for a cache.
For example, a client subscribes for something and the machines goes down, what happens to reactivity?
UPD Nevermind, I didn't have my eyes open. Sorry for the confusion.
Something I still fail to understand is where you can actually spend 20ms while answering a GET request in a RAM keyvalue storage (unless you implement it in Java).
I never gained much experience with existing opensource implementations, but when I was building proprietary solutions at my previous workplace, the in-memory response time was measured in tens-hundreds of microseconds. The lower bound of latency is mostly defined by syscalls so using io_uring should in theory result in even better timings, even though I never got to try it in production.
If you read from nvme AND also do the erasure-recovery across 6 nodes (lrc-12-2-2) then yes, you got into tens of milliseconds. But seeing these numbers for a single node RAM DB just doesn't make sense and I'm surprised everyone treats them as normal.
Does anyone has experience with low-latency high-throughput opensource keyvalue storages? Any specific implementation to recommend?
I had the same reaction as you. And that's for 4 simultaneous clients, too, for a single client you get 3159 ops/s (from https://dicedb.io/benchmarks/). I'm not too familiar with in-memory databases in general but I would have expected figures in the millions on modern hardware. Makes me feel there's some hidden bottleneck somewhere and the benchmarks are not purely measuring the performance of the software.
In-memory caches (lacking persistence) shouldn't be called a database. It's not totally incorrect, but it's an abuse of terminology. Why is a Python dictionary not an in-memory key-value database?
I didn't see it in the docs, but I'd want to know the delivery semantics of the pubsub before using this in production. I assume best effort / at most once? Any retries? In what scenarios will the messages be delivered or fail to be delivered?
Different tool. I metrics I am optimizing for are different hence wrote a separate utility. May not be the most optimized one. But I am usign this to measure all things DiceDB and will be using this to optimize DiceDB further.
What are some example use cases where having the ability for the database to push updates to an application would be helpful (vs. the traditional polling approach)?
One example is when you want to display live data on a website. Could be a dashboard, a chat, or really the whole site. Polling is both slower and more resource hungry.
If it is built into your language/framework, you can completely ignore the problem of updating the client, as it happens automatically.
15655 ops a second with a Hetzner CCX23 machine with 4 vCPU and 16GB RAM is rather slow for an in-memory database I hate to say it. You can't blame that on network latency as for example supermassivedb.com is written in go and achieves magnitudes more, actually x20 and it's persisted.. I must investigate the bottlenecks with Dice.
I love the "Follow on twitter" link with the old logo and everything, they probably used a template that hasn't been updated recently but I'm choosing to believe it's actually a subtle sign of protest or resistance.
Snapshot functionality is WIP, which can be utilised to persist and replay data between reboots.
For now Golang SDK is only one, more SDKs are to be added soon.
Based on this thread, I'm not sure you would want to use this over keyspace notifications, but I will also say that there comes a point in the maturity of a system when keyspace notifications become a complicated, unreliable, resource-heavy nightmare. They work fine is your needs and scale are limited, but it's definitely not what you want if handling lots of frequent chances across craploads of keys, with complicated logic for who needs them and how they get routed to them, and where it matters if the notification is successfully received.
But certainly you could build something to handle these and most other needs in this realm with mostly just redis, using streams for what needs to be more robust, in tandem with pub/sub, keyspace notifs, etc. in the areas they are suited to.
The benchmark tool is different. I mentioned the same on my benchmark page.
We had to write a small benchmark utility (membench) ourselves because the long-term metrics that we are optimizing need to be evaluated in a different way.
Also, the scripts, utilities, and infra configurations are mentioned. Feel free to run it.
kiitos|11 months ago
One example among many:
https://github.com/DiceDB/dice/blob/0e241a9ca253f17b4d364cdf... defines func ExpandID, which reads from cycleMap without locking the package-global mutex; and func NextID, which writes to cycleMap under a lock of the package-global mutex. So writes are synchronized, but only between each other, and not with reads, so concurrent calls to ExpandID and NextID would race.
This is all fine as a hobby project or whatever, but very far from any kind of production-capable system.
kiitos|11 months ago
This PR attempted to fix the memory model violation I mentioned in the parent comment, but also added in an extra change that swapped the sync.Mutex to a sync.RWMutex. The PR description claimed 2 benefits: "Eliminates the data race, ensuring thread safety" -- correct! at least to some level; but also "Improves performance by allowing concurrent ExpandID calls, which is likely a common operation" -- which is totally unsubstantiated, and very likely false, as RWMutex is only faster than a regular Mutex under very narrowly-defined load patterns.
In any case, the PR had no kind of test or benchmark to validate either of these claims, so not a great start by the author. But then a maintainer chimed in with a comment that expressed concerns about edge-condition performance details, without any kind of data or evidence, and apparently didn't care about (or know about?) the much more important fixes that the PR made re: data races.
https://github.com/DiceDB/dice/pull/1588#issuecomment-274521...
> I tried changing this, but I did not see any benefit in benchmark numbers.
No apparent understanding of the bugs in this code, nor how changes may or may not fix those bugs, nor really how performance is defined or can be meaningfully evaluated.
Again, hobby project or whatever, all good. But the authors and maintainers of this project are clearly, demonstrably, in over their heads on this one.
senderista|11 months ago
deazy|11 months ago
I could be wrong but the primary in-memory storage appears to be a standard Go map with locking. Is this a temporary choice for iterative development, and is there a longer-term plan to adopt a more optimized or custom data structure ?
I find the DiceDB's reactivity mechanism very intriguing, particularly the "re-execution" of the entire watch command (i.e re-running GET.WATCH mykey on key modification), it's an intriguing design choice.
From what I understand is the Eval func executes client side commands this seem to be laying foundation for more complex watch command that can be evaluated before sending notifications to clients.
But I have the following question.
What is the primary motivation behind re-executing the entire command, as opposed to simply notifying clients of a key change (as in Redis Pub/Sub or streams)? Is the intent to simplify client-side logic by handling complex key dependencies on the server?
Given that re-execution seems computationally expensive, especially with multiple watchers or more complex (hypothetical) watch commands, how are potential performance bottlenecks addressed?
How does this "re-execution" approach compare in terms of scalability and consistency to more established methods like server-side logic (e.g., Lua scripts in Redis) or change data capture (CDC) ?
Are there plans to support more complex watch commands beyond GET.WATCH (e.g. JSON.GET.WATCH), and how would re-execution scale in those cases?
I'm curious about the trade-offs considered in choosing this design and how it aligns with the project's overall goals. Any insights into these design decisions would help me understand its use-cases.
Thanks
deazy|11 months ago
I'm skeptical that the re-execution approach can scale for complex queries, the latency and throughput improvements would be offseted by the computational cost and bottlenecks introduced for achieving it via its reactivity mechanism (query subscription), this might not work at scale and serve niche use cases.
There are various ways throughput and latency for kv stores can be improved, so bar is really high here.
The messaging with Dice seems unclear and confusing to describe its purpose/use-cases over alternatives, or how it achieves them, which could just be how it's marketed. But it seems to be a collection of ideas and a WIP project.
I think reducing data fetching complexity and complex key dependencies for end clients could be appealing, and it would be great to have it at the KV store level, but there is no reason this type of reactivity can't be implemented on top of various clients for existing KV stores (like Redis). And basic WATCH with transactions are even offered out of the box in them.
Deno kv seem nice but its vendor locked, also there are many others like dragonfly, valkey etc, redis could still work, even something over sqlite can work, deno has a selfhosted kv on top of sqlite - https://github.com/denoland/denokv
Also with dice its creator had made this talk
https://hasgeek.com/rootconf/2024/sub/how-we-made-dicedb-a-t...
From that and the thread so far it seems, they want to make some super cache by building a realtime multi-threaded kv store, improving latency and reducing its read load via its reactivity mechanism. Solving the problem of cache invalidation.
Not sure how this will be achieved but there is no harm in trying. From what is said and shared, rationale behind this design and its tradeoffs are not clear, code could be fixed/improved but providing clarity on this is essential for adoption.
bdcravens|11 months ago
DrammBA|11 months ago
johnisgood|11 months ago
Description from GitHub:
> DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware. Commonly used as a cache, it offers a familiar interface while enabling real-time data updates through query subscriptions. It delivers higher throughput and lower median latencies, making it ideal for modern workloads.
arpitbbhayani|11 months ago
DiceDB is an in-memory database that is also reactive. So, instead of polling the database for changes, the database pushes the resultset if you subscribe to it.
We have a similar set of commands as Redis, but are not Redis-compliant.
lucianbr|11 months ago
Feels arrogant. "Of course you already know what this is, how could you not?"
rvnx|11 months ago
bdcravens|11 months ago
"What is DiceDB? DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware. Commonly used as a cache, it offers a familiar interface while enabling real-time data updates through query subscriptions. It delivers higher throughput and lower median latencies, making it ideal for modern workloads."
remram|11 months ago
> DiceDB is an open-source, fast, reactive, in-memory database optimized for modern hardware.
A Redis-like database with a Redis-like interface. No info about drop-in compatibility, I assume no.
unknown|11 months ago
[deleted]
ekianjo|11 months ago
siddharthgoel88|11 months ago
schmookeeg|11 months ago
bufferoverflow|11 months ago
dkh|11 months ago
Kinda refreshing to see someone own it and run with it
cozzyd|11 months ago
BoorishBears|11 months ago
weekendcode|11 months ago
Reactive looks promising, doesn't look much useful in realworld for a cache. For example, a client subscribes for something and the machines goes down, what happens to reactivity?
alexey-salmin|11 months ago
Something I still fail to understand is where you can actually spend 20ms while answering a GET request in a RAM keyvalue storage (unless you implement it in Java).
I never gained much experience with existing opensource implementations, but when I was building proprietary solutions at my previous workplace, the in-memory response time was measured in tens-hundreds of microseconds. The lower bound of latency is mostly defined by syscalls so using io_uring should in theory result in even better timings, even though I never got to try it in production.
If you read from nvme AND also do the erasure-recovery across 6 nodes (lrc-12-2-2) then yes, you got into tens of milliseconds. But seeing these numbers for a single node RAM DB just doesn't make sense and I'm surprised everyone treats them as normal.
Does anyone has experience with low-latency high-throughput opensource keyvalue storages? Any specific implementation to recommend?
davekeck|11 months ago
Aren’t these numbers .2 ms, ie 200 microseconds?
ajnin|11 months ago
esafak|11 months ago
Kerbonut|11 months ago
unknown|11 months ago
[deleted]
unknown|11 months ago
[deleted]
OutOfHere|11 months ago
ac130kz|11 months ago
hp77|11 months ago
losvedir|11 months ago
remram|11 months ago
arpitbbhayani|11 months ago
ref: https://github.com/DiceDB/membench
huntaub|11 months ago
zupa-hu|11 months ago
If it is built into your language/framework, you can completely ignore the problem of updating the client, as it happens automatically.
Hope that makes sense.
alexpadula|11 months ago
rebolek|11 months ago
throwaway2037|11 months ago
Is there a plan to commercialise this product? (Offer commercial support, features, etc.) I could not find anything obvious from the home page.
sidcool|11 months ago
arpitbbhayani|11 months ago
Aeolun|11 months ago
dkh|11 months ago
DrammBA|11 months ago
spiderfarmer|11 months ago
arpitbbhayani|11 months ago
datadeft|11 months ago
weekendcode|11 months ago
re-lre-l|11 months ago
Would be great to disclose details of this one. I'm interested in using what DiceDB achieves higher throughput.
robertlagrant|11 months ago
FYI this is a misspelling of "higher"
nylonstrung|11 months ago
deadbabe|11 months ago
999900000999|11 months ago
Anyway to persist data in case of reboots?
That's the only thing missing here.
Is Go the only SDK ?
lucifercr7|11 months ago
retropragma|11 months ago
dkh|11 months ago
But certainly you could build something to handle these and most other needs in this realm with mostly just redis, using streams for what needs to be more robust, in tandem with pub/sub, keyspace notifs, etc. in the areas they are suited to.
rednafi|11 months ago
spiderfarmer|11 months ago
It’s written in Go.
arpitbbhayani|11 months ago
curtisszmania|11 months ago
[deleted]
cytocync|11 months ago
[deleted]
Clemolomo|11 months ago
[deleted]
theverg|11 months ago
[deleted]
dagss|11 months ago
bitlad|11 months ago
These are the real numbers - https://dzone.com/articles/performance-and-scalability-analy...
Does not match with your benchmarks.
arpitbbhayani|11 months ago
We had to write a small benchmark utility (membench) ourselves because the long-term metrics that we are optimizing need to be evaluated in a different way.
Also, the scripts, utilities, and infra configurations are mentioned. Feel free to run it.