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"

在这里插入图片描述
完成!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>