学习目标:
1、了解Sentine机制的原理
2、掌握Sentine的搭建
学习过程:
一、直接使用JRedis的实现Sentine
上一节课说到使用Sentine可以自动完成主从切换,客户端的代码不需要修改,以实现高可用性,所以连接redis的客户端代码需要修改,我们只需要直接连接Sentine集群就可以了,不需要连接redis服务了
JRedis直接使用JedisSentinelPool连接池就可以了,感觉比使用Spring整合的方式还要简单一点,我们只需要连接Sentine的配置信息就可以了,代码如下。在运行下面的代码是你可以尝试一下把其中一个redis服务器停了。代码如下;
/**
* @author liubao
*/
public class JedisSentinelTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Set<String> sentinels = new HashSet<String>();
sentinels.add("192.168.137.101:6379");
sentinels.add("192.168.137.102:6379");
sentinels.add("192.168.137.103:6379");
JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels);
Jedis jedis = null;
int i=0;
while (true) {
Thread.sleep(1000);
i++;
try {
jedis = jedisSentinelPool.getResource();
Date now = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String format_now = dateFormat.format(now);
jedis.set("hello"+i, "world"+i);
String value = jedis.get("hello"+i);
System.out.println(format_now + ' ' + value);
} catch (Exception e) {
System.out.println(e);
} finally {
if (jedis != null)
try {
jedis.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
}
二、整合Spring
1、redis.properties配置文件
#访问地址 使用sentinel后,这个就不需要了。
#redis.host=192.168.8.234
#访问端口
#redis.port=6379
#注意,如果没有password,此处不设置值,但这一项要保留
#redis.password=
#最大闲置连接数
redis.maxIdle=500
#最大连接数,超过此连接时操作redis会报错
redis.maxTotal=5000
redis.maxWaitTime=1000
redis.testOnBorrow=true
#最小闲置连接数,spring启动的时候自动建立该数目的连接供应用程序使用,不够的时候会申请。
redis.minIdle=300
# Redis settings
#sentinel1的IP和端口
redis.sentinel1.host=192.168.8.234
redis.sentinel1.port=26379
#sentinel2的IP和端口
redis.sentinel2.host=192.168.8.235
redis.sentinel2.port=26379
#sentinel3的IP和端口
redis.sentinel3.host=192.168.8.236
redis.sentinel3.port=26379
#sentinel的鉴权密码
redis.sentinel.masterName=mymaster
redis.sentinel.password=123456
2、redisContext.xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- scanner redis properties -->
<context:property-placeholder location="classpath:redis.properties"
ignore-unresolvable="true" />
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.maxTotal}" />
<property name="minIdle" value="${redis.minIdle}" />
<property name="maxWaitMillis" value="${redis.maxWaitTime}" />
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
</bean>
<bean id="sentinelConfiguration"
class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<property name="name" value="${redis.sentinel.masterName}"></property>
</bean>
</property>
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host"
value="${redis.sentinel1.host}"></constructor-arg>
<constructor-arg name="port"
value="${redis.sentinel1.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host"
value="${redis.sentinel2.host}"></constructor-arg>
<constructor-arg name="port"
value="${redis.sentinel2.port}"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host"
value="${redis.sentinel3.host}"></constructor-arg>
<constructor-arg name="port"
value="${redis.sentinel3.port}"></constructor-arg>
</bean>
</set>
</property>
</bean>
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:password="${redis.sentinel.password}">
<constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
<constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
</beans>
3、测试类
@RunWith(SpringJUnit4ClassRunner.class) //
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) //
public class RedisTest {
@Resource(name = "redisTemplate")
private RedisTemplate template;
@Test
public void testSpringRedis() {
template.opsForValue().set("spring", "springredissentinel");
}
@Test
public void testgetRedis() {
String temp=(String) template.opsForValue().get("spring");
System.out.println(temp);
}
}
三、使用Spring Boot整合
Spring Boot非常容易使用
1、修改application.properteis
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
#哨兵监听redis server名称
spring.redis.sentinel.master=mymaster
#哨兵的配置列表
spring.redis.sentinel.nodes=192.168.8.234:26379,192.168.8.235:26379,192.168.8.236:26379
2、导入相关的包。修改pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
3、类封装
@Service
public class RedisService {
@Autowired // 操作字符串的template,StringRedisTemplate是RedisTemplate的一个子集
private StringRedisTemplate stringRedisTemplate;
@Autowired // RedisTemplate,可以进行所有的操作
private RedisTemplate<Object, Object> redisTemplate;
public void set(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}
4、测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringfirstApplicationTests {
@Autowired
private RedisService service;
@Test
public void testResis() {
service.set("name", "liubaospringboot");
String name = service.get("name");
System.out.println("name:" + name);
}
}
几乎不用写什么代码,直接使用就可以了。
Redis的HA(高可用性)我们就讲到这里,但是也留下了一些问题,就是高可用性和分片如何一起使用呢?在官方的JRedis居然没有好的解决方案。也就是说主从模式下,通过哨兵配置,单个集群数据无法分片(备复制->主的数据,备无写权限),后面我们可以使用Redis Cluster,它是Redis的集群实现,内置数据自动分片机制和主备模式。而且客户端的支持也非常好。
当然如果你就是要配置sentinel和ShardedJedisPool结合使用。也就是结合分片的技术,同事每一个分片又是主从模式,也有一些第三方的人写了一些插件。可以参考一下下面的开源项目