Optimize SCAN with MATCH when pattern implies cluster slot#12536
Optimize SCAN with MATCH when pattern implies cluster slot#12536madolson merged 3 commits intoredis:unstablefrom
Conversation
hpatro
left a comment
There was a problem hiding this comment.
Nice optimization.
There has been some new changes with dbScan method being introduced. For this optimization, we need to invoke addSlotIdToCursor prior to the dbScan call in scanGenericCommand.
#11695 is greenlit for merge, we can do a rebase/merge after it's in. 👍
Thanks for the advice! It makes it easier to update this.
Yes, I saw that! Finally! Yes, I'll update this PR when it is merged change the target to unstable. |
|
@zuiderkwast Yeah, just coming here to say it's merged now so please update. |
ef85b6e to
e11f487
Compare
Done. Consider this ready for review. (I won't force push again.) |
|
@madolson Could you please help close this out? |
|
Sure, will take a look tomorrow. |
|
@zuiderkwast Do you think we should document this optimization in the SCAN command? Part of me thinks we shouldn't, I'm not sure how much I want people to be relying on it. |
|
I'm not sure if this optimization is the right direction. It implicitly narrows down the scan range from the entire database to a specific slot, which seems to introduce a special syntax: using a hashtag in the pattern to specify a slot. However, we have never officially declared or documented this usage, which can lead to confusion and abuse. Additionally, we have encountered some interesting cases that are similar to the optimization in this PR. Inappropriate optimizations can sometimes backfire and have unintended consequences. There was a user who used Now looking at the optimization for SCAN in this PR, it is very similar to the optimization for KEYS mentioned earlier. I believe there is a relatively high potential risk (the performance difference between cluster mode and standalone mode results in different iterations required to scan the same pattern). If a user really wants to specify a slot for scanning, it would be better to provide a dedicated command for slot scanning rather than using such a implicit approach. I think it might be appropriate to revert this commit until we reach a consensus on the resolution for #2702. Also ping @oranagra @yossigo |
|
@madolson It's a good question, but yes, I think we should document it. Hash tags is the abstraction we want the end users to rely on, when they need to use multi-key commands or transactions with multiple related keys. We don't want them to be aware of the slot number of the key (except possibly advanced users and client developers), that seems to be the conclusion of #2702. So we provide a way to iterate efficiently over these related keys too using the same abstraction. In the docs, we already tell them use keys like The cluster docs about hash tags
@soloestoy That's an interesting point about |
|
@zuiderkwast This is not just a performance issue, my main concern is with the syntax: if a pattern contains a hashtag, it will be parsed and mapped to a slot. However, this is not a good practice, as the pattern is not a key and it does not trigger a "-MOVED" redirection in the cluster protocol. This special usage in |
|
First, I don't think the KEYS example is related. There, it was a complete (and silly) misuse of KEYS. And here it is a valid use of SCAN. I think this optimization will also work quite nicely with cluster routing (even if MOVED isn't handled), i.e. the client will SCAN all the nodes, and all but one will return very quickly. Of course, it doesn't support keys being moved during the scan, but that isn't/ wasn't supported anyway. I think it is ok to document this. |
|
Then how should these commands and usages be handled:
|
|
for KEYS, we can implement a similar optimization (again reducing the complexity from O(n) to a slightly smaller O(n).) |
Some of our users have requested this feature, and if we consider using a hashtag in patterns as standard syntax, we would be happy to implement it. Please go ahead @CharlesChen888 |
If KEYS also supports pattern-to-slot mapping, it is highly likely to trigger the issues I mentioned earlier. The time complexity of KEYS remains O(n), but the meaning of "n" has changed:
However, compared to the total number of keys, it is difficult for users to have control over the number of keys in a slot. Different slots in the same Redis instance may have varying numbers of keys, and if the difference is significant, it can lead to significant differences in performance. There is a case that can easily cause a significant performance difference: KEYS {tag}*. If the slot is on the current node, it will traverse that slot. If the slot is not on the current node, there is no need to traverse it. This means that the time complexity changes from O(n) to O(1). And it is also not possible to perform the MOVE reply, this introduces a great deal of instability to the smooth operation of the business. |
i think that argument is about also, i'd argue that when a client executes |
|
If that's the case, using hashtags in patterns would need to be defined as a standard practice in the cluster protocol. We would need detailed documentation to explain its correct usage (it would be especially challenging to explain to users in cases like the one I encountered with KEYS), the documentation should aim to cover all affected commands and provide guidance on constructing patterns correctly, such as ensuring that the hashtag is placed as a prefix before the wildcard. Additionally, since we allow the use of hashtags in patterns, I think we should also confirm whether slot redirection (-MOVED) is necessary before executing the command. This can help avoid ineffective execution of commands on nodes that do not hold the specified slot. |
|
@yossigo please comment |
|
Well, I wasn't expecting this to be so contentious 🐙. I'm inclined to say we should just document it as an optimization, but you really shouldn't be using
I don't think there is any way to do this without asking clients to do work and introducing a new concept for hashable pattern. I'm not materially against it, we discussed something similar for |
|
In retrospect, I don't know how useful this actually is. If you have a bunch of keys linked to a user, The more relevant use case for cluster SCAN is rather the one with SCAN guarantees over the whole cluster in the precence of migrations, discussed in #2702. |
In many cases, the data stored under a user might be more denormalized than this though. They might do something |
…lies slot. (#12728) The by/get options of sort/sort_ro command used to be forbidden in cluster mode, since we are not sure which slot the pattern may be in. As the optimization done in #12536, patterns now can be mapped to slots, we should allow by/get options in cluster mode when the pattern maps to the same slot as the key.
Adding to the cluster spec documentation of the following Redis features: redis/redis#12754 (SCAN) redis/redis#12536 (KEYS) redis/redis#12728 (SORT, SORT_RO)
This is the optimization part of #2702. No API changes, just optimization.