![c6c6e208f82e88003b7e08d7cc9bbc0a.png](https://img-blog.csdnimg.cn/img_convert/c6c6e208f82e88003b7e08d7cc9bbc0a.png)
遇到困难时不要抱怨,既然改变不了过去,那么就努力改变未来。
【Redis】
八、集群(Cluster)
集群原理
- 集群搭建完成后由集群节点平分(不能平分时,前几个节点多一个槽)16384个槽。
- 客户端可以访问集群中任意节点。所以在写代码时都是需要把集群中所有节点都配置上。
- 当向集群中新增或查询一个键值对时,会对Key进行Crc16算法得出一个小于16384值,判断值在哪个节点上,然后就操作哪个节点。
![fbc70e8dd7d5f55253bc73732f51fc4d.png](https://img-blog.csdnimg.cn/img_convert/fbc70e8dd7d5f55253bc73732f51fc4d.png)
前提:已经安装好redis单机版。
当集群中超过或等于1/2节点不可用时,整个集群不可用。为了搭建稳定集群,都采用奇数节点。
演示:创建3个节点,每个节点搭建一主一从。
1. 复制redis
在/usr/local下新建redis-cluster
- # mkdir /usr/local/redis-cluster
把单机redis复制到redis-cluster中
- # cd /usr/local/redis
- # cp -r bin /usr/local/redis-cluster/redis1
2. 修改redis.conf
- # cd /usr/local/redis-cluster/redis1
- # vim redis.conf
需要修改如下:
port 7001
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000
# appendonly yes 如果开启aof默认,需要修改为yes。如果使用rdb,此处不需要修改
daemonize yes
protected-mode no
pidfile /var/run/redis_7001.pid
3. 复制redis
把redis1复制5份
- # cd /usr/local/redis-cluster
执行之前一定要先删除dump.rdb,清空Redis中数据。
- # rm -f redis1/dump.rdb
- # cp -r redis1 redis2
- # cp -r redis1 redis3
- # cp -r redis1 redis4
- # cp -r redis1 redis5
- # cp -r redis1 redis6
新复制的5个redis的配置文件redis.conf都需要需改三处。
- # vim redis2/redis.conf
- # vim redis3/redis.conf
- # vim redis4/redis.conf
- # vim redis5/redis.conf
- # vim redis6/redis.conf
例如redis2/redis.conf中需要把所有7001都换成7002。
可以使用 :%s/7001/7002/g 进行全局修改。
port 7002
cluster-config-file nodes-7002.conf
pidfile /var/run/redis_700.2pid
4. 启动6个redis
- # vim startup.sh
先启用编辑状态,再粘贴下面内容
cd redis1
./redis-server redis.conf
cd ..
cd redis2
./redis-server redis.conf
cd ..
cd redis3
./redis-server redis.conf
cd ..
cd redis4
./redis-server redis.conf
cd ..
cd redis5
./redis-server redis.conf
cd ..
cd redis6
./redis-server redis.conf
cd ..
- # chmod a+x startup.sh
- # ./startup.sh
5. 查看启动状态
ps aux|grep redis
![52d39b11ed11f2ac286c3183316f8b60.png](https://img-blog.csdnimg.cn/img_convert/52d39b11ed11f2ac286c3183316f8b60.png)
6. 建立集群
在redis3的时候需要借助ruby脚本实现集群。在redis5中可以使用自带的redis-cli实现集群功能,比redis3的时候更加方便了。
建议配置静态ip,ip改变集群失效
- # cd redis1
- # ./redis-cli --cluster create 192.168.8.129:7001 192.168.8.129:7002 192.168.8.129:7003 192.168.8.129:7004 192.168.8.129:7005 192.168.8.129:7006 --cluster-replicas 1
执行完命令后,询问是否按照当前配置创建集群,输入yes而不是y。
![692a15fbe8ab69e6c8f468992062181d.png](https://img-blog.csdnimg.cn/img_convert/692a15fbe8ab69e6c8f468992062181d.png)
7. 测试
集群测试时,千万不要忘记最后一个-c参数。
- # ./redis-cli -p 7001 -c
- # set age 18
8. 编写关闭脚本
- # cd /usr/local/redis-cluster
- # vim stop.sh
- # chmod a+x stop.sh
./redis1/redis-cli -p 7001 shutdown
./redis2/redis-cli -p 7002 shutdown
./redis3/redis-cli -p 7003 shutdown
./redis4/redis-cli -p 7004 shutdown
./redis5/redis-cli -p 7005 shutdown
./redis6/redis-cli -p 7006 shutdown
九、Jedis
Redis给Java语言提供了客户端API,称之为Jedis。
Jedis API和Redis 命令几乎是一样的。
例如:Redis对String值新增时set命令,Jedis中也是set方法。所以本课程中没有重点把所有方法进行演示,重要演示Jedis如何使用。
Jedis API特别简单,基本上都是创建对象调用方法即可。由于Jedis不具备把对象转换为字符串的能力,所以每次都需要借助Json转换工具进行转换,这个功能在Spring Data Redis中已经具备,推荐使用Spring Data Redis。
1. 添加依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.2.6.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2. 单机版
public void testStandalone(){
Jedis jedis = new Jedis("192.168.32.132",6379);
jedis.set("name","smallming-standalone");
String value = jedis.get("name");
System.out.println(value);
}
3. 带有连接池
public void testPool(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(20);
jedisPoolConfig.setMaxIdle(5);
jedisPoolConfig.setMinIdle(3);
JedisPool jedisPool = new JedisPool(jedisPoolConfig,"192.168.32.132",6379);
Jedis jedis = jedisPool.getResource();
jedis.set("name","smallming-pool");
String value = jedis.get("name");
System.out.println(value);
}
4. 集群
public void testCluster(){
Set<HostAndPort> set = new HashSet<>();
set.add(new HostAndPort("192.168.32.132",7001));
set.add(new HostAndPort("192.168.32.132",7002));
set.add(new HostAndPort("192.168.32.132",7003));
set.add(new HostAndPort("192.168.32.132",7004));
set.add(new HostAndPort("192.168.32.132",7005));
set.add(new HostAndPort("192.168.32.132",7006));
JedisCluster jedisCluster = new JedisCluster(set);
jedisCluster.set("name","smallming");
String value = jedisCluster.get("name");
System.out.println(value);
}
十、 使用SpringBoot整合SpringDataRedis操作redis
1. Spring Data简介
Spring Data是Spring公司的顶级项目,里面包含了N多个二级子项目,这些子项目都是相对独立的项目。每个子项目是对不同API的封装。
所有Spring Boot整合Spring Data xxxx的启动器都叫做spring-boot-starter-data-xxxx
Spring Data 好处:很方便操作对象类型(基于POJO模型)。
把Redis不同值的类型放到一个opsForXXX方法中。
opsForValue : String值(最常用),如果存储Java对象或Java中时就需要使用序列化器,进行序列化。
- opsForList : 列表List
- opsForHash: 哈希表Hash
- opsForZSet: 有序集合Sorted Set
- opsForSet : 集合
2. Spring Data Redis序列化器介绍
经常需要向Redis中保存Java中Object或List等类型,这个时候就需要通过序列化器把Java中对象转换为字符串进行存储。
2.1 JdkSerializationRedisSerializer
是RedisTemplate类默认的序列化方式。JdkSerializationRedisSerializer使用JDK自带的序列化方式。要求被序列化的对象必须实现java.io.Serializable接口,而且存储的内容为二进制数据,这对开发者是不友好的。会出现虽然不影响使用,但是直接使用Redis客户端查询Redis中数据时前面出现乱码问题。
2.2 OxmSerializer
以字符串格式的xml存储。解析起来也比较复杂,效率也比较低。已经很少有人在使用该序列化器。
2.3 StringRedisSerializer
只能对String类型序列化操作。
2.4 GenericToStringSerializer
需要调用者给传递一个对象到字符串互转的Converter(转换器),使用比较麻烦。
2.5 Jackson2JsonRedisSerializer
该序列化器可以将对象自动转换为Json的形式存储,效率高且对调用者友好。
优点:
速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。
缺点:
此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。如果存储List等带有泛型的类型,此序列化器是无法识别泛型的,会直接把泛型固定设置为LinkedHashMap。
例如:存储时List<People> , 取出时是List<LinkedHashMap>
2.6 GenericJackson2JsonRedisSerializer
与Jackson2JsonRedisSerializer功能相似。底层依然使用Jackson工具包。相比Jackson2JsonRedisSerializer多了_class列,列里面存储类(新增时类型)的全限定路径,从Redis取出时根据_class类型进行转换,解决了泛型问题。
该序列化器不需要指定对象类型信息(.class对象)使用Object作为默认类型。目前都使用这个序列化器。
3. 代码步骤
基于Spring Test 单元测试演示
3.1 添加依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
</parent>
<dependencies>
<!-- 为了要在项目中jackson工具包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
3.2 配置配置文件
- spring.redis.host=localhost 默认值
- spring.redis.port=6379 端口号默认值
如果连接Redis集群,不需要配置host,配置spring.redis.cluster.nodes,取值为redis集群所在ip:port,ip:port。由于word排版问题nodes后面取值没有和nodes在一行。
spring:
redis:
host: 192.168.52.133
# cluster:
# nodes: 192.168.52.133:7001,192.168.52.133:7002,192.168.52.133:7003,192.168.52.133:7004,192.168.52.133:7005,192.168.52.133:7006
3.3 编写配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
3.4 编写代码
3.4.1 编写对象新增
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
public void testString() {
People peo = new People(1, "张三");
redisTemplate.opsForValue().set("peo1", peo);
}
3.4.2 编写对象获取
@Test
public void testGetString() {
People peo = (People) redisTemplate.opsForValue().get("peo1");
System.out.println(peo);
}
3.4.3 编写List
@Test
public void testList() {
List<People> list = new ArrayList<>();
list.add(new People(1, "张三"));
list.add(new People(2, "李四"));
redisTemplate.opsForValue().set("list2", list);
}
3.4.4 编写List取值
@Test
public void testGetList(){
List<People> list2 = (List<People>) redisTemplate.opsForValue().get("list2");
System.out.println(list2);
}
3.4.5 判断Key是否存在
上面讲解Redis作为缓存工具时,需要判断key是否存在,通过hasKey进行判断。
@Test
void hasKey(){
Boolean result = redisTemplate.hasKey("name");
System.out.println(result);
}
3.4.6 根据key删除数据
如果key-value正常被删除,返回true,如果key不存在返回false
@Test
void del(){
Boolean result = redisTemplate.delete("name");
System.out.println(result);
}
需要更多Java学习资料的可以到评论区留言或者私信哦,视频、源码、项目,通通都给你