spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成

第九章 Redis-Cluster集群搭建及系统集成

本系列博客旨在搭建一套能用于实际开发使用的spring cloud多模块微服务项目框架,并不是一个spring cloud的demo而已,提供系统的开发规范限制,微服务注册中心,配置中心,负载均衡,熔断,redis缓存,分布式事务,kafka服务消息通信,系统安全(sql注入攻击,xxs攻击等等),多数据源切换,全局异常处理等等。

 目录顺风车:

spring cloud多模块项目框架搭建 :https://blog.csdn.net/lingyancangqiong/article/details/109841353

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第1张图片

本章接着上章《spring cloud多模块项目框架搭建-集成Redis连接客户端及连接池Lettuce》来说,搭建Redis-Cluster模式高可用集群示例,并在本系统中用Lettuce连接池连接。

一.Redis主从模式,哨兵模式,Redis-Cluster模式三种Redis集群模式的区别?

1.什么是redis主从模式?

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第2张图片

 redis主从集群分为一主一从,一主多从,级联三种模式,级联就是一主(master)多从(slave),从节点再有多个从节点,主节点可以有多个从节点,但从节点只能有一个主节点。主要实现读写分离,容灾恢复。一台服务器通过执行slaveof命令或设置slaveof选项,复制同步到另一个服务器,就形成了主从集群,被复制的叫做master主节点,复制的成为slave从节点。问题是当master节点挂了,整个集群就无法写入了,但还是能slave节点读取,这时需要手动将一台slave节点使用slaveof no one提升为master。

        spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第3张图片

实现原理步骤:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器收到SYNC命令后,执行BGSAVE命令,在后台生成RDB文件,使用缓冲区记录从现在开始执行的所有的写命令。
  3. 当主服务器的BGSAVE命令执行完毕后,主服务器后将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

2.  什么是哨兵模式(Sentinel)?

上面说到主从模式当主节点挂了之后,需要人为的切换,这就无法达到高可用;于是哨兵模式(Sentinel)应运而生,可以抠字眼,当主节点挂了,由Sentinel像个哨兵一样自动的发现并根据配置规则提升一个slave节点为新的master节点,是redis主从的模式的高可用解决方案,一般的中小型系统中对内存存储数量不多的情况下使用较多,但是Sentinel本身也可能挂掉,实际使用中Sentinel也会集群。

实现原理步骤:

  1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令
  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 Sentinel(哨兵)进程标记为主观下线SDOWN
  3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有
    Sentinel(哨兵)
    进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
  4. 有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  5. 在一般情况下, 每个Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
  8. 当master节点被下线以后,再次上线,将不再是master节点,变成slave节点中的一员。

3.什么是Redis-Cluster模式?

高可用Redis(十二):Redis Cluster,什么是Redis-Cluster模式及实现原理?可以看看这位大神的这篇讲解,讲的非常到位。总结来讲,Redis-Cluster翻译就是redis集群嘛,实现了去中心化,不在依赖于主节点,而是将存储的key通过hash值运算平均分配已知的节点上,每个节点的权重是一样的,同时每个节点都至少有一个备用节点(主节点、备份节点由redis-cluster集群确定),当主节点挂了,备份节点之一自动补上,你在使用时也无需去寻找你的key存在哪个节点上,你只要查询集群其中一个节点,Redis-Cluster会自动去寻找在哪个节点并返回数据。Redis-Cluster模式主要用于分布式和对内存容量有要求的大型系统中,在我看来他还是主从,只是拆成了多个组,高可用实现的优雅了许多,可以理解为主从是普通版,哨兵为plus版,Cluster模式为pro版。

二.  搭建Redis-Cluster集群

 集群中至少应该有2n+1(n不为0)奇数个节点,所以至少有三个节点,每个节点至少有一个备份节点,所以下面使用6节点(主节点、备份节点由redis-cluster集群确定),由于没有6台服务器,我们示例就在一台服务器上开6个端口,作为集群的6个节点。为了方便日常开发,文末也提供了windows版本的集群下载。


  1. 下载redis,并上传到服务器,编译安装,我下载的是最新的redis

[root@VM-0-15-centos redis-3.2.0]# tar xzf redis-6.0.9.tar.gz
[root@VM-0-15-centos redis-3.2.0]# cd redis-6.0.9
[root@VM-0-15-centos redis-3.2.0]# make
[root@VM-0-15-centos redis01]# make install PREFIX=/usr/andy/redis-cluster

make 这里可能报错:erver.c:4511:19: error: ‘struct redisServer’ has no member named ‘stat_total_writes_processed’,参考这位老兄的博客解决:https://blog.csdn.net/qq_45069833/article/details/108762535

2. 在/usr/andy/redis-cluster下 ,创建目录7000 7001 7002 7003 7004 7005共6个目录,复制解压目录下的redis.conf配置文件到/usr/andy/redis-cluster下,再复制到刚才创建的这六个文件下,并在最后追加如下内容,把原内容的protected-mode yes改为protected-mode no(在没有密码的情况下,关闭保护模式),把daemonize no改为daemonize yes   (是否为进程守护,关闭ssh窗口后即是否在后台继续运行),注释掉bind 127.0.0.1 (取消绑定本地地址)或者改成bind 0.0.0.0

        daemonize yes #后台启动
        port 7000 #修改端口号,从7000到7005
        cluster-enabled yes #开启cluster,去掉注释
        cluster-config-file nodes.conf #自动生成
        cluster-node-timeout 15000 #节点通信时间
        appendonly yes #持久化方式

这里中文注释可能报错,去掉即可,这里命令就是基本的vi,就不写了,不会的同学自行问度娘。

3.复制redis解压文件src下的redis-trib.rb文件到/usr/andy/redis-cluster目录并安装gem

[root@VM-0-15-centos redis-cluster]# gem install redis

这里可能报这两个错:1. bash: gem: command not found    和  2. ERROR: Could not find a valid gem 'redis' (>= 0) in any repository ,这是因为ruby 版本太低,遇到错,就要勇于解决,不要害怕,恐惧报错,这也是我近两年才学会,以前一报错就是求爹爹告奶奶,或者逃避去选择其他的实现方法,现在养成解决bug的习惯后,除了一些问题很耗时间外,其他一般的问题好好思考,勇于解决还是不难的。

解决办法:

[root@VM-0-15-centos redis-cluster]# yum install -y ruby 
[root@VM-0-15-centos redis-cluster]# yum install -y rubygems
[root@VM-0-15-centos redis-cluster]# echo "source $HOME/.rvm/scripts/rvm" >> ~/.bash_profile
[root@VM-0-15-centos redis-cluster]#
[root@VM-0-15-centos redis-cluster]#

再次执行gem又报错:Error installing redis: redis requires Ruby version >= 2.3.0 ,解决方案:先安装rvm,再把ruby版本提升至2.6.5

[root@VM-0-15-centos redis-cluster]# yum install curl
[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable
[root@VM-0-15-centos redis-cluster]# 
[root@VM-0-15-centos redis-cluster]# 

到这步有可能报错,第一次在腾讯云安然无事,这是我第二次在阿里云搭的时候报的:curl: (7) Failed connect to raw.githubusercontent.com:443; Connection refused ,原因是被墙了,解决如下:

 修改hosts

[root@VM-0-15-centos redis-cluster]# vi /etc/hosts

末尾添加如下内容:

199.232.28.133 raw.githubusercontent.com

然后接着上面来再次执行

[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable

这里注意看提示,它有可能像下面这样提示你用密钥下载

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第4张图片

这里先执行下它提示的这个密钥命令,再把上面的curl命令执行下,就会发现执行成功了。

[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable
[root@VM-0-15-centos redis-cluster]# source /usr/local/rvm/scripts/rvm

 查看ruby版本,有很多版本

[root@VM-0-15-centos redis-cluster]# rvm list known

安装一个ruby版本,我安装的2.6.5,这里安装要很久,慢慢等着吧

[root@VM-0-15-centos redis-cluster]# rvm install 2.6.5

使用一个ruby版本

[root@VM-0-15-centos redis-cluster]# rvm use 2.6.5

设置默认版本

[root@VM-0-15-centos redis-cluster]# ruby --version

卸载一个已知版本

[root@VM-0-15-centos redis-cluster]# rvm remove 2.0.0

 再次gem安装,ok了

[root@VM-0-15-centos redis-cluster]# gem install redis
Successfully installed redis-4.2.5
Parsing documentation for redis-4.2.5
Done installing documentation for redis after 0 seconds
1 gem installed
[root@VM-0-15-centos redis-cluster]#

4. 在/usr/andy/redis-cluster下创建并编写启动文件start.sh,内容如下:

cd 7000
redis-server redis.conf
cd ..
cd 7001
redis-server redis.conf
cd ..
cd 7002
redis-server redis.conf
cd ..
cd 7003
redis-server redis.conf
cd ..
cd 7004
redis-server redis.conf
cd ..
cd 7005
redis-server redis.conf
cd ..

5.  设置权限,并启动:chmod 777是设置所有人可以读 + 写 + 执行。

[root@VM-0-15-centos redis-cluster]# chmod 777 start.sh 
[root@VM-0-15-centos redis-cluster]# sh start-all.sh 

这里可能会报错,原因:这是因为在系统的/usr/bin目录下没有命令文件

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第5张图片

解决办法:将redis-cluster/bin目录下的redis-server、redis-cli、redis-benchmark、redis-check-aof、redis-check-rdb、redis-sentinel这些可执行文件复制到/usr/bin下

[root@VM-0-15-centos redis-cluster]#  ls
7000  7001  7002  7003  7004  7005  bin  redis.conf  redis-trib.rb  start.sh
[root@VM-0-15-centos redis-cluster]#  cd bin
[root@VM-0-15-centos bin]#  ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server
[root@VM-0-15-centos bin]#  cp redis-benchmark /usr/bin
[root@VM-0-15-centos bin]#  cp redis-check-aof /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-check-rdb /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-cli /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-sentinel /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-server /usr/bin/
[root@VM-0-15-centos bin]#  

6. 再次执行sh脚本

[root@VM-0-15-centos bin]# cd ..
[root@VM-0-15-centos redis-cluster]# ls
7000  7001  7002  7003  7004  7005  bin  redis.conf  redis-trib.rb  start.sh
[root@VM-0-15-centos redis-cluster]# sh start.sh 

7.  查看redis启动的情况,可以看到redis的6个节点已经启动成功

[root@VM-0-15-centos redis-cluster]# ps -ef|grep cluster
root      54956      1  0 19:17 ?        00:00:00 redis-server *:7000 [cluster]
root      54961      1  0 19:17 ?        00:00:00 redis-server *:7001 [cluster]
root      54966      1  0 19:17 ?        00:00:00 redis-server *:7002 [cluster]
root      54971      1  0 19:17 ?        00:00:00 redis-server *:7003 [cluster]
root      54976      1  0 19:17 ?        00:00:00 redis-server *:7004 [cluster]
root      54981      1  0 19:17 ?        00:00:00 redis-server *:7005 [cluster]
root      55071  24089  0 19:24 pts/0    00:00:00 grep --color=auto cluster

8.  使用redis-cli命令创建集群,以前使用的./redis-trib.rb create已经废弃了,这里ip 127.0.0.1最好是改成你的服务器ip

[root@VM-0-15-centos redis-cluster]# redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7000
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 2730
Master[1] -> Slots 2731 - 5460
Master[2] -> Slots 5461 - 8191
Master[3] -> Slots 8192 - 10922
Master[4] -> Slots 10923 - 13652
Master[5] -> Slots 13653 - 16383
M: ff5bae64ce3aa0ee89f3d8813b155b45ff97788a 127.0.0.1:7001
   slots:[0-2730] (2731 slots) master
M: 634c92d72d4a657102583f6ff81e46e9aaf8bc6f 127.0.0.1:7002
   slots:[2731-5460] (2730 slots) master
M: 691743965bd6a300ffe84740077797cefc403f67 127.0.0.1:7003
   slots:[5461-8191] (2731 slots) master
M: 0a099c363e9e9cadb83f1215658ee01b2645c7dc 127.0.0.1:7004
   slots:[8192-10922] (2731 slots) master
M: ea521ddcdef20d0fc924d4e862035a7232456c75 127.0.0.1:7000
   slots:[10923-13652] (2730 slots) master
M: 8386f6314894649b15463c72d44f2b05d752f798 127.0.0.1:7005
   slots:[13653-16383] (2731 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: ff5bae64ce3aa0ee89f3d8813b155b45ff97788a 127.0.0.1:7001
   slots:[0-2730] (2731 slots) master
M: 0a099c363e9e9cadb83f1215658ee01b2645c7dc 127.0.0.1:7004
   slots:[8192-10922] (2731 slots) master
M: 8386f6314894649b15463c72d44f2b05d752f798 127.0.0.1:7000
   slots:[13653-16383] (2731 slots) master
M: 634c92d72d4a657102583f6ff81e46e9aaf8bc6f 127.0.0.1:7002
   slots:[2731-5460] (2730 slots) master
M: 691743965bd6a300ffe84740077797cefc403f67 127.0.0.1:7003
   slots:[5461-8191] (2731 slots) master
M: ea521ddcdef20d0fc924d4e862035a7232456c75 127.0.0.1:7005
   slots:[10923-13652] (2730 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

至此集群就搭建好了,测试下

[root@VM-0-15-centos redis-cluster]# redis-cli -c -p 7001
127.0.0.1:7001> set name 11
-> Redirected to slot [5798] located at 127.0.0.1:7003
OK
127.0.0.1:7003> get name
"11"
127.0.0.1:7003> 

二,系统集成Lettuce客户端及连接池

1. 我们还是在第八章《spring cloud多模块项目框架搭建-集成Redis连接客户端及连接池Lettuce》的代码基础上进行集成,将dream.order.web和dream.activity.web下的application.yml里的redis的配置改成如下即可.

 redis:
    database: 2
    cluster:
      refresh:
        adaptive: true
        period: 30000
      nodes:
        - 192.168.10.185:7001
        - 192.168.10.185:7002
        - 192.168.10.185:7003
        - 192.168.10.185:7004
        - 192.168.10.185:7005
        - 192.168.10.185:7000
      max-redirects: 3 # 获取失败 最大重定向次数
    timeout: 6000ms  # 连接超时时长(毫秒)
    lettuce:
      pool:
        max-active: 100  # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms      # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 10      # 连接池中的最大空闲连接
        min-idle: 1       # 连接池中的最小空闲连接
        timeout: 6000ms

#设置lettuce日志输出级别,输出的日志太多了
logging:
  config: classpath:log4j2.xml
  level:
    io.lettuce.core: info

2.  将dream父模块的jar 包版本升级为如下,之前的低版本使用的Lettuce会出现连接池拓扑图不自动刷新,连接超时问题。

   
        org.springframework.boot
        spring-boot-starter-parent
        2.3.7.RELEASE
         
    

        1.8
        UTF-8
        2.3.7.RELEASE
        2.3.7.RELEASE
        2.3.7.RELEASE
        2.2.5.RELEASE
        8.0.19
        3.4.0
        1.18.16
        1.2.3
        2.3.5.RELEASE
        2.0.0-alpha1
        2.4.0
        2.8.1
    

3. 将dream.order.common和dream.activity.common下的RedisConfig分别改成如下:


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * redis配置
 *
 * @AutoConfigureAfter(RedisAutoConfiguration.class) 是让我们这个配置类在内置的配置类之后在配置,
 * 

* 这样就保证我们的配置类生效,并且不会被覆盖配置 选择性配置 * @Author: renkj * @Version 1.0.0 */ @Component @Configuration @EnableCaching @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig extends CachingConfigurerSupport { @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuffer sb = new StringBuffer(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * 配置自定义redisTemplate * * @return */ @Bean RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.activateDefaultTyping( LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY); serializer.setObjectMapper(mapper); template.setValueSerializer(serializer); //使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } }

4. 用第八章redis的测试代码测试下,完美的取到了值,第一次请求会有点慢,应该是进行初始化,第二次之后就很快了。

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成_第6张图片

 

到此Redis-Cluster集群搭建及系统集成就完成了,为了方便在本地开发使用,我也搭建了一套windows版的Redis-Cluster集群,包括启动脚本都放在csdn资源(https://download.csdn.net/download/lingyancangqiong/13701164)了,下载下来按使用说明修改下启动脚本盘符路径,双击启动脚本就能使用了。本章更新的有些久了,原因是两周前我的电脑硬盘坏了,在jd买的才用了五个月,这两周一直在扯皮和维权,后面实在等不了,自己买了个固态换上。坏掉的固态客服连型号都不知道,拆下一看生产厂家,批次,日期,型号啥也没有,京东处理的也比较消极,到今日也没个初步处理结果,每次都是升级专员处理,京东再也不是当年那个绝无假货的京东了。

 

本章代码我放在了蓝奏云,可以下载下来对照对照:  (https://wws.lanzous.com/b01hweach 密码:2vx3 )

 

上面所写内容如有不足和纰漏,欢迎留言或私聊指正批评。如果需要转载,也是欢迎,不甚荣幸,但请把《spring cloud多模块项目框架搭建》这一系列博客全部一起转载,这一系列博客毕竟是个整体教程,如果别人只看到一部分,那就是个残次品,谢谢,鞠躬。

你可能感兴趣的:(spring,cloud,多模块框架搭建教程,redis,spring,cloud,分布式,软件框架)