feat: Optimize MGET to GET for single-key partitions #2432
Make sure that:
- [x] You have read the contribution guidelines.
- [x] You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
- [x] You applied code formatting rules using the
mvn formatter:formattarget. Don’t submit any formatting related changes. - [x] You submit test cases (unit or integration tests) that back your changes.
Summary
This pull request resolves issue #2432, which was discussed and marked as status: help-wanted.
When an MGET command is executed in a Redis Cluster environment, the internal logic now checks the number of keys for each slot-based partition. If a partition contains only a single key, this change translates the command to a more lightweight GET instead of MGET.
This optimization reduces unnecessary overhead on both the client and server, improving throughput and lowering latency. This is especially effective in applications where single-key MGET calls occur frequently.
Changes
-
src/main/java/io/lettuce/core/cluster/RedisAdvancedClusterAsyncCommandsImpl.java- Modified
mget(Iterable<K> keys)to check the number of keys per partition. - If a partition contains only one key, it now dispatches a
GETcommand. - If a partition contains multiple keys, it retains the existing behavior of dispatching an
MGETcommand for that partition.
- Modified
-
src/test/java/io/lettuce/core/cluster/commands/StringClusterCommandIntegrationTests.java- Added the
mgetOptimizationintegration test. - This test creates two keys on different slots using hash tags, calls the
mgetmethod, verifies the result, and cleans up the keys afterward.
- Added the
Testing
Using the Redis Cluster environment launched via src/test/resources/docker-env/docker-compose.yml, I have verified the behavior change with the MONITOR command.
Before (Original Code):
The client sends an MGET command for each key, even when there's only one key for the slot.
...$ redis-cli -p 7379 MONITOR
...
1754637572.821032 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "SET" "{slot-a}:test" "value-a"
1754637572.824821 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "SET" "{slot-b}:test" "value-b"
1754637572.833766 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "MGET" "{slot-b}:test"
1754637572.834413 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "MGET" "{slot-a}:test"
1754637572.842009 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "DEL" "{slot-b}:test"
1754637572.842053 [0 [172.18.0.1:59736](http://172.18.0.1:59736/)] "DEL" "{slot-a}:test"
...
After (With this PR):
The client now correctly sends a GET command for each single-key partition.
...$ redis-cli -p 7379 MONITOR
...
1754637500.361643 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "SET" "{slot-a}:test" "value-a"
1754637500.364315 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "SET" "{slot-b}:test" "value-b"
1754637500.367065 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "GET" "{slot-b}:test"
1754637500.367496 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "GET" "{slot-a}:test"
1754637500.371618 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "DEL" "{slot-b}:test"
1754637500.374739 [0 [172.18.0.1:34086](http://172.18.0.1:34086/)] "DEL" "{slot-a}:test"
...
This confirms that the optimization is working as intended.
Thank you for the opportunity to contribute. This is my first pull request to the project, so I'm still getting familiar with the contribution process. I'm more than happy to make any changes and welcome all feedback 🤗
Hi @tishun, I hope you're having a great week.
Since it’s been about a month and a half since I opened this PR, I wanted to kindly check in on its progress.
I understand you are all very busy, but if there's any feedback or changes I can address, please let me know.
I'm happy to rebase it against the main branch to resolve any conflicts if needed.
Thank you for your time and consideration! 😊
Hi @tishun, I hope you're having a great week.
Since it’s been about a month and a half since I opened this PR, I wanted to kindly check in on its progress. I understand you are all very busy, but if there's any feedback or changes I can address, please let me know. I'm happy to
rebaseit against the main branch to resolve any conflicts if needed.Thank you for your time and consideration! 😊
Bump on this. Would be very valuable!