Redis集群模式搭建

标签: Redis 分类: 后台服务 创建时间:2021-05-31 02:04:02 更新时间:2023-10-20 11:23:26

1.需求分析

为了配置高可用,我对编写的springboot进行了多份虚拟机部署,使用nginx的upstream进行了ip_hash负载均衡策略,搭建了集群。在springboot程序中,有操作redis的环节,电脑显示二维码,手机扫码登录,因为使用了ip_hash模式,所以在同一个ip访问的时候,谁扫码了,那么缓存就保存在当前服务器上,同一个ip访问的时候轮询进行验证是否登录也没有问题,但是如果一个使用有线网pc端,用手机的无线扫码,就会造成扫码处理的程序和验证登录的程序提供服务的节点不在同一个服务器上,造成了即便手机扫码后写入了redis,但是轮询验证的时候,还是找不到这个redis,于是我就想到了如何进行redis的集群搭建。

redis集群的三种模式:主从复制模式Sentinel;(哨兵)模式;Cluster 模式;搭建集群,主要的就是Cluster模式,也就是说,数据分散到多态服务器上,随便连接一台服务器,都可以取到集群中的任何一个数据。

参考文章:
1.Redis集群的原理和搭建
2.【Redis】redis集群搭建(非常详细,适合新手) V2 (在一台虚拟机上启动了6个redis实例,然后使用官方提供的redis-trib.rb脚本,进行集群的搭建,写的挺详细的,也有配图)
3.Redisson的使用
4.SpringBoot系列教程之Redis集群环境配置
5.[Redis] 你了解 Redis 的三种集群模式吗? redis集群的三种模式:主从复制模式Sentinel;(哨兵)模式;Cluster 模式,并对各种模式搭建进行了说明。
6.Redis 创建和使用集群(yum方式安装低版本) 使用yum方式安装的redis,也可以创建集群,其实原理都差不多的,就是复制多份实例,然后复制配置文件,使用Redis 5 cli自带的./redis-cli –cluster,加上参数启动多个实例,构建成集群就可以了。

1.安装

这一步我就不详细的说明了,只需要执行yum安装就可以了。我主要搭建了三台虚拟机,内网ip分别是192.168.1.85,192.168.1.86,192.168.1.87,每台服务器上我准备启动两个redis示例,这样就构成了6个节点,就可以组成了集群。

2.配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
## 端口号
port 6380
## 是否作为守护进程运行
daemonize yes
## 打开redis集群
cluster-enabled yes
## 集群配置文件,启动自动生成,不用人为干涉
cluster-config-file nodes.conf
## 节点互联超时时间,毫秒
cluster-node-timeout 15000
## 可用数据库数,默认是16,默认数据存储在DB 0号ID库中
databases 16

## 启用aof持久化,因为redis本身同步数据文件是按照上面save条件来同步的,所以有的数据会在一段时间存在于内存中,默认值为no
appendonly yes
## 根据参考文章中的描述,bind的ip地址,应该是本机网卡地址,而不是需要监听的地址,我的网卡有192.168.1.85这个ip于是我就使用了这个ip
bind 192.168.1.85 127.0.0.1

## 如果以后台进程运行,则需要指定一个pid,默认为/var/run/redis.pid
pidfile /usr/local/redis-cluster/6380/redis.pid

## 数据存储目录
dir /usr/local/redis-cluster/6380
## 数据迁移的副本临界数,这个参数表示的是,一个主节点在拥有多少个好的从节点时候就要割让一个从节点出来给另外一个没有任何从节点的主节点
cluster-migration-barrier 1
## 如果某一些key space没有被集群中任何节点覆盖,集群将停止接受写入
cluster-require-full-coverage yes
参考文章:
1.搭建redis集群发现对Redis的bind的误区 关于为什么绑定0.0.0.0无法启动redis的问题探索,说明了这个bind操作的用途

3.复制文件

根据我的集群配置,我85,86,87这三台服务器上,都使用6380和6381这两个端口,

1
2
3
4
5
6
7
8
9
10
11
## 创建文件夹
mkdir /usr/local/redis-cluster
mkdir /usr/local/redis-cluster/6380 /usr/local/redis-cluster/7001 /home/redis-cluster/6380
## 复制服务启动程序
cp -a /usr/bin/redis-server /usr/local/redis-cluster/

## 将编辑好的配置文件,复制到相应的目录中,
## 我只需要创建一份配置文件,复制六份,然后修改其中的端口号和bind的ip地址就可以了
## 然后上传到对应服务器的相应目录下
cp -a redis.conf /usr/local/redis-cluster/6380/
cp -a redis.conf /usr/local/redis-cluster/6381/

4.启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 在每台服务器上6380和6381端口上启动实例
/usr/local/redis-cluster/redis-server /usr/local/redis-cluster/6380/redis-85-6380.conf
/usr/local/redis-cluster/redis-server /usr/local/redis-cluster/6381/redis-85-6381.conf

## 查看启动端口
netstat -tunlp | grep redis

## 因为我的redis是5.0.3版本,所以脚本自带了集群启动方式,不需要安装ruby和gemo启动程序
cp -a /usr/bin/redis-cli /usr/local/redis-cluster/

## 在任意一台服务器上,启动集群
## --cluster-replicas 1 表示为每一个主服务器配一个从服务器。
./redis-cli --cluster create 192.168.1.85:6380 192.168.1.85:6381 192.168.1.86:6380 192.168.1.86:6381 192.168.1.87:6380 192.168.1.87:6381 --cluster-replicas 1

## 节点加入到集群中,cluster meet命令,这条命令我还没有测试过,应该是集群启动之后,继续增加节点的配置
redis-cli -p 6379 cluster meet 127.0.0.1 6380

输入一个yes之后,最后成功启动了redis集群

参考文章:
1.Redis之——Redis 集群的安装(Redis+CentOS) 这里还有使用ruby和geom的方式启动集群的,我这里不需要
2.深入理解Redis Cluster 这里还有很多的参数,还有Failover的流程、客户端ASK重定向流程
3.Redis 集群教程 –cluster-replicas 参数的解释
4.Redis集群增加节点和删除节点 这个有点老了,使用的是redis-trib.rb脚本
5.redis 5.0中使用 redis-cli 添加cluster node 并 reshard 这是5.x版本的增加和收缩节点,感觉很复杂
6.Redis Cluster日常操作命令梳理 下线,上线,基本的命令等

5.关闭

逐个关闭redis实例进程即可

1
2
3
4
5
6
7
## 查看进程id
ps -ef | grep redis
## 关闭进程
kill -9 10252 10257 10262 10267 10272 10294

##也可执行以下命令来关闭redis进程
pkill -9 redis

6.测试集群

在任意一台服务器上,启动客户端,使用set命令设置值,然后在另一台服务器上,登录,使用get命令查看这个值

1
2
3
4
## 集群启动客户端
redis-cli -c -p 6380
## 设置值
set dd ddd
参考文章:
1.Redis集群性能测试工具redis-benchmark Redis-benchmark官方提供的工具,进行性能测试
2.redis及集群性能测试
3.看完还不会搭建高性能的Redis集群,小丑就是我! 文章没有具体的操作,但是对于相关的概念,都进行了形象生动的描述,也提供了思维导图进行数模,比如:数据快照,数据持久化以及,主从复制:多副本,哨兵:故障自动切换,分片集群:横向扩展。
4.redis集群节点宕机

7.问题

(1) (error) MOVED 原因和解决方案

1
2
## 启动集群时需要加入-c参数
redis-cli -c -p 7000

(2) ‘always-show-logo yes’ Bad directive or wrong number of arguments
注释掉这一行

(3) ‘replica-serve-stale-data yes’ Bad directive or wrong number of arguments
这个问题和上一个问题是一样的,其实都是redis版本问题。在服务器里安装了两个版本的redis,/usr/bin/redis-server的版本非常的低,/usr/local/redis里面的版本比较高,选择正确的版本启动就可以了。

1
2
## 查看版本
./redis-server -v
参考文章:
1.Redis启动报错: Bad directive or wrong number of arguments 这里指出了是版本问题,使用正确的版本可以避免问题

8.springboot配置

我使用的springboot版本是2.3.1.RELEASE,使用的Redis版本是5.0.3,使用了RedisTemplate进行操作,配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
redis:
cluster:
nodes: 192.168.1.85:6380,192.168.1.85:6381,192.168.1.86:6380,192.168.1.86:6381,192.168.1.87:6380,192.168.1.87:6381
database: 0
jedis:
pool:
#最大连接数
max-active: 1000
#连接池最大等待时间
max-wait: 1000ms
#最大空闲数
max-idle: 50
#最小空闲
min-idle: 0

RedisUtil内容如下,也挺简单,和单机的时候一样操作,集群会自动处理的,到底存储到哪里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.bibichuan.phemsjava.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
* redis操作工具类.</br>
* (基于RedisTemplate)
*
*/
@Component
public class RedisUtils {
private final static Logger logger= LoggerFactory.getLogger(RedisUtils.class);
@Autowired
private RedisTemplate<String,String> redisTemplate;
/**
* 读取缓存
*
* @param key
* @return
*/
public String get(final String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
*/
public boolean set(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
logger.error("RedisUtils.set",e);
}
return result;
}
/**
* 删除缓存
*/
public boolean delete(final String key) {
boolean result = false;
try {
redisTemplate.delete(key);
result = true;
} catch (Exception e) {
e.printStackTrace();
logger.error("RedisUtils.delete",e);
}
return result;
}
}
参考文章:
1.SpringBoot整合Redis集群 使用SpringBoot 1.5.8.RELEASE版本整合Redis 4.0.11,实现Redis Pool操作Redis集群,版本太老了。
2.SpringBoot 2.1.x整合Redis Cluster集群配置相关示例
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。