(十五)Spring Boot NoSQL【Redis集群环境搭建】

一、Linux 安装Redis 单机版

   官网下载地址:http://download.redis.io/releases/
在这里插入图片描述

  1. 解压 Redis 源码安装包:tar -zxvf redis-6.2.0.tar.gz
  2. 进入目录:cd redis-6.2.0.tar.gz
  3. 编译前确认操作系统已经安装gcc,如果没有安装 gcc 会报错,安装gcc:yum install -y gcc tcl gcc-c++ make
  4. 编译:make && make install
    Alt
  5. 启动:
    ·······前台启动:redis-server
    ·······后台启动:vi redis.conf
    a.首先设置Redis密码,不设置密码可能导致无法连接,requirepass 123456 #指定密码123456
    在这里插入图片描述
    b.注释掉redis.conf的 bind 127.0.0.1
    在这里插入图片描述
    c.设置为后台启动
    在这里插入图片描述
    d.保护模式禁用
    在这里插入图片描述
    e.带配置文件启动方式:redis-server redis.conf
    f. 查看redis是否启动成功并远程连接: ps -ef|grep redis
    在这里插入图片描述
    在这里插入图片描述

一、搭建 Redis 集群

1.1 集群原理

        在Redis 集群中,所有的 Redis 节点彼此互联,节点内部使用二进制协议优化传输速度和带宽。当一个节点挂掉后,集群中超过半数的节点检测失效时才认为该节点己失效。 不同 Tomcat 集群需要使用反向代理服务器, Redis 集群中的任意节点都可以直接和 Java 客户端连接。 Redis 集群上的数据分配则是采用哈希槽(HASH SLOT) , Redis 集群中内置了 16384 个哈希槽,当有数据需要存储时, Redis 会首先使用 CRC16 算法对 key 进行,将计算获得的结果对 16384 取余,这样每一个 key 都会对应一个取值在 0~16383 之间的哈希槽, Redis 则根据这个余数将该条数据存储到对应的 Redis 节点上,开发者可根据每个 Redis 实例的性能来调整每 Redis 实例上哈希槽的分布范围。

1.2 集群规划

        本案例在同一台服务器上用不同的端口表示不同的 Redis 服务器( 伪分布式集群)。
        主节点 10.211.55.6:8001,10.211.55.6:8002,10.211.55.6:8003。
        从节点 10.211.55.6:8004,10.211.55.6:8005,10.211.55.6:8006。

1.3 集群配置

# 创建一个存放redis集群的配置文件夹
mkdir redis-cluster
# 将redis的安装压缩包拷贝到 redis-cluster 文件夹中
cp redis-6.2.0.tar.gz redis-clust/
# 解压并安装 redis
tar -zxvf redis-6.2.0.tar.gz
cd redis-6.2.0/
make && make install
# 在redis-cluster 文件夹中分别创建以下文件夹,用来存放每个节点的配置文件
mkdir redis-8001
mkdir redis-8002
mkdir redis-8003
mkdir redis-8004
mkdir redis-8005
mkdir redis-8006
# 从刚刚已安装的 redis 中拷贝 redis.conf
cp redis.conf ../redis-clust/redis-8001/
cp redis.conf ../redis-clust/redis-8002/
cp redis.conf ../redis-clust/redis-8003/
cp redis.conf ../redis-clust/redis-8004/
cp redis.conf ../redis-clust/redis-8005/
cp redis.conf ../redis-clust/redis-8006/
# 分别修改每个节点下的配置文件,例如8001端口,其他配置文件修改成对应端口即可
port 8001 
#bind 127.0.0.1 
cluster-enabled yes 
cluster-config-file nodes-8001.conf
protected no 
daemonize yes 
requirepass 123456
masterauth 123456
这里的配置在单机版安装配置的基础上增加了几条,其中端口修改为 8001,cluster-enabled 表示开启集群,cluster-config-file 表示集群节点的配置文件,由于每个节点都开启了密码认证,因此又增加了 masterauth 配置,使得从机可以登录到主机上 。按照这里的配置,对8001~ 8006 目录中的 redis.conf 文件依次进行修改,注意修改时每个文件的 port、cluster-config-file。

小提示:配置文件 redis.conf 中内容过多,可以通过 vi redis.conf 命令进入编辑窗口,在使用 /prot 模糊匹配要修改的位置,通过键盘 n 查找下一处,再次按键盘i即可在指定位置进行编辑操作。

全部修改完成后,进入 redis-6.2.0/ 录下,分 启动 Redis 实例,相关命令如下:

redis-server ../redis-8001/redis.conf
redis-server ../redis-8002/redis.conf
redis-server ../redis-8003/redis.conf
redis-server ../redis-8004/redis.conf
redis-server ../redis-8005/redis.conf
redis-server ../redis-8006/redis.conf

由于一个一个启动太麻烦了,所以我在/redis-clust目录下创建一个批量启动redis节点的脚本文件,命令为./start-redis-all.sh,文件内容如下:

cd redis-6.2.0/
redis-server ../redis-8001/redis.conf
redis-server ../redis-8002/redis.conf
redis-server ../redis-8003/redis.conf
redis-server ../redis-8004/redis.conf
redis-server ../redis-8005/redis.conf
redis-server ../redis-8006/redis.conf

创建好启动脚本文件之后,需要修改该脚本的权限,使之能够执行,指令如下:chmod +x start-redis-all.sh
通过命令./start-redis-all.sh 执行脚本并查看是否启动成功:
在这里插入图片描述
在这里插入图片描述

http://rvm.io/
        Redis集群管理工具 redis-trib. rb依赖Ruby环境,首先需要安装Ruby环境,由于 Centos 7 yum库中默认的Ruby版本较低,因此建议采用如下步骤进行安装
        首先安装RVM,RVM是一个命令行工具,可以提供一个便捷的多版本Ruby环境的管理和切换,安装命令如下:

gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
curl -L get.rvm.io | bash -s stable
source /usr/local/rvm/scripts/rvm

最后一条命令表示安装完后使RVM名生效,RVM安装成功后,查看RWM中有哪些Ruby

rvm list known

       上一步中6个redis节点启动成功,接下来正式开启搭建集群,以上都是准备条件。大家不要觉得图片多看起来冗长所以觉得麻烦,其实以上步骤也就一句话的事情:创建6个redis实例(6个节点)并启动。 要搭建集群的话,需要使用一个工具(脚本文件),这个工具在redis解压文件的源代码里。因为这个工具是一个ruby脚本文件,所以这个工具的运行需要ruby的运行环境,就相当于java语言的运行需要在jvm上。所以需要安装ruby,指令如下:

  1. Ruby在线安装
yum install ruby
  1. Ruby离线安装,可以直接去官网地址进行下载安装,这里可以通过此链接:https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.4.tar.gz直接下载我这里使用的版本,以下是参考官网源代码安装的 Ruby命令

在这里插入图片描述

./configure
make
sudo make install

1.4 创建集群

  1. 将该ruby工具(redis-trib.rb)复制到redis-cluster目录下,指令如下:
    cp redis-6.2.0/src/redis-trib.rb /software/redis/redis-clust/
    在这里插入图片描述
  2. 执行如下命令创建 Redis 集群
./redis-trib.rb create --replicas 1 10.211.55.6:8001 10.211.55.6:8002 10.211.55.6:8003 10.211.55.6:8004 10.211.55.6:8005 10.211.55.6:8006

在这里插入图片描述
执行完毕后提示:redis-trib.rb is not longer available!该方式已淘汰不可用了,建议使用redis cli方式创建集群,所以在这里估计也可以不用安装ruby了,根据提示执行相关命令:
在这里插入图片描述如果加了密码,那么创建集群时就需要加-a 123456参数,不然会出现上图错误。
创建主从集群命令,后面是集群的ip地址和端口,cluster-replicas 1表示一个主节点对应1个从节点,创建成功后会自动分配主从关系。

redis-cli --cluster create 10.211.55.6:8001 10.211.55.6:8002 10.211.55.6:8003 10.211.55.6:8004 10.211.55.6:8005 10.211.55.6:8006 --cluster-replicas 1 -a 123456

在这里插入图片描述
在这里插入图片描述

  1. Redis 集群当集群创建成功后,登陆 redis-8001~8006中任意实例,命令如下: redis-cli -p 8001 -a 123456 -c
-p 表示要登录的集群的端口 ,
-a 表示要登录集群的密码,
-c 表示以集群的方式登录。登录成功后 ,通过 clust info 命令可以查询集群状态信息(如图 6- 所示),通过 cluster nodes 命令可以查询集群节点信息(如图 -6 所示〉,在集群节点信息中,可以看到每一个节点的 id ,该节点是slave还是master ,如果是 slave ,那么它的 master 的 id 是什么,如果是 master ,那么每一个 master 的 slot 范围是多少,这些信息都会显示出来

在这里插入图片描述
在这里插入图片描述

1.5 添加主节点

        当集群创建成功后,随着业务的增长,有可能需要添加主节点,添加主节点需要先构建主节点实例,将 redis-cluster 目录下的 8001 目录再复制一份,名为8007 ,根据1.3集群配置修改步骤修改redis.conf文件,修改完成后启动该节点。

[root@admin redis-6.2.0]# redis-server ../redis-8007/redis.conf 

在这里插入图片描述

        启动成功后,进入 redis-cluster/ 目录下,执行如下命令将该节点添加到集群中:

redis-cli -c -a 123456 --cluster add-node 10.211.55.6:8007 10.211.55.6:8001

在这里插入图片描述

        登录任意Redis 实例,查看集群节点信息,就可以看到该实例己经被添加进集群了,如下图:

在这里插入图片描述
        从上图可以看到,新实例己经被添加进集群中,但是由于 slot 已经被之前的实例分配完了,新添加的实例没有 slot ,也就意味着新添加的实例没有存储数据的机会,此时需要从另外一个实例中拿出一部分 slot 分配给新实例,具体操作如下。

  1. 首先,在 redis-cluer 目录下执行如下命令对 slot 重新分配
# 对集群进行重新分片,为新添加的节点分配槽
redis-cli -c -a 123456 --cluster reshard 10.211.55.6:8001

在这里插入图片描述
在这里插入图片描述

· 第一个配置是要拿出多少个 slot 分配给新实例,本案例配置了 1000 个。
· 第二个是把拿出来的 1000 个 slot 分配给谁,输入接收这 1000 个 slot 的Redis 实例的 id ,这个 id 在节点添加成功后就可以看到,也可以进入集群控制台后利用 cluster nodes 命令查看。
· 第三个配置是这 1000 个 slot 哪个实例出,例如从端口为 8001 实例中拿出 1000 给端口为 8007 的实例,那么这里输入 8001 的 id 后按回车键,输入 done 接回车键即可,如果想将 1000 个 slot 均摊到原有的所有实例中,那么这里输入 all 按回车键即可。
· slot 分配成功后,再次查看节点信息,就可以看到新实例也有 slot 了,如图下所示
  1. 再次查看节点信息

在这里插入图片描述

1.6 添加从节点

        首先将 redis-cluster 目录下的 8001 目录复制一份,命名为 8008 ,然后按照 1.3 节中集群配置修改 8008 录下的 redis.conf,修改完成后,启动该实例,然后输入如下命令添加从节点
在这里插入图片描述

redis-cli -c -a 123456 --cluster add-node 10.211.55.6:8008 10.211.55.6:8001 --cluster-slave --cluster-master-id 4fea0ca214f64e0439524676ab68fd793979649e

在这里插入图片描述

添加从节点需要指定该从节点的 masterid,--cluster-master-id 后面的参数即表示该从节点 master 的 id,10.211.55.6:8008 表示从节点的地址, 10.211.55.6:8001 表示集群中任意一个实例的地址,当从节点添加成功后,登录集群中任意 Redis 实例, 通过 cluster nodes 命令就可以看到从节点的信息,如下图所示。

在这里插入图片描述

1.7 删除节点

        可以通过--cluster del-node子命令移除一个从节点,第一个参数是集群任意一个节点,第二个参数是要删除的节点id。同样也能够通过该命令删除一个主节点,但要删除主节点,它必须为空,如果主节点不为空需要将其数据分片到其他主节点,或对其进行故障转移,将其变为新主节点的从节点之后,再执行删除。

redis-cli -c -a 123456 --cluster del-node 10.211.55.6:8008 c7a80099cb30060b3dc8479f008102d104a75561

在这里插入图片描述

二、配置 Spring Boot

2.1 创建Spring Boot 项目

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

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2.2 配置集群信息

        由于集群节点有多个,可以保存在一个集合中,因此这里的配置文件使用 YAML 格式的,修改resources 目录下的 application.properties 文件为 application.yml 配置文件。

spring:
  redis:
    cluster:
      ports:
        - 8001
        - 8002
        - 8003
        - 8004
        - 8005
        - 8006
        - 8007
      host: 10.211.55.6
      poolConfig:
        max-total: 8
        max-idle: 8
        max-wait-millis: -1
        min-idle: 0

2.3 配置 Redis

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.RedisConnectionFactory;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

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

@Configuration
@ConfigurationProperties("spring.redis.cluster")
public class RedisConfig {
    List<Integer> ports;
    String host;
    JedisPoolConfig poolConfig;

    @Bean
    RedisClusterConfiguration redisClusterConfiguration() {
        RedisClusterConfiguration configuration = new RedisClusterConfiguration();
        List<RedisNode> nodes = new ArrayList<>();
        for (Integer port : ports) {
            nodes.add(new RedisNode(host, port));
        }
        configuration.setPassword(RedisPassword.of("123456"));
        configuration.setClusterNodes(nodes);
        return configuration;
    }

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory(redisClusterConfiguration(), poolConfig);
    }

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setConnectionFactory(jedisConnectionFactory());
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

//    @Bean
//    RedisTemplate redisTemplate() {
//        RedisTemplate redisTemplate = new RedisTemplate();
//        redisTemplate.setConnectionFactory(jedisConnectionFactory());
//        redisTemplate.setKeySerializer(new StringRedisSerializer());
//        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
//        return redisTemplate;
//    }

    @Bean
    StringRedisTemplate stringRedisTemplate() {
        StringRedisTemplate stringRedsTemplate = new StringRedisTemplate(jedisConnectionFactory());
        stringRedsTemplate.setKeySerializer(new StringRedisSerializer());
        stringRedsTemplate.setKeySerializer(new StringRedisSerializer());
        return stringRedsTemplate;
    }

    public List<Integer> getPorts() {
        return ports;
    }

    public void setPorts(List<Integer> ports) {
        this.ports = ports;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public JedisPoolConfig getPoolConfig() {
        return poolConfig;
    }

    public void setPoolConfig(JedisPoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }
}

2.4 创建Controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.Serializable;

@RestController
public class TestController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @GetMapping("test")
    public void test() {
        Book book = new Book();
        book.setName("西游记");
        book.setAuthor("吴曾恩");
        redisTemplate.opsForValue().set("b1", book.toString());
        String str = (String) redisTemplate.opsForValue().get("b1");
        System.out.println(str);
        ValueOperations<String, String> ops2 = stringRedisTemplate.opsForValue();
        ops2.set("k1", "v1");
        System.out.println(ops2.get("k1"));
    }


    class Book implements Serializable {
        String name;
        String author;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAuthor() {
            return author;
        }

        public void setAuthor(String author) {
            this.author = author;
        }

        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }
    }
}

2.5 测试

最后 在浏览器中输入 http://localhost:8080/test ,控制台打印日志如图所示。
2-5-1

然后登录任意一个 Red 实例,查询数据,结果如图所示。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值