diff --git a/README.md b/README.md index 53790e0..1494ca9 100644 --- a/README.md +++ b/README.md @@ -138,41 +138,66 @@ The `#pubsub` method supports sharded subscriptions. Every interface handles redirections and resharding states internally. ## Multiple keys and CROSSSLOT error -A subset of commands can be passed multiple keys. But it has a constraint the keys are in the same hash slot. -The following error occurs because keys must be in the same hash slot and not just the same node. +A subset of commands can be passed multiple keys. +In cluster mode, these commands have a constraint that passed keys should belong to the same slot +and not just the same node. +Therefore, The following error occurs: -```ruby -cli = RedisClient.cluster.new_client +``` +$ redis-cli mget key1 key2 key3 +(error) CROSSSLOT Keys in request don't hash to the same slot + +$ redis-cli cluster keyslot key1 +(integer) 9189 -cli.call('MGET', 'key1', 'key2', 'key3') -#=> CROSSSLOT Keys in request don't hash to the same slot (RedisClient::CommandError) +$ redis-cli cluster keyslot key2 +(integer) 4998 -cli.call('CLUSTER', 'KEYSLOT', 'key1') -#=> 9189 +$ redis-cli cluster keyslot key3 +(integer) 935 +``` -cli.call('CLUSTER', 'KEYSLOT', 'key2') -#=> 4998 +For the constraint, Redis cluster provides a feature to be able to bias keys to the same slot with a hash tag. -cli.call('CLUSTER', 'KEYSLOT', 'key3') -#=> 935 ``` +$ redis-cli mget {key}1 {key}2 {key}3 +1) (nil) +2) (nil) +3) (nil) -Also, you can use the hash tag to bias keys to the same slot. +$ redis-cli cluster keyslot {key}1 +(integer) 12539 -```ruby -cli.call('CLUSTER', 'KEYSLOT', '{key}1') -#=> 12539 +$ redis-cli cluster keyslot {key}2 +(integer) 12539 -cli.call('CLUSTER', 'KEYSLOT', '{key}2') -#=> 12539 +$ redis-cli cluster keyslot {key}3 +(integer) 12539 +``` -cli.call('CLUSTER', 'KEYSLOT', '{key}3') -#=> 12539 +In addition, this gem works multiple keys without a hash tag in MGET, MSET and DEL commands +using pipelining internally automatically. +If the first key includes a hash tag, this gem sends the command to the node as is. +If the first key doesn't have a hash tag, this gem converts the command into a single-key command +and sends them to nodes with pipelining, then gathering replies and returning them. -cli.call('MGET', '{key}1', '{key}2', '{key}3') +```ruby +r = RedisClient.cluster.new_client +#=> # + +r.call('mget', 'key1', 'key2', 'key3') +#=> [nil, nil, nil] + +r.call('mget', '{key}1', '{key}2', '{key}3') #=> [nil, nil, nil] ``` +This behavior is for upper libraries to be able to keep a compatibility with a standalone client. +You can exploit this behavior for migrating from a standalone server to a cluster. +Although multiple calles with single-key comamnds are slower than pipelining, +the performance of the pipelined commands are slower than a single-slot query with multiple keys. +We recommend to use a hash tag in this use cases for the performance. + ## Transactions This gem supports [Redis transactions](https://redis.io/topics/transactions), including atomicity with `MULTI`/`EXEC`, and conditional execution with `WATCH`. Redis does not support cross-node transactions, so all keys used within a