springboot整合redis集群

一、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:

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

安装rvm:

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

此时发现有报错:
springboot整合redis集群_第1张图片
这是因为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,如下图所示:
springboot整合redis集群_第2张图片
选择指定版本进行安装: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命令来安装。安装成功:
springboot整合redis集群_第3张图片

设置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目录下执行以下命令进行安装:

make MALLOC=libc
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:已经设置了密码认证,此处关闭保护模式
springboot整合redis集群_第4张图片
(5)6个节点均配置完成后,分别进入到两台服务器的/usr/local/redis_cluster/目录下,分别启动6个redis实例:

redis-server ./cluster_config/7001/redis.conf
redis-server ./cluster_config/7002/redis.conf
redis-server ./cluster_config/7003/redis.conf
redis-server ./cluster_config/8001/redis.conf
redis-server ./cluster_config/8002/redis.conf
redis-server ./cluster_config/8003/redis.conf

检查redis实例是否启动:ps -ef|grep 700ps -ef|grep 800
springboot整合redis集群_第5张图片
springboot整合redis集群_第6张图片
(6)执行命令创建Redis集群
redis5.0之前的版本使用redis-trib.rb创建,执行如下命令:

cd /usr/local/redis_cluster/src/
cp redis-trib.rb ../cluster_config/ 
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方式创建,执行如下命令:

 cd /usr/local/redis_cluster/src/
 ./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后创建成功。
springboot整合redis集群_第7张图片
springboot整合redis集群_第8张图片
从成功的提示信息可以看到,使用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节点:
springboot整合redis集群_第9张图片
8001节点:
springboot整合redis集群_第10张图片
然后获取已经存放在7003节点的数据:
在这里插入图片描述
这时候我们停止7003这个master节点,然后登录集群中的另外一个几点,继续获取该值,同样会有返回值123456,这时候登录8001节点,查看主从状态:
springboot整合redis集群_第11张图片
发现8001节点已经由原先的slave变成了master,这时候再启动7003节点,然后再查看8001节点的主从状态,发现多了一个salve节点。
由此我们可以看出来,当集群中的某个master节点宕机的时候,如果继续发生对该节点的存取数据操作,其对应的salve节点会主动切换为master节点,来保证业务进行。当之前宕机的master节点恢复后,它会主动作为现在master节点的slave。

三、springboot整合redis集群

1.添加依赖

    
        redis.clients
        jedis
    
    
        org.springframework.data
        spring-data-redis
        2.0.9.RELEASE
    
    
        org.apache.commons
        commons-pool2
        2.5.0
    

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

 #redis集群配置
redis:
  cluster:
    ports_1:
      - 7001
      - 7002
      - 7003
    ports_2:
      - 8001
      - 8002
      - 8003
    host_1: 192.168.72.129
    host_2: 192.168.72.130
    password: 123456
    poolConfig:
      max-total: 8
      max-idle: 8
      max-waitmillis: -1
      min-idle: 0

3.编写redis集群配置类

package com.fix.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * redis集群配置
 */
@Configuration
@ConfigurationProperties(prefix = "redis.cluster")
public class RedisClusterConfig {
    private List ports_1;
    private List ports_2;
    private String host_1;
    private String host_2;
    private String password;
    private JedisPoolConfig poolConfig;
    @Bean
    public RedisClusterConfiguration getRedisClusterConfiguration(){
        RedisClusterConfiguration configuration=new RedisClusterConfiguration();
        configuration.setPassword(RedisPassword.of(password));
        List nodes=new ArrayList<>();
        for (Integer integer : ports_1) {
            nodes.add(new RedisNode(host_1,integer));
        }
        for (Integer integer : ports_2) {
            nodes.add(new RedisNode(host_2,integer));
        }
        configuration.setClusterNodes(nodes);
        return configuration;
    }

    /**
     * 配置使用rediscluster配置jedis连接工厂
     * @return
     */
    @Bean
    public JedisConnectionFactory getJedisConnectionFactory(){
        JedisConnectionFactory factory=new JedisConnectionFactory(getRedisClusterConfiguration(),poolConfig);
        return factory;
    }

    /**
     * 配置RedisTemplate的key,value的序列化方式
     */
    @Bean
    public RedisTemplate getRedisTemplate(){
        RedisTemplate redisTemplate=new RedisTemplate();
        redisTemplate.setConnectionFactory(getJedisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate;
    }

    /**
     * 配置StringRedisTemplate的key,value序列化方式
     */
    @Bean
    public StringRedisTemplate getStringRedisTemplate(){
        StringRedisTemplate stringRedisTemplate=new StringRedisTemplate(getJedisConnectionFactory());
        stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
        stringRedisTemplate.setValueSerializer(new StringRedisSerializer());
        return stringRedisTemplate;
    }

   //getter ,setter
}

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

public class User implements Serializable {
    private Long id;
    private String name;
    private Byte sex;
    private String phone;
    private Byte age;
    private Boolean status;
    private String address;
    //getter,setter
    }

创建RedisTestController:

@RestController
@RequestMapping("/test/redis")
public class RedisTestController {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @GetMapping("/cluster")
    public void testCluster(){
        //stringRedisTemplate存取值
        ValueOperations stringStringValueOperations = stringRedisTemplate.opsForValue();
        stringStringValueOperations.set("testKey","testVlaue");
        System.out.println(stringStringValueOperations.get("testKey"));

        //redisTemplate存取值
        User user=new User();
        user.setId(1L);
        user.setName("张三");
        user.setSex((byte)3);
        user.setAge((byte)20);
        user.setPhone("111111111");
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("user",user);
        System.out.println(valueOperations.get("user"));

    }
}

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

你可能感兴趣的:(java,redis)