springboot整合redis集群

以你之姓@ 2022-03-10 11:46 442阅读 0赞

一、redis集群原理

redis集群中的所有节点彼此互联,节点内部采用二进制协议优化传输速度和带宽,每个节点都可以与Java客户端连接。redis集群的数据分配采用哈希槽,它内置了16384个哈希槽,开发者可以根据每个redis实例的性能来调整每个redis实例上哈希槽的分布范围。当需要进行数据存取时,redis首先使用CRC16算法对key进行计算,计算结果对16384取余,即CRC16(key)%16384,使用余数来确定去哪一个节点存取这个key。当集群中超过半数的节点检测失效时会认为该节点失效。

二、集群搭建

1.集群规划
本次在两台服务器上进行安装,192.168.72.129和192.168.72.130,集群规划如下:
主节点:192.168.72.129:7001,192.168.72.129:7002,192.168.72.129:7003
从节点:192.168.72.130:8001,192.168.72.130:8002,192.168.72.130:8003
2.安装Ruby环境
Redis5.0之前的版本,创建集群需要使用redis集群管理工具redis-trib.rb,它依赖于Ruby环境,需要安装Ruby环境,5.0之后的版本不再依赖Ruby环境,请自行绕过该小节
为了方便安装,此处使用Ruby版本管理工具rvm来进行安装(可参考rvm官网:http://www.rvm.io/)。
安装GPG key:

  1. gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

安装rvm:

  1. \curl -sSL https://get.rvm.io | bash -s stable

此时发现有报错:
在这里插入图片描述
这是因为nss版本过低导致,升级nss版本:yum -y update nss,再次执行上一步命令安装成功。

查找rvm配置文件: find / -name rvm.sh ,返回路径为:/etc/profile.d/rvm.sh。

使配置文件生效:source /etc/profile.d/rvm.sh

下载rvm依赖:rvm requirements

查看rvm库Ruby版本:rvm list known,如下图所示:
在这里插入图片描述
选择指定版本进行安装:rvm install ruby-2.5.3
安装后有提示:在这里插入图片描述
查看/usr/local/rvm/log/1551880376_ruby-2.5.3/rubygems.install.log,里边有如下提示:
在这里插入图片描述
此时需要使用rvm install ruby-2.5.3 --rubygems ignore命令来安装。安装成功:
在这里插入图片描述

设置ruby默认版本:rvm use 2.5.3 default
最后,安装Redis依赖:gem install redis

3.解压安装redis
两台服务器上均执行如下操作:
(1)上传下载好的redis安装包redis-5.0.3.tar.gz到/instal目录下,执行命令tar -zxvf redis-5.0.3.tar.gz解压文件;
(2)将解压好的文件复制到规划好的安装位置cp -r redis-5.0.3 /usr/local/redis_cluster
(3)在/usr/local/redis_cluster目录下执行以下命令进行安装:

  1. make MALLOC=libc
  2. make install

安装期间会遇到的问题可参考:https://blog.csdn.net/m0_37674755/article/details/88094197 编译安装部分。
4.配置集群
两台服务器上均执行如下操作:
(1)在/usr/local/redis_cluster下创建cluster_config文件夹:mkdir cluster_config
(2)主节点cluster_config目录下创建7001,7002,7003三个文件夹,从节点cluster_config下面创建8001,8002,8003三个文件夹,用于存放各redis节点的配置文件。
(3)将集群安装目录/usr/local/redis_cluster下的redis.conf分别向cluster_config下的7001,7002,7003,8001,8002,8003文件夹中复制一份。
(4)修改刚才复制好的redis.conf文件,主要修改如下配置(以7001节点为例):
port 7001:按照集群规划修改为各自监听的端口号:
在这里插入图片描述
cluster-enabled yes:开启集群
在这里插入图片描述
cluster-config-file nodes-7001.conf:集群节点的配置文件
在这里插入图片描述
bind 0.0.0.0:绑定主机地址,修改为0.0.0.0表示允许外部访问
在这里插入图片描述
daemonize yes:允许后台运行
在这里插入图片描述
requirepass 123456:开启密码认证,密码为123456
在这里插入图片描述
masterauth 123456:从机登录主机需要认证,密码123456
在这里插入图片描述
protected-mode no:已经设置了密码认证,此处关闭保护模式
在这里插入图片描述
(5)6个节点均配置完成后,分别进入到两台服务器的/usr/local/redis_cluster/目录下,分别启动6个redis实例:

  1. redis-server ./cluster_config/7001/redis.conf
  2. redis-server ./cluster_config/7002/redis.conf
  3. redis-server ./cluster_config/7003/redis.conf
  4. redis-server ./cluster_config/8001/redis.conf
  5. redis-server ./cluster_config/8002/redis.conf
  6. redis-server ./cluster_config/8003/redis.conf

检查redis实例是否启动:ps -ef|grep 700ps -ef|grep 800
在这里插入图片描述
在这里插入图片描述
(6)执行命令创建Redis集群
redis5.0之前的版本使用redis-trib.rb创建,执行如下命令:

  1. cd /usr/local/redis_cluster/src/
  2. cp redis-trib.rb ../cluster_config/
  3. redis-trib.rb create --replicas 1 192.168.72.129:7001 192.168.72.129:7002 192.168.72.129:7003 192.168.72.130:8001 192.168.72.130:8002 192.168.72.130:8003

redis5.0之后的版本使用redis-cli方式创建,执行如下命令:

  1. cd /usr/local/redis_cluster/src/
  2. ./redis-cli --cluster create --cluster-replicas 1 -a 123456 192.168.72.129:7001 192.168.72.129:7002 192.168.72.129:7003 192.168.72.130:8001 192.168.72.130:8002 192.168.72.130:8003

其中cluster-replicas 1表示每个主节点的slave数量,同时由于开启了密码认证,所以携带参数-a 123456进行认证,此时可能有报错:
在这里插入图片描述
这是因为两台机器之间redis实例的端口不通的缘故,设置防火墙,开放每个redis实例的端口7001,7002,7003,8001,8002,8003,同时还应该开启集群总线端口,集群总线的端口是redis实例端口号上加10000,即17001,17002,17003,18001,18002,18003然后再次执行上面的命令,出现如下提示,输入yes后创建成功。
在这里插入图片描述
在这里插入图片描述
从成功的提示信息可以看到,使用6个节点搭建的集群,redis自己分配了三个节点作为主节点,另外三个作为从节点,如id为5bca5aa06864b3fe60b191c4a1ecb638d3abc7d1的slave实例对应的master节点id为94cab328ab66b4f04f6bfcb3d67880538cbead83。

注:有时候会碰到输完yes后提示“Waiting for the cluster to join”,然后一直等待的情况,这时候首先应该检查集群总线端口是否开通,如果已经开通,可以分别登录各个节点,输入meet <本实例ip> <本实例端口>来尝试。

5.测试集群
(1)测试集群存放数据:
随便登录一个节点的实例,如登录7001这个端口监听的实例,使用命令:redis-cli -a 123456 -p 7001 -c登录。
执行set name zhangsan存入一个key=name,value=zhangsan的字符串:
在这里插入图片描述
可以看到,name这个key的计算后取余数为5798,故而name这个key存入了5798这个槽位,对应8001这个节点。
(2)测试查询数据
重新登录另外一个节点,如7003节点:redis-cli -a 123456 -p 7003 -c,执行查询命令:get name
在这里插入图片描述
可以看到,获取数据的时候,redis也是对name这个key进行计算,最终结果为5798这个槽位号,对应于8001这个节点,从该节点获取数据来展示。
通过以上两个存放,查询数据的实例,我们可以很清楚地看到,redis集群的工作原理,它不同于redis单点,redis主从那样将全部数据放到一个实例中,redis集群中的数据是分片散布在各个节点上的,当发送数据存取命令时,redis按照计算结果确定对哪一个槽位号对应的节点进行操作。集群分散了redis的压力,节点互通保证了数据共享。
(3)测试某一个主节点宕机的情况
如有redis集群中的两个节点,使用info replication命令查看7003为master节点,而8001节点为其slave节点:
7003节点:
8002节点:
8001节点:
在这里插入图片描述
然后获取已经存放在7003节点的数据:
在这里插入图片描述
这时候我们停止7003这个master节点,然后登录集群中的另外一个几点,继续获取该值,同样会有返回值123456,这时候登录8001节点,查看主从状态:
在这里插入图片描述
发现8001节点已经由原先的slave变成了master,这时候再启动7003节点,然后再查看8001节点的主从状态,发现多了一个salve节点。
由此我们可以看出来,当集群中的某个master节点宕机的时候,如果继续发生对该节点的存取数据操作,其对应的salve节点会主动切换为master节点,来保证业务进行。当之前宕机的master节点恢复后,它会主动作为现在master节点的slave。

三、springboot整合redis集群

1.添加依赖

  1. <dependency>
  2. <groupId>redis.clients</groupId>
  3. <artifactId>jedis</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.data</groupId>
  7. <artifactId>spring-data-redis</artifactId>
  8. <version>2.0.9.RELEASE</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.apache.commons</groupId>
  12. <artifactId>commons-pool2</artifactId>
  13. <version>2.5.0</version>
  14. </dependency>

2.配置集群信息
在application.yml中进行如下配置:

  1. #redis集群配置
  2. redis:
  3. cluster:
  4. ports_1:
  5. - 7001
  6. - 7002
  7. - 7003
  8. ports_2:
  9. - 8001
  10. - 8002
  11. - 8003
  12. host_1: 192.168.72.129
  13. host_2: 192.168.72.130
  14. password: 123456
  15. poolConfig:
  16. max-total: 8
  17. max-idle: 8
  18. max-waitmillis: -1
  19. min-idle: 0

3.编写redis集群配置类

  1. package com.fix.config;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.data.redis.connection.RedisClusterConfiguration;
  6. import org.springframework.data.redis.connection.RedisNode;
  7. import org.springframework.data.redis.connection.RedisPassword;
  8. import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
  9. import org.springframework.data.redis.core.RedisTemplate;
  10. import org.springframework.data.redis.core.StringRedisTemplate;
  11. import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
  12. import org.springframework.data.redis.serializer.StringRedisSerializer;
  13. import redis.clients.jedis.JedisPoolConfig;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. /**
  17. * redis集群配置
  18. */
  19. @Configuration
  20. @ConfigurationProperties(prefix = "redis.cluster")
  21. public class RedisClusterConfig {
  22. private List<Integer> ports_1;
  23. private List<Integer> ports_2;
  24. private String host_1;
  25. private String host_2;
  26. private String password;
  27. private JedisPoolConfig poolConfig;
  28. @Bean
  29. public RedisClusterConfiguration getRedisClusterConfiguration(){
  30. RedisClusterConfiguration configuration=new RedisClusterConfiguration();
  31. configuration.setPassword(RedisPassword.of(password));
  32. List<RedisNode> nodes=new ArrayList<>();
  33. for (Integer integer : ports_1) {
  34. nodes.add(new RedisNode(host_1,integer));
  35. }
  36. for (Integer integer : ports_2) {
  37. nodes.add(new RedisNode(host_2,integer));
  38. }
  39. configuration.setClusterNodes(nodes);
  40. return configuration;
  41. }
  42. /**
  43. * 配置使用rediscluster配置jedis连接工厂
  44. * @return
  45. */
  46. @Bean
  47. public JedisConnectionFactory getJedisConnectionFactory(){
  48. JedisConnectionFactory factory=new JedisConnectionFactory(getRedisClusterConfiguration(),poolConfig);
  49. return factory;
  50. }
  51. /**
  52. * 配置RedisTemplate的key,value的序列化方式
  53. */
  54. @Bean
  55. public RedisTemplate getRedisTemplate(){
  56. RedisTemplate redisTemplate=new RedisTemplate();
  57. redisTemplate.setConnectionFactory(getJedisConnectionFactory());
  58. redisTemplate.setKeySerializer(new StringRedisSerializer());
  59. redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
  60. return redisTemplate;
  61. }
  62. /**
  63. * 配置StringRedisTemplate的key,value序列化方式
  64. */
  65. @Bean
  66. public StringRedisTemplate getStringRedisTemplate(){
  67. StringRedisTemplate stringRedisTemplate=new StringRedisTemplate(getJedisConnectionFactory());
  68. stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
  69. stringRedisTemplate.setValueSerializer(new StringRedisSerializer());
  70. return stringRedisTemplate;
  71. }
  72. //getter ,setter
  73. }

4.编写controller测试
创建User实体类,需要实现Serializable 接口:

  1. public class User implements Serializable {
  2. private Long id;
  3. private String name;
  4. private Byte sex;
  5. private String phone;
  6. private Byte age;
  7. private Boolean status;
  8. private String address;
  9. //getter,setter
  10. }

创建RedisTestController:

  1. @RestController
  2. @RequestMapping("/test/redis")
  3. public class RedisTestController {
  4. @Autowired
  5. RedisTemplate redisTemplate;
  6. @Autowired
  7. StringRedisTemplate stringRedisTemplate;
  8. @GetMapping("/cluster")
  9. public void testCluster(){
  10. //stringRedisTemplate存取值
  11. ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
  12. stringStringValueOperations.set("testKey","testVlaue");
  13. System.out.println(stringStringValueOperations.get("testKey"));
  14. //redisTemplate存取值
  15. User user=new User();
  16. user.setId(1L);
  17. user.setName("张三");
  18. user.setSex((byte)3);
  19. user.setAge((byte)20);
  20. user.setPhone("111111111");
  21. ValueOperations valueOperations = redisTemplate.opsForValue();
  22. valueOperations.set("user",user);
  23. System.out.println(valueOperations.get("user"));
  24. }
  25. }

启动springboot应用,访问 https://localhost:8081/test/redis/cluster , 查看控制台输出日志:
在这里插入图片描述
说明springboot整合redis已经成功。

发表评论

表情:
评论列表 (有 0 条评论,442人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringBoot整合redis

    一:缓存的应用场景 1:什么是缓存? 在互联网场景下,尤其 2C 端大流量场景下,需要将一些经常展现和不会频繁变更的数据,存放在存取速率更快的地方。缓存就是一个存储器,在技

    相关 springboot整合redis

    一、redis集群原理 redis集群中的所有节点彼此互联,节点内部采用二进制协议优化传输速度和带宽,每个节点都可以与Java客户端连接。redis集群的数据分配采用哈希