|
此版本仍在开发中,尚未被视为稳定版本。如需使用最新稳定版本,请访问 Spring Data Redis 4.0.4! |
Redis 集群
| 在将Redis Repository与 Redis 集群一起使用时,请先熟悉如何在集群上运行 Redis Repository。 |
| 使用 Redis 集群时,请勿依赖键空间(keyspace)事件,因为键空间事件不会在分片之间进行复制。 发布/订阅(Pub/Sub)会随机订阅一个集群节点,而该节点仅能接收来自单个分片的键空间事件。 请使用单节点 Redis 以避免键空间事件丢失。 |
使用 Redis 集群连接
Redis 集群的行为与单节点 Redis 甚至由 Sentinel 监控的主从环境有所不同。
这是因为自动分片会将一个键映射到 16384 个槽(slot)之一,而这些槽分布在各个节点上。
因此,涉及多个键的命令必须确保所有键都映射到完全相同的槽,以避免跨槽错误。
单个集群节点仅负责一组特定的键。
针对某个特定服务器发出的命令,其返回结果仅包含该服务器所负责的那些键。
举一个简单的例子,考虑 KEYS 命令。
在集群环境中向某台服务器发出该命令时,它仅返回接收请求的节点所负责的键,而不一定是整个集群中的所有键。
因此,若要在集群环境中获取所有键,您必须从所有已知的主节点分别读取键。
虽然针对特定键重定向到相应槽位服务节点的操作由驱动程序库处理,但更高层次的功能(例如跨节点收集信息或向集群中所有节点发送命令)则由 RedisClusterConnection 提供支持。
以前面提到的 keys 示例为例,这意味着 keys(pattern) 方法会获取集群中的每个主节点,并同时在每个主节点上执行 KEYS 命令,收集结果并返回所有键的汇总集合。
如果只想请求单个节点的键,RedisClusterConnection 为这些方法提供了重载版本(例如 keys(node, pattern))。
RedisClusterNode 可以通过 RedisClusterConnection.clusterGetNodes 获取,也可以通过主机和端口或节点 ID 来构造。
以下示例展示了一组在集群中执行的命令:
[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-present2 (2)
164888... 127.0.0.1:7381 master - 0 1449730618304 3 connected 10923-present3 (3)
b8b5ee... 127.0.0.1:7382 slave 6b38bb... 0 1449730618304 25 connected (4)
RedisClusterConnection connection = connectionFactory.getClusterConnection();
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 | 主节点负责处理槽位 0 到 5460,并复制到位于 7382 的副本节点 |
| 2 | 主节点负责处理槽位 5461 至 10922 |
| 3 | 主节点负责处理槽位 10923 至 16383 |
| 4 | 持有主节点(端口 7379)副本的副本节点 |
| 5 | 请求已路由至服务于槽位 12182 的节点(端口 7381) |
| 6 | 请求已路由至服务于槽位 5061 的 7379 节点 |
| 7 | 请求被路由到端口为 7379、7380、7381 的节点 → [thing1, thing2] |
| 8 | 请求已路由至节点 7379 → [thing2] |
| 9 | 请求已路由到节点 7380 → [] |
| 10 | 请求已路由到节点 7381 → [thing1] |
| 11 | 请求已路由到节点 7382 → [thing2] |
当所有键都映射到同一个槽(slot)时,原生驱动库会自动处理跨槽请求,例如 MGET。
然而,一旦情况并非如此,RedisClusterConnection 就会对负责各个槽的节点并行执行多个 GET 命令,并再次返回一个汇总的结果。
这种方式的性能不如单槽方法,因此应谨慎使用。
如有疑问,可考虑通过在键名中添加花括号内的前缀(例如 {my-prefix}.thing1 和 {my-prefix}.thing2)将键固定到同一个槽,这样它们都会映射到相同的槽编号。
以下示例展示了跨槽请求的处理方式:
[email protected]:7379 > cluster nodes
6b38bb... 127.0.0.1:7379 master - 0 0 25 connected 0-5460 (1)
7bb...
RedisClusterConnection connection = connectionFactory.getClusterConnection();
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 | 与前面示例中的配置相同。 |
| 2 | 键映射到相同的槽 → 127.0.0.1:7381 MGET thing1 {thing1}.thing2 |
| 3 | 键映射到不同的槽位,并被拆分为单个槽位,路由到相应的节点 → 127.0.0.1:7379 GET thing2 → 127.0.0.1:7381 GET thing1 |
上述示例展示了 Spring Data Redis 所遵循的一般策略。
请注意,某些操作可能需要将大量数据加载到内存中,以执行所需命令。
此外,并非所有跨槽(cross-slot)请求都能安全地转换为多个单槽(single slot)请求,若误用则会报错(例如 PFCOUNT)。 |
使用RedisTemplate和ClusterOperations
有关 xref page 的通用目的、配置和用法信息,请参阅通过 RedisTemplate 操作对象部分。
在使用任意 JSON RedisTemplate#keySerializer 设置 RedisSerializers 时请务必小心,因为更改 JSON 结构会立即影响哈希槽(hash slot)的计算。 |
RedisTemplate 通过 ClusterOperations 接口提供对集群特定操作的访问,该接口可通过 RedisTemplate.opsForCluster() 获取。
这允许您在集群中的单个节点上显式执行命令,同时保留为模板配置的序列化和反序列化功能。
它还提供了管理命令(例如 CLUSTER MEET)或更高级别的操作(例如重新分片)。
以下示例展示了如何通过 RedisClusterConnection 访问 RedisTemplate:
RedisClusterConnection 访问 RedisTemplateClusterOperations clusterOps = redisTemplate.opsForCluster();
clusterOps.shutdown(NODE_7379); (1)
| 1 | 关闭位于 7379 端口的节点,并祈祷已有副本可以接管。 |
Redis 集群管道功能目前仅通过 Lettuce 驱动程序支持,但在使用跨槽键时以下命令除外:rename、renameNX、sort、bLPop、bRPop、rPopLPush、bRPopLPush、info、sMove、sInter、sInterStore、sUnion、sUnionStore、sDiff、sDiffStore。
同一槽位的键已完全支持。 |