目錄:
前言:
通過結合前篇的redis sentinel與springboot達到增加理解的效果。本文采取1master2slave3sentinel.
一.預備工作
先啓動master和兩個slave,然後再啓動sentinel.
redis端口依次爲6379,6380,6381,sentinel依次是10001,10002,10003
二.創建springboot項目
pom文件
<properties> <java.version>1.8</java.version> <lombok.version>1.18.4</lombok.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </exclusion> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.5.0</version> <!--<version>2.4.2</version>--> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
yml文件:
spring: redis: password: 123456 jedis: pool: #最大連接數 max-active: 1024 #最大阻塞等待時間(負數表示沒限制) max-wait: 20000 #最大空閒 max-idle: 200 #最小空閒 min-idle: 10 sentinel: master: mymaster nodes: 127.0.0.1:10001,127.0.0.1:10002,127.0.0.1:10003 server: port: 9527
config文件:
@Configuration
@EnableAutoConfiguration
@Slf4j
public class RedisSentinelConfig {
@Value("#{'${spring.redis.sentinel.nodes}'.split(',')}")
private List<String> nodes;
@Bean
@ConfigurationProperties(prefix="spring.redis")
public JedisPoolConfig getRedisConfig(){
JedisPoolConfig config = new JedisPoolConfig();
return config;
}
@Bean
public RedisSentinelConfiguration sentinelConfiguration(){
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
//配置matser的名稱
redisSentinelConfiguration.master("mymaster");
//配置redis的哨兵sentinel
Set<RedisNode> redisNodeSet = new HashSet<>();
nodes.forEach(x->{
redisNodeSet.add(new RedisNode(x.split(":")[0],Integer.parseInt(x.split(":")[1])));
});
log.info("redisNodeSet -->"+redisNodeSet);
//哨兵模式添加set
redisSentinelConfiguration.setSentinels(redisNodeSet);
return redisSentinelConfiguration;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisSentinelConfiguration sentinelConfig) {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinelConfig,jedisPoolConfig);
return jedisConnectionFactory;
}
}
啓動服務:期間曾經遇到一個問題:
警告: Cannot get master address from sentinel running @ 127.0.0.1:6379. Reason: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect. Trying next one.
問題的原因是因爲sentinel綁定127.0.0.1的時候綁定自己本機ip或者指定ip地址
完成這些以後日誌:
經過sentinel找到redis地址。
接下來說說 JedisConnectionFactory
按照上面的配置,獲得了JedisPoolConfig的bean和RedisSentinelConfiguration的bean.最終配置的JedisConnectionFactory。
點進JedisConnectionFactory類裏面去,可以看到裏面的類關係圖,如圖所示(網上找的)
時序圖:
根據bean的生命週期,由於JedisConnectionFactory實現了InitializingBean因此先執行了afterPropertiesSet方法,在afterPropertiesSet方法裏面調用createPool,一直調用,在initSentinels的方面裏面調用了new JedisSentinelPool.MasterListener返回了masterlisenter,隨後調用了masterlistener的start方法。
打斷點進入initSentinels方法裏面,先是根據yml的配置文件獲取哨兵的ip和端口,然後根據sentinelGetMasterAndAddrByName獲取redis主節點的ip和地址
如下圖所示,其實masterlistener是個內部類,繼承了Thread.
在這個線程裏面不停在遍歷,獲取redis的master節點。
關閉主節點後,經過選舉,和masterlinster的遍歷循環,更改了主節點並告知了服務