Redis集群
Posted 用生命研发技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis集群相关的知识,希望对你有一定的参考价值。
Redis集群
一、Redis持久化
1.1、RDB持久化
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
快照文件称为RDB文件,默认是保存在当前运行目录。
配置文件介绍
## Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000
# RDB的其它配置也可以在redis.conf文件中设置:
## 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes
## RDB文件名称
dbfilename dump.rdb
## 文件保存的路径目录
dir ./
命令
## 由redis主进程执行来执行RDB,会阻塞所有命令
save
##bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。
# fork采用的是copy-on-write技术:
# 当主进程执行读操作时,访问共享内存;
# 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
bgsave
RDB方式bgsave的基本流程
- fork主进程得到一个子进程,共享内存空间
- 子进程读取内存数据并写入新的RDB文件
- 用新RDB文件替换旧的RDB文件。
RDB会在什么时候执行
- save命令
- bgsave命令
- 服务停止时
save 60 1000代表什么含义
- 代表60秒内至少执行1000次修改则触发RDB
恢复RDB文件
- 只需要将RDB文件放在redis启动目录,redis自动检查dump.rdb恢复其中的数据
RDB的优点
- 适合大规模的数据恢复
- 对数据的完整性要求不高
RDB的缺点
- RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
- fork子进程、压缩、写出RDB文件都比较耗时
1.2、AOF持久化
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
AOF默认是关闭的,需要修改redis.conf
配置文件来开启AOF
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"
AOF的命令记录的频率也可以通过redis.conf文件来配:
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
配置项 | 刷盘时机 | 优点 | 缺点 |
---|---|---|---|
Always | 同步刷盘 | 可靠性高,几乎不丢数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最多丢失1秒数据 |
no | 操作系统控制 | 性能最好 | 可靠性较差,可能丢失大量数据 |
因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:
## AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
## AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb
AOF优点
- 每一次修改都同步,文件的完整性会更好
- 每秒同步一次,可能会丢失一秒数据
- 从不同步,效率是最高的
AOF缺点
- 相对于数据文件来说,AOF大于RDB,修复也比RDB慢
- AOF运行效率比RDB慢,所以redis默认是RDB
- AOF默认就是文件无限追加,所以文件越来越大
RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。
RDB | AOF | |
---|---|---|
持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
文件大小 | 会有压缩,文件体积小 | 记录命令,文件体积很大 |
宕机恢复速度 | 很快 | 慢 |
数据恢复优先级 | 低,因为数据完整性不如AOF | 高,因为数据完整性更高 |
系统资源占用 | 高,大量CPU和内存消耗 | 低,主要是磁盘IO资源 但AOF重写时会占用大量CPU和内存资源 |
使用场景 | 可以容忍数分钟的数据丢失,追求更快的启动速度 | 对数据安全性要求较高常见 |
二、单机部署
2.1、安装gcc依赖
由于 redis 是用 C 语言开发,安装之前必先确认是否安装 gcc 环境(gcc -v),如果没有安装,执行以下命令进行安装
## 下载安装gcc
yum install -y gcc
## 测试gcc版本
gcc --version
2.2、下载redis
方式一:官网下载
官网下载: https://redis.io/
方式二:wget下载
cd /opt/home/
## 下载
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
## 解压
tar -zxvf redis-6.2.6.tar.gz
2.3、编译、安装并指定安装目录
## 切换目录 执行编译
cd redis-6.2.6/
## 编译安装 如不指定目录 则会默认安装到 /usr/local/bin
make && make install PREFIX=/opt/home/redis
2.4、启动服务
cd /opt/home/redis/bin
## 1.启动Redis
./redis-server
# 2.停止redis服务
./redis-cli shutdown
## 3.后台启动(推荐)
# 3.1 从 redis 的源码目录中复制 redis.conf 到 redis 的安装目录
cp /opt/home/redis-6.2.6/redis.conf /opt/home/redis/bin
## 3.2 修改配置
vi redis.conf
####修改内容如下#####
## 远程访问
# 注释掉: bind 127.0.0.1 -::1
## 后台启动
#daemonize no 改为daemonize yes
## 设置密码:
# 取消注释:requirepass foobared
# 应修改为:requirepass java521
## 修改rdb文件存放路径
# 将 ./ 修改为/opt/home/redis/bin/
dir /opt/home/redis/bin/
## redis 日志文件路径
logfile "/opt/home/redis/bin/redis.log"
## 484行 当master服务设置了密码保护时 slave服务连接master的密码
# masterauth <master-password>
masterauth java521
## 3.3 执行启动命令指定配置文件就是后台启动了
./redis-server redis.conf
## 4.查看是否启动
ps -aux | grep redis
## 5 关闭redis服务
# 5.1 末设密码
./redis-cli shutdown
# 5.2 设置了密码
./redis-cli -a java521 shutdown
2.5、启动客户端
./redis-cli
## 设置密码后访问需要先输⼊密码认证通过
# auth 检测给定的密码和配置文件中的密码是否相符
auth java521
## 查看所有的key
keys *
## 设置指定 key 的值
set k1 v1
## 获取指定 key 的值
get k1
## 删除指定 key 的值
del k1
注意:
(error) NOAUTH Authentication required. 和 (error) NOAUTH Authentication required. 错误是因为没有输入密码
进入客户端输入 auth 密码
然后就可以操作了
2.6、设置开机启动
添加开机启动服务
vi /etc/systemd/system/redis.service
## 添加以下内容
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/opt/home/redis/bin/redis-server /opt/home/redis/bin/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
## 重新加载配置文件
systemctl daemon-reload
### 服务操作命令 ###
### 必须用下列命令启动才可以用下列命令关闭和查看状态 ###
## 启动redis
systemctl start redis.service
## 停止redis服务
systemctl stop redis.service
## 重新启动服务
systemctl restart redis.service
## 查看服务当前状态
systemctl status redis.service
## 设置开机自启动
systemctl enable redis.service
## 停止开机自启动
systemctl disable redis.service
三、Redis主从集群
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
默认情况下,每台reids都是主服务器,我们一般只配置从机就好了
3.1、集群结构
搭建的主从集群结构
共包含三个节点,一个主节点,两个从节点。
使用三台虚拟机分别部署redis,模拟主从集群,信息如下:
IP | PORT | 角色 |
---|---|---|
192.168.0.3 | 6379 | master |
192.168.0.4 | 6379 | slave |
192.168.0.5 | 6379 | slave |
3.2、准备实例和配置
使用单面部署的方式按照上面的方法分别部署三台服务器
3.3、开启主从关系
现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。
有临时和永久两种模式
-
修改配置文件(永久生效)
在redis.conf中添加一行配置:slaveof <masterip> <masterport>
-
使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
slaveof <masterip> <masterport>
注意:在5.0以后新增命令replicaof,与salveof效果一致。
这里我们为了演示方便,使用方式二。
通过redis-cli命令连接192.168.0.4,执行
./redis-cli -a java521 -p 6379
# 执行slaveof 或者 replicaof
slaveof 192.168.0.3 6379
replicaof 192.168.0.3 6379
通过redis-cli命令连接192.168.0.5,执行
./redis-cli -a java521 -p 6379
# 执行slaveof 或者 replicaof
slaveof 192.168.0.3 6379
replicaof 192.168.0.3 6379
通过redis-cli命令连接192.168.0.3,查看集群状态
./redis-cli -a java521 -p 6379
# 查看状态
info replication
## 发现connected_slaves:0 这是困为主节点设置了密码
# 修改两台从服务器的redis配置文件redis.conf
vi redis.conf
# 取消注释 masterauth <master-password>
# 应更改为 masterauth java521
# 重新启动服务
systemctl restart redis.service
## 因为这里用的是临时模式 所以192.168.0.4、192.168.0.5还要重新发送 执行slaveof 或者 replicaof
## 192.168.0.3查看状态
info replication
## 让当前redis服务停止接收其他redis服务的同步,同时把自己升格为主数据库。
slaveof no one
3.4、测试
执行下列操作以测试:
- 利用redis-cli连接192.168.0.3,执行
set a b
,再执行get a
- 利用redis-cli连接192.168.0.4,执行
get a
,再执行set a bb
- 利用redis-cli连接192.168.0.5,执行
get a
,再执行set a bb
可以发现,只有在192.168.0.3这个master节点上可以执行写操作,192.168.0.4和192.168.0.5这两个slave节点只能执行读操作。
四、搭建哨兵集群
主从切换的技术方法是:
当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用,这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
哨兵模式是一种特殊的模式,首先reids提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行,其原理是哨兵通过发送命令,等待redis服务器响应,从而监控运行的多个redis实例。
如果主机宕机后恢复,只能归并到新主机下,当做从机,这就是哨兵模式的规则。
优点
- 哨兵集群,基于主从复制模式,所有主从配置优点,它全有
- 主从可以切换,故障可以转移,系统的可用性就会更好
- 哨兵模式就是主从模式的升级,手动到自动,更加健壮
缺点
- redis不好在线扩容,集群容量一旦到达上限,在线扩容十分麻烦
- 实现哨兵模式的配置,其实是很麻烦的,里面有很多选择
4.1、集群结构
这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。
三个sentinel实例信息如下:
节点 | IP | PORT |
---|---|---|
s1 | 192.168.0.3 | 27001 |
s2 | 192.168.0.4 | 27001 |
s3 | 192.168.0.5 | 27001 |
4.2、添加配置
创建sentinel.conf
文件,添加下面的内容:
cp /opt/home/redis-6.2.6/sentinel.conf /opt/home/redis/bin/
cd /opt/home/redis/bin/
vi sentinel.conf
# 15行 允许所有IP访问
bind 0.0.0.0
# 17行 去掉注释
protected-mode no
## 21行 sentinel监听端口,默认是26379,可以修改
port 26379
# 26行 改为后台运行
daemonize yes
# 36行 logfile ""应改为
logfile "/opt/home/redis/bin/sentinel.log"
## 58行 当提供announce-ip时,Sentinel将在通信中声明指定的IP地址,而不是像通常那样自动检测本地地址。
sentinel announce-ip 192.168.0.3
## 65行 指定工作目录
dir "/opt/home/redis/bin"
## 84行 sentinel monitor mymaster 127.0.0.1 6379 2 应改为
sentinel monitor mymaster 192.168.0.3 6379 2
# mymaster 主节点名称 自定义
# 192.168.0.3 6379 主节点的ip和端口
# 2 选举master时的quorum值
## 86行 如果redis配置了密码,那这里必须配置认证,master和slave的密码应该设置相同
sentinel auth-pass mymaster java521
## 117行 主节点或副本在指定时间内没有回复PING,便认为该节点为主观下线 S_DOWN 状态,默认是30秒
sentinel down-after-milliseconds mymaster 5000
## 225行 指定故障转移超时(毫秒)
sentinel failover-timeout mymaster 60000
192.168.0.4 和192.168.0.5进行同样的操作
4.3、启动
分别启动3个redis实例,启动命令:
./redis-sentinel ./sentinel.conf
./redis-server ./sentinel.conf --sentinel
netstat -lnp | grep 26379
rm -rf sentinel.log
4.4、测试
尝试让master节点192.168.0.3宕机,查看sentinel日志:
tail -f sentinel.log
问题:192.168.0.3重新启动之后,该节点不能跟选举后的master数据主从同步
## 查询信息
info replication
查看发现主链接状态为关闭
其余slave节点主链接状态为开启
查看mysql的日志发现,一直报身份验证
经过排查,原因是主机配置了redis密码,需要在从机redis.conf
中添加如下配置,修改从机的配置文件后,重启从机的redis服务,重新及进行连接
## redis.conf中添加
masterauth java521
再次查看,主从配置成功
五、RedisTemplate的哨兵模式
在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。
1、新建SpringBoot项目
2、引入依赖
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
3、在配置文件application.yml中指定sentinel相关信息
server:
port: 9527
spring:
redis:
# redis密码 必须一致
password: java521
sentinel:
# 指定master名称
master: mymaster
# 指定redis-sentinel集群信息
nodes: 192.168.0.3:26379, 192.168.0.4:26379, 192.168.0.5:26379
4、配置主从读写分离
@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer()
return new LettuceClientConfigurationBuilderCustomizer()
@Override
public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder)
clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
;
这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:
- MASTER:从主节点读取
- MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
- REPLICA:从slave(replica)节点读取
- REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master
5、编写接口
@RestController
public class HelloController
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/get/key")
public String getValue(@PathVariable String key)
return redisTemplate.opsForValue().get(key);
@GetMapping("/set/key/value")
public String setValue(@PathVariable String key, @PathVariable String value)
redisTemplate.opsForValue().set(key, value);
return "success";
6、启动项目测试
这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:
六、搭建分片集群
6.1、集群结构
分片集群需要的节点数量较多,这里我们搭建一个较小的分片集群,包含三个master节点,每个master包含两个slave节点
IP | 端口 | 角色 |
---|---|---|
192.168.0.3 | 6379 | master |
192.168.0.4 | 6379 | master |
192.168.0.5 | 6379 | master |
192.168.0.3 | 6380 | slave |
192.168.0.4 | 6380 | slave |
192.168.0.5 | 6380 | slave |
192.168.0.3 | 6381 | slave |
192.168.0.4 | 6381 | slave |
192.168.0.5 | 6381 | slave |
6.2、准备实例和配置
暂停启动的reids 和 sentinel
## 进入/opt/home/目录
cd /opt/home/
## 将redis复制到880、8002、8003
cp -r redis 8001/
cp -r redis 8002/
cp -r redis 8003/
rm -rf /opt/home/8001/bin/redis.conf
rm -rf /opt/home/8002/bin/redis.conf
rm -rf /opt/home/8003/bin/redis.conf
## 分别更改端口为8001 8002 8003
vi 8001/bin/redis.conf
## 新增 8001
# 端口
port 8001
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir "/opt/home/8001"
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.0.3
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile "/opt/home/8001/run.log"
# 密码
requirepass "java521"
masterauth "java521"
vi 8002/bin/redis.conf
## 新增 8002
# 端口
port 8002
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir "/opt/home/8002"
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.0.3
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile "/opt/home/8002/run.log"
# 密码
requirepass "java521"
masterauth "java521"
vi 8003/bin/redis.conf
## 新增 8003
# 端口
port 8003
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir "/opt/home/8003"
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.0.3
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile "/opt/home/8003/run.log"
# 密码
requirepass "java521"
masterauth "java521"
6.3、启动
8001/bin/redis-server 8001/bin/redis.conf
8002/bin/redis-server 8002/bin/redis.conf
8003/bin/redis-server 8003/bin/redis.conf
## 查看是否启动
netstat -lnp | grep 8001
netstat -lnp | grep 8002
netstat -lnp | grep 8003
6.4、创建集群
虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。
我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中。
1)Redis5.0之前
Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。
# 安装依赖
yum -y install zlib ruby rubygems
gem install redis
然后通过命令来管理集群:
# 进入redis的src目录
cd /tmp/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.0.3:8001 192.168.0.4:8001 192.168.0.5:8001 192.168.0.3:8002 192.168.0.4:8002 192.168.0.5:8003 192.168.0.3:8003 192.168.0.4:8003 192.168.0.5:8003
2)Redis5.0以后
我们使用的是Redis6.2.6版本,集群管理以及集成到了redis-cli中,格式如下:
cd /opt/home/8001/bin/
./redis-cli -a java521 --cluster create --cluster-replicas 1 192.168.0.3:8001 192.168.0.4:8001 192.168.0.5:8001 192.168.0.3:8002 192.168.0.4:8002 192.168.0.5:8003 192.168.0.3:8003 192.168.0.4:8003 192.168.0.5:8003
命令说明:
redis-cli --cluster
或者./redis-trib.rb
:代表集群操作命令create
:代表是创建集群--replicas 1
或者--cluster-replicas 1
:指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1)
得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master
输入"yes"
通过命令可以查看集群状态:
./redis-cli -a java521 -p 8001 cluster nodes
6.5、测试
尝试连接8001节点,存储一个数据:
## 连接
./redis-cli -p 8001 -a java521
## 存储数据
set num 123
## 读取数据
get num
## 再次存储
set a 1
## 报错了
# 127.0.0.1:8001> set a 1
# (error) MOVED 15495 192.168.0.3:8002
# 127.0.0.1:8001> get a
# (error) MOVED 15495 192.168.0.3:8002
集群操作时,需要给redis-cli
加上-c
参数才可以:
./redis-cli -c -p 8001 -a java521
## 这次可以了
127.0.0.1:8001> set a 1
-> Redirected to slot [15495] located at 192.168.0.3:8002
OK
192.168.0.3:8002> get a
"1"
192.168.0.3:8002> set b 123
-> Redirected to slot [3300] located at 192.168.0.3:8001
OK
192.168.0.3:8001> get b
"123"
完成!
以上是关于Redis集群的主要内容,如果未能解决你的问题,请参考以下文章