Redis集群(Cluster)演示——超详细演示步骤+Spring Boot演练

在这里插入图片描述
本文所用的Redis是5.0.8所以和旧版的4.0.X不同的地方在于创建集群的方式的变化

所用系统:Centos7.7 64位

本文设置的统一密码为:shunleite

Spring Boot 2.0+

一、集群的原理

在Redis集群中,所有的Redis节点彼此互联,节点内部使用的二进制协议优化传输速度和带宽。

当一个节点挂掉后,集群中超过半数的节点坚持失效时才认为该节点已失效。Redis集群中的任意

节点都以和Java客户端连接。Redis集群上的数据分配是才用哈希槽(HASH SLOT),Redis集群内置

了16384个哈希槽,当有数据需要储存时,Redis会首先使用CRC16算法对Key进行计算,将计算获得

的结果对16384取余,这样每一个key都会对应一个取值在0~16383之间的哈希槽,Redis则根据这个

余数将该条数据储存到对应的Redis节点上,程序猿们就可根据每个Redis实例的性能来调整每个Redis

实例上哈希槽的分布范围

二、分布式集群规划

需要了解一些概念:
一个master(主)可以拥有多个slave(从),而一个slave(从)只能拥有一个master(主)
另外官方说明每个集群中至少需要三个主master才能正常运行
本案例采取每个服务器上对应的每个端口来区别每一个不同的Redis服务器

主节点:111.67.194.61:6661,111.67.194.60:6662,111.67.194.63:6663

从节点:111.67.194.64:6664,111.67.194.65:6665,111.67.202.207:6666

两个用来测试添加主从数据库的节点: 111.67.194.70:6667(主),111.67.194.108:6668(从)

三、Redis集群配置环节

1.安装集群管理工具(集群老大哥服务器111.67.194.61由它配置Ruby环境,也只在这台)

因为Redis集群工具依赖Ruby环境,首先需要安装Ruby环境,又因为centos7 yum库中
的默认的Ruby版本太低,所以就搞个便捷的RVM工具(以下步骤是下载配置rvm公钥)

gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
#上面个木有成功就下面那个
gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -L get.rvm.io | bash -s stable
source /usr/local/rvm/scripts/rvm

看下RVM是否安装成功

rvm list known

如图所示出现了绿色那就成功了
在这里插入图片描述
选个比较稳定的版本安(教程所出时间为2020/4/5)
在这里插入图片描述

rvm install 2.6.5

在这里插入图片描述
最后安装Redia依赖

gem install redis

2.安装Redis:

①下载Redis

wget http://download.redis.io/releases/redis-5.0.8.tar.gz

没有wget命令的话就需要安装,然后再执行上面命令

yum install wget

②安装Redis
先创建个redisCluster文件夹,将下载的文件移动过去然后再安装

mkdir redisCluster
cp -f ./redis-5.0.8.tar.gz ./redisCluster
cd redisCluster
tar -zxvf redis-5.0.8.tar.gz
cd redis-5.0.8
make MALLOC=libc
make install

③其它每台各进行第②小步(该操作是每个服务器都必须要的操作)

然后在每台服务器(包括老大哥服务器111.67.194.61)的redisCluster下创建一个文件夹(以便于生产后面在单台上添加)
分别为文件夹6661 6662 6663 6664 6665 6666 (与前面规划部分一致)
另外每个文件夹下面都需要把上层目录中redis-5.0.8目录下的redis.conf文件复制一份到该目录

cp -f ../redis-5.0.8/redis.conf ./

接着对每台服务器666x文件夹下的redis.conf的配置进行修改,所修改的配置如下(是修改不是添加)

port 6661
#bind 127.0.0.1
cluster-enabled yes
cluster-config-file nodes-6661.conf
protected no
daemonize yes
requirepass shunleite
masterrauth shunleite

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
提一下:如果使用vi的话那你就需要/字符串模式慢慢找然后修改

    第一为该节点端口与文件夹名一一对应

    第二行是将bind部分注释掉,因为默认是本地乱接,注释掉就可以外网连接Redis了

    第三行表示开启集群

    第四行表示该集群节点的配置文件(注意nodes-666x.conf格式配置方便管理)

    第五行就是关闭保护毕竟你第七行用了密码

    第六行表示允许Redis后台运行

    第七行就是设置密码了

    第八行因为第七行设置了密码所以他就需要个密码认证

④开启Redis实例

redis-server /root/redisCluster/6661/redis.conf
redis-server /root/redisCluster/6662/redis.conf
redis-server /root/redisCluster/6663/redis.conf
redis-server /root/redisCluster/6664/redis.conf
redis-server /root/redisCluster/6665/redis.conf
redis-server /root/redisCluster/6666/redis.conf

⑤为了能够远程连接上Redis,还需要关闭防火墙(或者开启相应端口)

systemctl stop firewalld.service
systemctl disable firewalld.service

在这里插入图片描述
回到老大哥服务器(111.67.194.61)后切到redisCluster目录下

3.创建集群(该步骤在老大哥服务器运行)

    提一下:因为设置了密码,一般来说,Redis5.0.x以下的版本是需要将redis-trib.rb文件复制到redisCluster目录下的

    然而我们用的不是(嘻嘻)如果是就需要移

    而且还需修改复制后的redis-trib.rb文件,将@r = Redis.new(:host => @info[:host], :port => @info[:port], :timeout => 60)这行

    修改成@r = Redis.new(:host => @info[:host], :port => @info[:port], :timeout => 60, :password=>"shunleite")

    然后操作就把后面的redis-cli -a shunleite --cluster的部分改成./redis-trib.rb(在你redisCluster目录下)即可(虽然有些细微的不一样比如删除啥

    子,但大多一样,毕竟官方只是进行移植集成操作)

创建集群

redis-cli -a shunleite --cluster create 111.67.194.61:6661 111.67.194.60:6662 111.67.194.63:6663 111.67.194.64:6664 111.67.194.65:6665 111.67.202.207:6666 --cluster-replicas 1

replicas表示每个主节点的salve数量。集群在创建过程中都将分配到一个唯一的id并分配一段slot
成功效果如下:M代码主节点,S代码从节点,slots就是分配的slot段,replicates后面的Id代表所对应的主节点Id
在这里插入图片描述
在这里插入图片描述

-h 表示实例主机地址 -p表示登陆的集群的端口,-a表示要登陆的集群的密码,-c则便是以集群的方式登陆,登陆成功后随便登陆一个节点

使用cluster nodes命令查询集群节点的信息,cluster info命令查询集群状态信息,此时你会发现已经自动配置好了slot
redis-cli -h 111.67.194.61 -p 6661 -a shunleite -c
cluster info
cluster nodes

在这里插入图片描述

四、Redis集群主节点和从节点的增加与删除

1.主节点增加

业务增长的情况下,我们避免不了增加主节点,增加主节点也就是构建主节点实例
①按Redis集群配置环节中的第2个步骤的②与③,④,⑤小步骤的模子在 111.67.194.70的节点上创建文件夹6667(配置

和上面步骤一样,这里就不演示了)
②开启Redis也一样模子:redis-server /root/redisCluster/6667/redis.conf
③接着登陆到老大哥服务器(111.67.194.61)执行添加节点操作,add-node就是添加节点的操作,中间的参数是要添加的Redis

实例地址,最后一个参数是集群中的实例地址

redis-cli -a shunleite --cluster add-node  111.67.194.70:6667 111.67.194.61:6661

在这里插入图片描述
登陆任意集群中的实例,执行cluster nodes就会发现实例地址已经添加成功,但是slot没有分配,注意节点的6667的node ID。

    此新节点的ID为:d35877f5646c96fdfce71bdf66f588e8c90fd520

在这里插入图片描述
④重新分配下slot(本案例给新增主节点分配1000个slot)

因为之前的操作已经将slot分配完了,所以导致没有slot分配给新节点,也就是书新节点没有储存数据的机会,所以我们可以
另外三个主节点中拿出一部分分配给新节点实例,我这里总共分配1000个slot给新节点

如果是把n个的slot分配给谁,输入接收这n个slot的Redis实例的ID,这个ID添加的时候就可以看到,或者登陆进集群控制器后
使用上面的clustern nodes命令也可以看到。例如从端口为6661的实例拿出n个slot分给6667的实例,那么输入6661的id后按回
车键,在输入done按返回键即可

登陆老大哥服务器(111.67.194.61)执行如下代码重新分配,all表示均摊原来原有的实例

redis-cli -a shunleite --cluster reshard 111.67.194.61:6661
#接着填入1000
#在填写节点的ID
#填入all

在这里插入图片描述
平摊后:
在这里插入图片描述

2.从节点增加

从节点的增加就容易很多了

①还是按Redis集群配置环节中的第2个步骤的②与③,④,⑤小步骤的模子在 111.67.194.108的节点上创建文件夹6668然后

启动它

②登陆老大哥服务器(111.67.194.61)添加从节点需要指定该解答你的master id,–cluster-master-id后面的参数依次表示:

从节点master(主节点)的id(这里是以6667为例子),从节点的地址,集群中任意一个实例的地址。代码如下:

redis-cli -a shunleite --cluster add-node --cluster-slave --cluster-master-id d35877f5646c96fdfce71bdf66f588e8c90fd520 111.67.194.108:6668 111.67.194.61:6661

登陆集群控制器后输入cluster nodes便可以看到了
在这里插入图片描述
5.0.x以下版本的Redis增加新从节点需要在redisCluster目录下使用如下命令增加子节点(命令意思和上面基本一致):

./redis-trib.rb add-node --slave --master-id d35877f5646c96fdfce71bdf66f588e8c90fd520 111.67.194.108:6668 111.67.194.61:6661

3.节点删除

删除节点登录到老大哥服务器(111.67.194.61)使用如下命令模子删除即可:

del-node代表删除节点,后面的参数就是要删除的节点,如果删除的节点占有slot,则会删除失败,那么你按照第四大步骤

Redis集群主节点和从节点的增加与删除第1步骤中第④小步将要删除节点的全部slot分配出去,然后执行该命令即可,从节点

直接该命令即可删

redis-cli -a shunleite --cluster del-node 111.67.194.61:6661

五、Spring Boot案例演示

不同于单实例的Redis,Redis集群整合Spring Boot需要程序猿们手动配置

1.配置依赖

jedis连接池是基于apache.commons-pool2实现的,在侯建连接池对象时,需要提供连接池对象的配置对象,即JedisPoolConfig,

JedisPoolConfig继承自GenericObjectPoolConfig,我们可以通过这个配置对象对连接池进行相关参数的配置(如最大连接数,

最大空闲数等)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </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>
</dependency>

2.配置集群信息(application.yml)

此时使用application.yml就方便很多,所以就直接删除原来的application.properties,新建它了

因为使用的host很多,所以就创建两个一一对应的数组即可,也方便生产中后续增删节点的操作

max-total代表连接池最大连接数,max-idle代表连接池中最大空闲连接数, max-wait-millis表示最大阻塞等待时间,默认为-1

表示没有限制,min-idle表示连接池最小连接数

spring:
  redis:
    cluster:
      ports:
        - 6661
        - 6662
        - 6663
        - 6664
        - 6665
        - 6666
        - 6667
        - 6668
      hosts:
        - 111.67.194.61
        - 111.67.194.60
        - 111.67.194.63
        - 111.67.194.64
        - 111.67.194.65
        - 111.67.202.207
        - 111.67.194.70
        - 111.67.194.108
      poolConfig:
        max-total: 8
        max-idle: 8
        max-wait-millis: -1
        min-idle: 0

3.配置Redis创建RedisConfig

我们来分析一下

在SpringBoot的自动配置类中提供了RedisAutoConfiguration进行Redis的配置,源码如下:
**加粗样式**
这一段源码可以看出,默认的application.properties中的配置信息将被注入RedisProperties中,如果没有提供RedisTemplate或者

StringRedisTemplate实例,那么Spring Boot默认会提供这两个实例,RedisTemplate和StringRedisTemplate都提供了Redis的

基本操作
在这里插入图片描述
由于本案例使用的是Jedis,再加上JedisConnectionFactory继承自RedisConnection

所以我们需要手动配置与提供Redis集群配置,JedisConnectionFactory,RedisTemplate,StringRedisTemplate。

@Configuration
//通过ConfigurationProperties注解声明配置文件前缀,配置文件中定义的ports,hosts数组及连接配置信息都将被注入port、host、poolConfig三个属性中
@ConfigurationProperties("spring.redis.cluster")
public class RedisConfig {
    List<Integer> ports;
    List<String> hosts;
    JedisPoolConfig poolConfig;
    //配置RedisClusterConfiguration实例,设置Redis登陆密码以及Redis节点信息
    @Bean
    RedisClusterConfiguration redisClusterConfiguration(){
        RedisClusterConfiguration configuration = new RedisClusterConfiguration();
        List<RedisNode> nodes = new ArrayList<>();
        for(int i = 0;i<ports.size();i++){
            nodes.add(new RedisNode(hosts.get(i),ports.get(i)));
        }
        //配置RedisClusterConfiguration实例,摄制Redis登陆密码以及Redis节点信息
        configuration.setPassword(RedisPassword.of("shunleite"));
        configuration.setClusterNodes(nodes);
        return configuration;
    }
    //根据RedisClusterConfiguration实例以及连接池配置信息Jedis连接工厂JedisConnectionFactory
    @Bean
    JedisConnectionFactory jedisConnectionFactory(){
        JedisConnectionFactory factory = new JedisConnectionFactory(redisClusterConfiguration(),poolConfig);
        return factory;
    }
    //根据RedisConnectionFactory创建RedisTemplate和StringRedisTemplate,同时配置key和value的系列化方式。
    // 有了RedisTemplate和StringRedisTemplate,剩下的用法就和单一使用Redis用法一致
    @Bean
    RedisTemplate redisTemplate(){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate;
    }
    @Bean
    StringRedisTemplate stringRedisTemplate(){
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(jedisConnectionFactory());
        stringRedisTemplate.setKeySerializer(new StringRedisSerializer());
        stringRedisTemplate.setValueSerializer(new StringRedisSerializer());
        return stringRedisTemplate;
    }
 
    @Override
    public String toString() {
        return "RedisConfig{" +
                "ports=" + ports +
                ", hosts=" + hosts +
                ", poolConfig=" + poolConfig +
                '}';
    }
 
    public List<Integer> getPorts() {
        return ports;
    }
 
    public void setPorts(List<Integer> ports) {
        this.ports = ports;
    }
 
    public List<String> getHosts() {
        return hosts;
    }
 
    public void setHosts(List<String> hosts) {
        this.hosts = hosts;
    }
 
    public JedisPoolConfig getPoolConfig() {
        return poolConfig;
    }
 
    public void setPoolConfig(JedisPoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }
}

4.创建实体类

public class Customer implements Serializable {
    private String name;
    private String email;
 
    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
}

5.创建Controller(直接测试,就演示一下怎么使用)

StringRedisTemplate是RedisTemplate子类,StringRedisTemplate中的key和value都是字符串,采用的

系列化方案是StringRedisSerializer,而RedisTemplate则可以用来操作对象,RedisTemplate采用的序列化

方案是JdkSerializationRedisSerializer。无论是StringRedisTemplate还是RedisTemplater,操作Redis的方法都一样

StringRedisTemplate和RedisTemplate都是通过opsForValue,opsForZSet或者opsForSet等方法首先获取一个操作对象,

再使用该操作对象完成数据的读写

@RestController
public class CustomerController {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @GetMapping("/test1")
    public void test1(){
        ValueOperations ops = redisTemplate.opsForValue();
        Customer customer = new Customer();
        customer.setName("shunzi");
        customer.setEmail("[email protected]");
        ops.set("customer",customer);
        System.out.println("customer = " + ops.get("customer"));
        ValueOperations<String,String> ops2 = stringRedisTemplate.opsForValue();
        ops2.set("ceshi","数据正确");
        System.out.println("ceshi = " + ops2.get("ceshi"));
    }
}

6.输入127.0.0.1:8080/test1测试一下

在这里插入图片描述

7.登陆任意Redis服务器实例,查询数据看下查询结果

get customer
get ceshi

在这里插入图片描述
RedisCluster会很负责的将查询请求Redirected到相应的实例上去。

教程很长,细节地方很多,所以耐心看完后再实践一遍。☺

差点忘了,下面提供有案例源码

百度网盘:https://pan.baidu.com/s/17pNKWjfu_Fb70_x12m5ckQ (snet)

普通的下载:http://t.cn/A6Z1r6tG

蓝奏云:https://lanzous.com/ib1ip9e

发布了1 篇原创文章 · 获赞 0 · 访问量 7

猜你喜欢

转载自blog.csdn.net/shunleite/article/details/105669237