Working With Redis Cluster Connection

As mentioned earlier, Redis Cluster behaves differently from single-node Redis or even a Sentinel-monitored master-replica environment. This is because the automatic sharding maps a key to one of 16384 slots, which are distributed across the nodes. Therefore, commands that involve more than one key must assert all keys map to the exact same slot to avoid cross-slot execution errors. A single cluster node serves only a dedicated set of keys. Commands issued against one particular server return results only for those keys served by that server. As a simple example, consider the KEYS command. When issued to a server in a cluster environment, it returns only the keys served by the node the request is sent to and not necessarily all keys within the cluster. So, to get all keys in a cluster environment, you must read the keys from all the known master nodes.

While redirects for specific keys to the corresponding slot-serving node are handled by the driver libraries, higher-level functions, such as collecting information across nodes or sending commands to all nodes in the cluster, are covered by RedisClusterConnection. Picking up the keys example from earlier, this means that the keys(pattern) method picks up every master node in the cluster and simultaneously executes the KEYS command on every master node while picking up the results and returning the cumulated set of keys. To just request the keys of a single node RedisClusterConnection provides overloads for those methods (for example, keys(node, pattern)).

A RedisClusterNode can be obtained from RedisClusterConnection.clusterGetNodes or it can be constructed by using either the host and the port or the node Id.

The following example shows a set of commands being run across the cluster:

Example 1. Sample of Running Commands Across the Cluster
[email protected]:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      (1)
7bb78c... 127.0.0.1:7380 master - 0 1449730618304 2 connected 5461-10922       (2)
164888... 127.0.0.1:7381 master - 0 1449730618304 3 connected 10923-16383      (3)
b8b5ee... 127.0.0.1:7382 slave 6b38bb... 0 1449730618304 25 connected          (4)
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("thing1", value);                                               (5)
connection.set("thing2", value);                                               (6)

connection.keys("*");                                                          (7)

connection.keys(NODE_7379, "*");                                               (8)
connection.keys(NODE_7380, "*");                                               (9)
connection.keys(NODE_7381, "*");                                               (10)
connection.keys(NODE_7382, "*");                                               (11)
1 Master node serving slots 0 to 5460 replicated to replica at 7382
2 Master node serving slots 5461 to 10922
3 Master node serving slots 10923 to 16383
4 Replica node holding replicants of the master at 7379
5 Request routed to node at 7381 serving slot 12182
6 Request routed to node at 7379 serving slot 5061
7 Request routed to nodes at 7379, 7380, 7381 → [thing1, thing2]
8 Request routed to node at 7379 → [thing2]
9 Request routed to node at 7380 → []
10 Request routed to node at 7381 → [thing1]
11 Request routed to node at 7382 → [thing2]

When all keys map to the same slot, the native driver library automatically serves cross-slot requests, such as MGET. However, once this is not the case, RedisClusterConnection executes multiple parallel GET commands against the slot-serving nodes and again returns an accumulated result. This is less performant than the single-slot execution and, therefore, should be used with care. If in doubt, consider pinning keys to the same slot by providing a prefix in curly brackets, such as {my-prefix}.thing1 and {my-prefix}.thing2, which will both map to the same slot number. The following example shows cross-slot request handling:

Example 2. Sample of Cross-Slot Request Handling
[email protected]:7379 > cluster nodes

6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460                      (1)
7bb...
RedisClusterConnection connection = connectionFactory.getClusterConnnection();

connection.set("thing1", value);           // slot: 12182
connection.set("{thing1}.thing2", value);  // slot: 12182
connection.set("thing2", value);           // slot:  5461

connection.mGet("thing1", "{thing1}.thing2");                                  (2)

connection.mGet("thing1", "thing2");                                           (3)
1 Same Configuration as in the sample before.
2 Keys map to same slot → 127.0.0.1:7381 MGET thing1 {thing1}.thing2
3 Keys map to different slots and get split up into single slot ones routed to the according nodes
→ 127.0.0.1:7379 GET thing2
→ 127.0.0.1:7381 GET thing1
The preceding examples demonstrate the general strategy followed by Spring Data Redis. Be aware that some operations might require loading huge amounts of data into memory to compute the desired command. Additionally, not all cross-slot requests can safely be ported to multiple single slot requests and error if misused (for example, PFCOUNT).