StackExchange / StackExchange.Redis

General purpose redis client
https://stackexchange.github.io/StackExchange.Redis/
Other
5.9k stars 1.51k forks source link

How can I solve CROSSSLOT issue? #1528

Closed sseyalioglu closed 3 years ago

sseyalioglu commented 4 years ago

Sorry, read as much as possible in documentation but unable to figure out.

Here is AWS documentation of the issue resolution in Phyton: https://aws.amazon.com/premiumsupport/knowledge-center/elasticache-crossslot-keys-error-redis/ @mgravell

NickCraver commented 4 years ago

Do you have an example error?

mgravell commented 4 years ago

Cross-slot errors mean you're trying to do a multi-key operation where the keys are not in the same "slot". That is not supported on redis cluster. The fix here is to use "hash tags" for data that always needs to be in the same slot. See https://redis.io/topics/cluster-spec#:~:text=Hash%20tags%20are%20a%20way,different%20way%20in%20certain%20conditions .

On Sat, 15 Aug 2020, 02:10 Nick Craver, notifications@github.com wrote:

Do you have an example error?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/StackExchange/StackExchange.Redis/issues/1528#issuecomment-674326793, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAEHMDJF2ZF7HGOXMRMY5LSAXN6RANCNFSM4OZBUMQQ .

mgravell commented 4 years ago

To be more specific: say you need

/foo/1234/X /foo/1234/Y

To be in the same slot for some cross slot purpose; you could instead use the keys

{/foo/1234}/X {/foo/1234}/Y

The slot is now computed on the value inside the braces, not the entire key, so: they are in the same slot.

On Sat, 15 Aug 2020, 08:43 Marc Gravell, marc.gravell@gmail.com wrote:

Cross-slot errors mean you're trying to do a multi-key operation where the keys are not in the same "slot". That is not supported on redis cluster. The fix here is to use "hash tags" for data that always needs to be in the same slot. See https://redis.io/topics/cluster-spec#:~:text=Hash%20tags%20are%20a%20way,different%20way%20in%20certain%20conditions .

On Sat, 15 Aug 2020, 02:10 Nick Craver, notifications@github.com wrote:

Do you have an example error?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/StackExchange/StackExchange.Redis/issues/1528#issuecomment-674326793, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAEHMDJF2ZF7HGOXMRMY5LSAXN6RANCNFSM4OZBUMQQ .

sseyalioglu commented 4 years ago

so there is no way to do the following: var allItems = await _db.GetAllAsync<T>(activeKeys);

instead we do the following:

foreach (var key in activeKeys)
{
   var item = await _db.GetAsync<T>(key, CommandFlags.PreferReplica);
   allItems.Add(item);
}

_db is IRedisDatabase.

I thought it would be efficient enough to pull from wherever the key is.

mgravell commented 4 years ago

IIRC there is a method to get the slot from a key, so you could GroupBy the slot which means you'd only issue (unique number of slots used) MGET operations. Any use?

On Mon, 24 Aug 2020, 22:03 sseyalioglu, notifications@github.com wrote:

so there is no way to do the following: var allItems = await _db.GetAllAsync(activeKeys);

instead we do the following: foreach (var key in activeKeys) { var item = await _db.GetAsync(key, CommandFlags.PreferReplica); allItems.Add(item); }

_db is IRedisDatabase

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/StackExchange/StackExchange.Redis/issues/1528#issuecomment-679364737, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAEHMH5FGM5MMZRQGCB3ALSCLIQZANCNFSM4OZBUMQQ .

sseyalioglu commented 4 years ago

I have a feeling, it is not a good use because than for every key, I need to find slot anyway and this is same or more cost than the for loop I am doing already. Hashing the keys is also not that good because it feels like putting all eggs to the same basket. I felt like I could have super scaling solutions with so many shards distributed and redis does the magic to pull me the data I need. (also based on our architecture, hash solution is against us, it is not a small amount of keys that is distributed across)

sseyalioglu commented 4 years ago

Thinking again, can you tell me how it is used? Is it like I give begin part of the key and get slots matching?

mgravell commented 4 years ago

No, the API I'm talking about is in-process - no round-trip cost. Not at a PC but will be shortly - will look it up then.

mgravell commented 4 years ago

I'm talking about the method on the multiplexer instance:

public int HashSlot(RedisKey key)

so you could essentially do:

var grouped = activeKeys.GroupBy(key => multiplexer.HashSlot(key));

and work by group.

sseyalioglu commented 3 years ago

Hi, I know I am writing after such a long time but do you have one full implementation for such thing? I got the point but I can't easily see how multiplexer is instantiated. (not knowing the main context of connection multiplexing, but seems like it has something to do with the connection which I don't deal with usually)

sseyalioglu commented 3 years ago

nevermind, got it. I was using StackExchange.Redis.Extensions so multiplexer was not obvious.

NickCraver commented 3 years ago

Glad you got it - closing out to cleanup!