分片集群 有了主从、有了哨兵,解决了高可用和高并发读的问题。但是,即便如此,仍然有两个问题没有解决。 第一,是海量数据的储存问题 。 第二,是高并发写的问题 。 那么,使用分片集群,便可以解决这样的两个问题。 对于一个分片集群来说,集群中有多个master,每个master保存不一样的数据,对于每个master来说,有多个slave节点。 master之间可以通过ping来监测彼此的健康状态。 客户端发出的对于redis的请求,可以访问集群的任意节点,最终,都会被转发到正确的节点中去。 对于一个分片集群来说,一个节点就是一个运行在集群模式下的Redis服务器。启动Redis服务器时,通过判断cluster-enabled选项,选择是否开启集群模式。(Yes开启集群,No则单机模式普通服务器)
1 2 3 4 5 6 7 8 cluster-enabled yes cluster-node -timeout 15000 cluster-config-file nodes-6379 .conf
每个节点使用的端口各不相同,可以设置。每个节点最开始可以看做一个只有自己节点的集群,节点间通过命令相互握手,组建集群。 握手命令如下:
1 2 3 4 5 cluster meet 127.0.0.1:6378 cluster nodes
分片集群的搭建与使用 此处还是采用docker的方式来进行演示分片集群的搭建与使用。 首先,还是使用redis:bullseye的镜像。
1 docker pull redi s:bullseye
而后,于此以不挂载的方式进行搭建,挂载的方式其实也是一样的。 第一步是创建一个network网络:
1 2 3 4 docker network create redis-cluster-network docker network ls
Redis分片集群至少需要6个Redis实例,3个为主节点,3个为副本节点。
1 2 3 4 5 6 docker run -d --name redis-node-1 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7001 docker run -d --name redis-node-2 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7002 docker run -d --name redis-node-3 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7003 docker run -d --name redis-node-4 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7004 docker run -d --name redis-node-5 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7005 docker run -d --name redis-node-6 --net redis-cluster-network redis:bullseye redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --port 7006
接着可以检查redis的实例是否全部启动成功:
随后,集群需要使用IP地址来进行节点间通信,可以使用以下命令来获得每个Redis实例的IP地址:
1 2 3 4 5 6 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-1 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-2 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-3 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-4 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-5 docker inspect -f ' {{range.NetworkSettings.Networks }} {{.IPAddress }} {{end }} ' redis-node-6
于此,得到了几个redis实例的IP地址:
1 2 3 4 5 6 172.24.0.2 172.24.0.3 172.24.0.4 172.24.0.5 172.24.0.6 172.24.0.7
基于此,可以开始启动集群了:
1 2 3 4 5 6 7 8 docker run -it --rm --net redis-cluster-network redis:bullseye redis-cli --cluster create \ 172.24 .0.2 :7001 \ 172.24 .0.3 :7002 \ 172.24 .0.4 :7003 \ 172.24 .0.5 :7004 \ 172.24 .0.6 :7005 \ 172.24 .0.7 :7006 \ --cluster-replicas 1
Port就是上面启动时使用的Port,此命令将会创建一个有三个主节点、三个从节点的Redis集群,其中 –cluster-replicas 1 表示每个主节点都会有一个副本节点。启动的时候显示如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 >>> Performing hash slots allocation on 6 nodes...Master [0 ] -> Slots 0 - 5460 Master [1 ] -> Slots 5461 - 10922 Master [2 ] -> Slots 10923 - 16383 Adding replica 172.24 .0.6 :7005 to 172.24 .0.2 :7001 Adding replica 172.24 .0.7 :7006 to 172.24 .0.3 :7002 Adding replica 172.24 .0.5 :7004 to 172.24 .0.4 :7003 M: a85caca5fada00aa43bc3ff7baf47e8eda13c814 172.24 .0.2 :7001 slots:[0 -5460 ] (5461 slots) master M : dae07fbbbf0e8ba7c9959408ac931d70deaaef0b 172.24 .0.3 :7002 slots:[5461 -10922 ] (5462 slots) master M : 43 e2c65d9be8750131a631b6fe79a19bdb6deaee 172.24 .0.4 :7003 slots:[10923 -16383 ] (5461 slots) master S : a044956680f88d49209b54aaa282279c2b955679 172.24 .0.5 :7004 replicates 43 e2c65d9be8750131a631b6fe79a19bdb6deaee S: 71 f225cb0e495187062782dc668b3b9e2d1e6fcd 172.24 .0.6 :7005 replicates a85caca5fada00aa43bc3ff7baf47e8eda13c814 S: 7108324 df122bc424d6f5c0502311e4b7f19701f 172.24 .0.7 :7006 replicates dae07fbbbf0e8ba7c9959408ac931d70deaaef0b Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join .. >>> Performing Cluster Check (using node 172 .24.0 .2 :7001 ) M: a85caca5fada00aa43bc3ff7baf47e8eda13c814 172.24 .0.2 :7001 slots:[0 -5460 ] (5461 slots) master 1 additional replica(s) M: 43 e2c65d9be8750131a631b6fe79a19bdb6deaee 172.24 .0.4 :7003 slots:[10923 -16383 ] (5461 slots) master 1 additional replica(s) S: a044956680f88d49209b54aaa282279c2b955679 172.24 .0.5 :7004 slots: (0 slots) slave replicates 43 e2c65d9be8750131a631b6fe79a19bdb6deaee M: dae07fbbbf0e8ba7c9959408ac931d70deaaef0b 172.24 .0.3 :7002 slots:[5461 -10922 ] (5462 slots) master 1 additional replica(s) S: 71 f225cb0e495187062782dc668b3b9e2d1e6fcd 172.24 .0.6 :7005 slots: (0 slots) slave replicates a85caca5fada00aa43bc3ff7baf47e8eda13c814 S: 7108324 df122bc424d6f5c0502311e4b7f19701f 172.24 .0.7 :7006 slots: (0 slots) slave replicates dae07fbbbf0e8ba7c9959408ac931d70deaaef0b [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
搭建好后的Redis分片集群如下: 在集群创建成功后,使用以下命令查看集群状态:
1 docker exec -it redis-node -1 redis-cli -p 7001 cluster nodes
1 2 3 4 5 6 43e2c65d9be8750131a631b6fe79a19bdb6deaee 172.24.0.4:7003 @17003 master - 0 1727075791763 3 connected 10923 -16383 a044956680f88d49209b54aaa282279c2b955679 172.24.0.5:7004 @17004 slave 43 e2c65d9be8750131a631b6fe79a19bdb6deaee 0 1727075792766 3 connecteddae07fbbbf0e8ba7c9959408ac931d70deaaef0b 172.24.0.3:7002 @17002 master - 0 1727075791000 2 connected 5461 -10922 71f225cb0e495187062782dc668b3b9e2d1e6fcd 172.24.0.6:7005 @17005 slave a85caca5fada00aa43bc3ff7baf47e8eda13c814 0 1727075790558 1 connected7108324df122bc424d6f5c0502311e4b7f19701f 172.24.0.7:7006 @17006 slave dae07fbbbf0e8ba7c9959408ac931d70deaaef0b 0 1727075791000 2 connecteda85caca5fada00aa43bc3ff7baf47e8eda13c814 172.24.0.2:7001 @17001 myself,master - 0 1727075791000 1 connected 0 -5460
或者也可通过以下命令查看集群状态:
1 docker exec -it redis-node -1 redis-cli -p 7001 cluster inf o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cluster_state: okcluster_slots_assigned: 16384 cluster_slots_ok: 16384 cluster_slots_pfail: 0 cluster_slots_fail: 0 cluster_known_nodes: 6 cluster_size: 3 cluster_current_epoch: 6 cluster_my_epoch: 1 cluster_stats_messages_ping_sent: 37 cluster_stats_messages_pong_sent: 39 cluster_stats_messages_sent: 76 cluster_stats_messages_ping_received: 34 cluster_stats_messages_pong_received: 37 cluster_stats_messages_meet_received: 5 cluster_stats_messages_received: 76
在分片集群搭建完毕后,如果说,采用原始的方式进入分片集群的一个节点,进行设置。比如,通过redis-cli 命令连接到集群中的任意节点,插入数据并验证是否自动分片。
1 docker exec -it redis-node -1 redis-cli -p 7001
会出现如下显示:
1 2 3 4 127.0.0.1:7001 > set key1 "value1" (error) MOVED 9189 172 .24 .0 .3 :7002 127.0.0.1:7001 > get key1 (error) MOVED 9189 172 .24 .0 .3 :7002
出现 (error) MOVED 错误是因为 Redis 集群将键分片到不同的主节点上,Redis 集群使用哈希槽(hash slots)将键映射到特定的节点。当你直接连接到某个节点时,如果该键不属于这个节点,Redis 会返回 MOVED 错误,并告知你正确的主节点地址。 解决方法是通过 redis-cli 的集群模式连接,这样 redis-cli 会自动跟踪集群中的正确节点,不需要手动处理 MOVED 错误。在运行redis-cli的时候加上-c的选项。
1 docker exec -it redis-node -1 redis-cli -p 7001 -c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 127.0.0.1:7001 > set key1 1099 -> Redirected to slot [9189] located at 172 .24 .0 .3 :7002 OK172.24.0.3:7002 > get key1"1099" 172.24.0.3:7002 > set key1 "gagaduck" OK172.24.0.3:7002 > get key1"gagaduck" 172.24.0.3:7002 > set test_key "gagaduck" -> Redirected to slot [15118] located at 172 .24 .0 .4 :7003 OK172.24.0.4:7003 > get test_key"gagaduck"
此时,Redis CLI 应该自动处理键的分片,并且不会再出现 MOVED 错误。
客户端连接Redis分片集群 springboot连接分片Redis集群 首先,要确保pom.xml中添加有redis的依赖:
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency >
随后,配置集群信息:
1 2 3 spring.data.redis.cluster.nodes=172.24.0.2 :7001,172.24 .0.3:7002 ,172.24.0.4 :7003,172.24 .0.5:7004 ,172.24.0.6 :7005,172.24 .0.7:7006 spring.data.redis.password= spring.data.redis.timeout=2000
spring.redis.cluster.nodes 列出所有Redis集群节点的IP和端口,Spring Boot将会连接这些节点,并通过Redis集群协议获取集群的信息和哈希槽分片。 spring.redis.timeout 设置连接的超时时间。 Spring Boot支持两种主要的Redis客户端:Lettuce 和 Jedis。这两者都支持Redis分片集群。默认情况下,Spring Boot使用 Lettuce,它是非阻塞的,性能更好。这里也采用Lettuce作为客户端为例。 对客户端进行配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Configuration public class RedisClusterConfig { @Bean public LettuceConnectionFactory redisConnectionFactory () { RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration ( Arrays.asList("172.24.0.2:7001" , "172.24.0.3:7002" , "172.24.0.4:7003" , "172.24.0.5:7004" , "172.24.0.6:7005" , "172.24.0.7:7006" )); ClusterTopologyRefreshOptions refreshOptions = ClusterTopologyRefreshOptions.builder() .enablePeriodicRefresh(Duration.ofMinutes(10 )) .enableAllAdaptiveRefreshTriggers() .build(); ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() .topologyRefreshOptions(refreshOptions) .build(); LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder() .clientOptions(clusterClientOptions) .build(); return new LettuceConnectionFactory (redisClusterConfiguration, clientConfiguration); } }
正确配置好了之后,便可以通过 RedisTemplate 或 StringRedisTemplate 来操作Redis数据。Spring Boot会根据键的哈希值自动将请求路由到正确的Redis节点。
1 2 stringRedisTemplate.opsForValue().set ("key1" , "value1" ); stringRedisTemplate.opsForValue().get ("key1" );
具体可以参考https://github.com/gagaducko/learning_demos/tree/main/distributed-redis-example 如果需要显示集群的一些信息等等情况,也可以采用RedisConnectionFactory来进行操作:
1 2 @Autowired private RedisConnectionFactory redisConnectionFactory;
当进行请求时,如/clusterInfo便可以获得cluster的一些信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Cluster Info: Node ID: a044956680f88d49209b54aaa282279c2b955679 Address: 172.24 .0 .5 Master: false Slots: []----------------------- Node ID: 71f225cb0e495187062782dc668b3b9e2d1e6fcd Address: 172.24 .0 .6 Master: false Slots: []----------------------- Node ID: dae07fbbbf0e8ba7c9959408ac931d70deaaef0b Address: 172.24 .0 .3 Master: true Slots: …… ……
当setKey时:
1 Key 'key1' set to 'value1'
当getKey时:
1 Value for 'key1' : value1
python连接分片Redis集群 首先,需要安装依赖:
而后配置集群节点:
1 2 3 4 5 6 7 8 startup_nodes = [ ClusterNode("172.24.0.2" , 7001 ), ClusterNode("172.24.0.3" , 7002 ), ClusterNode("172.24.0.4" , 7003 ), ClusterNode("172.24.0.5" , 7004 ), ClusterNode("172.24.0.6" , 7005 ), ClusterNode("172.24.0.7" , 7006 ) ]
最后创建redis连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 try : redis_client = redis.RedisCluster(startup_nodes=startup_nodes, decode_responses=True ) redis_client.set ("name" , "Python Redis Cluster Example" ) value = redis_client.get("name" ) print (f"Stored value: {value} " )except RedisError as e: print (f"Error connecting to Redis Cluster: {e} " )except Exception as e: print (f"An unexpected error occurred: {e} " )
运行后输出:
1 Stored value: Python Redis Cluster Example
详细可见https://github.com/gagaducko/learning_demos/tree/main/distributed_redis_example_py