本文为原创文章。欢迎任何形式的转载,但请务必注明出处 冷冷https://lltx.github.io。java
本篇是 spring boot v2.3 系列第三篇,来分享一下 v2.3 关于 spring data redis 的故障转移优化。github
关于 Redis 在生产中咱们通常状况下都会选择 redis cluster 高可用架构部署,既能保证数据分片而且实现节点的故障自动转移。 基本部署拓扑以下:redis
docker run --name redis-cluster -d -e CLUSTER_ANNOUNCE_IP=宿主机IP \ -p 7000-7005:7000-7005 -p 17000-17005:17000-17005 pig4cloud/redis-cluster:4.0
⋊> ./redis-cli -h 172.17.0.111 -p 7000 -c 16:09:48 172.17.0.111:7000> cluster nodes 3d882206d40935beef84ff564b538d57369e4fd9 172.17.0.111:7003@17003 slave b8d24150df4a221c1045cd9a0696bd1972912d52 0 1591344590000 4 connected b8d24150df4a221c1045cd9a0696bd1972912d52 172.17.0.111:7001@17001 master - 0 1591344590513 2 connected 5461-10922 c21167a6da7f8af31d2dd612d449cdf92ad2e7e9 172.17.0.111:7005@17005 slave 810baa140db6e008a137708f09d4335f5207ede3 0 1591344591000 6 connected 810baa140db6e008a137708f09d4335f5207ede3 172.17.0.111:7000@17000 myself,master - 0 1591344590000 1 connected 0-5460 05d2f9884d350a50ac9e38f575b57f19e864e74c 172.17.0.111:7004@17004 slave b3cf24a918d96a1949f49a1d7b3a965ff9dc858c 0 1591344590011 5 connected b3cf24a918d96a1949f49a1d7b3a965ff9dc858c 172.17.0.111:7002@17002 master - 0 1591344591617 3 connected 10923-16383
spring: redis: cluster: nodes: - 172.17.0.111:7000 - 172.17.0.111:7001 - 172.17.0.111:7002 - 172.17.0.111:7003 - 172.17.0.111:7004 - 172.17.0.111:7005
@RestController public class DemoController { @Autowired private RedisTemplate redisTemplate; @GetMapping("/add") public String redis() { redisTemplate.opsForValue().set("k1", "v1"); return "ok"; } }
⋊> curl http://localhost:8080/add ok⏎
咱们会发现操做 k1 是在 7000 节点进行操做写入spring
[channel=0x5ff7aa8f, /172.17.0.156:50783 -> /172.17.0.111:7000, epid=0x8] write() writeAndFlush command ClusterCommand [command=AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], redirections=0, maxRedirections=5] [channel=0x5ff7aa8f, /172.17.0.156:50783 -> /172.17.0.111:7000, epid=0x8] write() done
./redis-cli -h 172.17.0.111 -p 7000 -c 172.17.0.111:7000> SHUTDOWN
咱们能够看到此时集群选举完毕,完成故障转移docker
23:S 05 Jun 08:24:49.387 # Starting a failover election for epoch 7. 29:M 05 Jun 08:24:49.388 # Failover auth granted to c21167a6da7f8af31d2dd612d449cdf92ad2e7e9 for epoch 7 26:M 05 Jun 08:24:49.388 # Failover auth granted to c21167a6da7f8af31d2dd612d449cdf92ad2e7e9 for epoch 7 23:S 05 Jun 08:24:49.389 # Failover election won: I'm the new master. 23:S 05 Jun 08:24:49.389 # configEpoch set to 7 after successful failover 23:M 05 Jun 08:24:49.389 # Setting secondary replication ID to 5253748ecf5bd7ab3536058fba8cad62d2d5e825, valid up to offset: 1622. New replication ID is 21d6a0b199a1ba655c0279d9c78f9682477ac9a3 23:M 05 Jun 08:24:49.389 * Discarding previously cached master state. 23:M 05 Jun 08:24:49.390 # Cluster state changed: ok
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /172.17.0.111:7000 Caused by: java.net.ConnectException: Connection refused io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /172.17.0.111:7000 Caused by: java.net.ConnectException: Connection refused io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /172.17.0.111:7000 Caused by: java.net.ConnectException: Connection refused
⋊> curl http://localhost:8080/add
此时仍是操做 k1, 根据 slot 对应链接到 7000 节点,已经链接不到无限尝试重连的问题。 lettuce 客户端并未和 redis cluster 集群状态同步刷新,把宕机节点移除,完成故障转移。shell
拓扑动态感应即客户端可以根据 redis cluster 集群的变化,动态改变客户端的节点状况,完成故障转移。架构
咱们只须要在 spring boot 2.3.0 版本中 开启此特性便可。app
spring: redis: lettuce: cluster: refresh: adaptive: true
咱们只须要参考 adaptive 开关打开后作了哪些事情,给本身的项目配置上 topology-view 便可
@Bean public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) { RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes()); // https://github.com/lettuce-io/lettuce-core/wiki/Redis-Cluster#user-content-refreshing-the-cluster-topology-view ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enablePeriodicRefresh() .enableAllAdaptiveRefreshTriggers() .refreshPeriod(Duration.ofSeconds(5)) .build(); ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder() .topologyRefreshOptions(clusterTopologyRefreshOptions).build(); // https://github.com/lettuce-io/lettuce-core/wiki/ReadFrom-Settings LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder() .readFrom(ReadFrom.REPLICA_PREFERRED) .clientOptions(clusterClientOptions).build(); return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration); }