1. Redis性能优化

1.设置最大打开文件数
cat /etc/security/limits.conf
redis soft nofile 100000
redis hard nofile 100000

2.请确保将Linux内核的超额内存设置设为1。
cat /etc/sysctl.conf
vm.overcommit_memory=1
net.core.somaxconn=65535
sysctl -p

3.设置内存大页
cat /etc/rc.local
echo never > /sys/kernel/mm/transparent_hugepage/enabled

system资源限制

# /etc/systemd/system/redis.service
[Unit]
Description=Redis Single Service
After=network.target

[Service]
Type=notify
User=dev
Group=dev
TimeoutStartSec=120s
ExecStart=/data/redis/src/redis-server /data/redis/redis.conf
ExecStop=/data/redis/src/redis-cli shutdown -a w4RedisService
Restart=on-failure
RestartSec=30s
LimitNOFILE=100000
LimitNPROC=65535

[Install]
WantedBy=multi-user.target

2. Redis持久化分类

在Redis中,分别为我们提供了 RDB 和 AOF 两种持久化模式。在4.0及以后版本中,提供了一种混合持久化的功能,就是RDB和AOF结合的持久化模式。

分类如下:

  • RDB

RDB持久化方式是通过快照完成的。RDB程序将当前内存中的数据快照保存到磁盘中,在Redis重启时,RDB程序可以通过载入RDB文件来还原数据库的状态。

  • AOF

AOF(append only file),是以独立日志的方式记录每次的写命令,重启时在执行文件中的命令来达到恢复数据的目的。

  • 混合模式

混合模式就是同时结合了RDB持久化和AOF持久化混合写入AOF文件。这样就可以结合2者的优点了,快速的加载持久化文件,同时避免数据丢失过多。

3. RDB 持久化

3.1 介绍

RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。

触发方式

触发rdb持久化的方式有2种,分别是手动触发自动触发

(1)手动触发

手动触发分别对应save和bgsave命令

  • save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用

  • bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子 进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短(推荐

bgsave流程图如下所示

image-20220509181016785

具体流程如下:

  • redis客户端执行 bgsave 命令或者自动触发 bgsave 命令;
  • 主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回;
  • 如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;
  • 子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
  • 同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)。

自动触发

在以下4种情况时会自动触发

  • redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;
  • 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;
  • 执行debug reload命令重新加载redis时也会触发bgsave操作;
  • 默认情况下执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作

3.2 配置说明

快照周期:内存快照虽然可以通过技术人员手动执行SAVE或BGSAVE命令来进行,但生产环境下多数情况都会设置其周期性执行条件。

# 周期性执行条件的设置格式为
save <seconds> <changes>

# 默认的设置为:
save 900 1  # 如果900秒内有1条Key信息发生变化,则进行快照;
save 300 10 # 如果300秒内有10条Key信息发生变化,则进行快照;
save 60 10000  # 如果60秒内有10000条Key信息发生变化,则进行快照。读者可以按照这个规则,根据自己的实际请求压力进行设置调整。

# 以下设置方式为关闭RDB快照功能
save ""

其它相关配置

# RDB持久化数据库文件名,默认dump.rdb
dbfilename dump.rdb

# 数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
dir /home/work/app/redis/data/

# yes:代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no:表明忽略错误继续写文件。
stop-writes-on-bgsave-error yes

# 是否开启RDB文件压缩,yes默认开启压缩,no不开启
rdbcompression yes

# 在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动
rdbchecksum yes

配置查询

127.0.0.1:6379> config get dbfilename # 想要获取 RDB 文件的存储名称设置
127.0.0.1:6379> config get dir    # 查询 RDB 的文件目录

3.3 RDB优缺点

优点

  • RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;
  • RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;
  • RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;
  • 与 AOF 格式的文件相比,RDB 文件可以更快的重启。

缺点

  • 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;
  • RDB 需要经常 fork() 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟。

4. AOF 持久化

4.1 介绍

AOF(Append-Only File)记录Redis中每次的写命令,类似mysql中的binlog,服务重启时会重新执行AOF中的命令将数据恢复到内存中,RDB(按策略持久化)持久化方式记录的粒度不如AOF(记录每条写命令),因此很多生产环境都是开启AOF持久化。

AOF日志记录Redis的每个写命令,步骤分为:命令追加(append)、文件写入(write)和文件同步(sync)。

  • 命令追加 当AOF持久化功能打开了,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的 aof_buf 缓冲区。

  • 文件写入和同步 关于何时将 aof_buf 缓冲区的内容写入AOF文件中,Redis提供了三种写回策略:always、everysec、no

触发持久化

AOF 的触发条件分为两种:自动触发和手动触发。

(1)手动触发

在客户端执行 bgrewriteaof 命令就可以手动触发 AOF 持久化,如下图所示:

image-20220509194616438

可以看出执行完 bgrewriteaof 命令之后,AOF 持久化就会被触发。

(2)自动触发

有两种情况可以自动触发 AOF 持久化,分为是:**满足 AOF 设置的策略触发 **和 **满足 AOF 重写触发。**其中,AOF 重写触发会在本文的后半部分详细介绍,这里重点来说 AOF 持久化策略,配置 Redis 多久才将数据 fsync(同步)到磁盘一次。

AOF 持久化策略,分为以下三种:

  • always:每条 Redis 操作命令都会写入磁盘,最多丢失一条数据;
  • everysec:每秒钟写入一次磁盘,最多丢失一秒的数据;
  • no:不设置写入磁盘的规则,根据当前操作系统来决定何时写入磁盘,Linux 默认 30s 写入一次数据至磁盘。

推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

注:因为每次写入磁盘都会对 Redis 的性能造成一定的影响,所以要根据用户的实际情况设置相应的策略,一般设置每秒写入一次磁盘的频率就可以满足大部分的使用场景了。

4.2 配置

# appendonly参数开启AOF持久化
appendonly yes
 
# AOF文件名
appendfilename "appendonly.aof"

# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./
 
# AOF同步策略,一般都是选择第一种[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录]
appendfsync always
#appendfsync everysec
# appendfsync no
 
# 配置重写触发机制
# aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写。[假如上次重写后大小为10MB,当AOF文件达到20MB时也会再次触发重写,以此类推]
auto-aof-rewrite-percentage 100 
# aof文件大小超过64MB时,触发重写
auto-aof-rewrite-min-size 64mb

4.3 深入理解AOF重写

AOF持久化机制记录每个写命令,当服务重启的时候会复现AOF文件中的所有命令,会消耗太多的资源且重启很慢。因此为了避免AOF文件中的写命令太多文件太大,Redis引入了AOF的重写机制来压缩AOF文件体积。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。

把过期的,没有用的,重复的,可优化的命令简化为很小的aof文件。实际上是redis内存中的数据回溯成aof文件。

重写流程:

  1. bgrewriteaof 触发重写,判断是否当前有 bgsavebgrewriteaof 在运行,如果有,则等待该命令结束后再继续执行。
  2. 主进程fork出子进程执行重写操作,保证主进程不会阻塞。
  3. 子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入 aof_buf 缓冲区和 aof_rewrite_buf 重写缓冲区 保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
  4. 子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
  5. 使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。

image-20220509180050894

5. RDB和AOF混合方式(4.0版本)

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

原理:混合持久化同样也是通过 bgrewriteaof 重写命令完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。

简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。如图所示

img

配置

# 我们可以在appendonly yes命令 下面加上以下的配置,然后重启Reids
aof-use-rdb-preamble yes

6. 数据恢复实战操作

本次实验redis版本由3.2.12升级到4.0.0,并开启混合持久化,迁移RDB数据,验证数据是否正常

6.1 AOF和RDB的恢复顺序

当Redis服务重启时数据恢复的顺序如下:

  • 判断是否开启AOF持久化,若开启了AOF,则使用AOF持久化文件恢复数据,否则使用RDB持久化文件恢复数据;
  • 若AOF文件不存在则从RDB文件恢复【其实并没有】;若AOF文件存在则使用AOF文件恢复;
  • 若AOF文件和RDB文件都不存在则直接启动Redis;
  • 若AOF或RDB文件出现错误,则启动失败返回错误信息;

img

6.2 恢复流程

流程较为复杂,需要严格按照以下步骤

  • 修改配置文件方式关闭aof备份功能,但要开启rdb备份功能;

  • 一定要开启热修改配置功能,这步很重要,所以单独列一条来写

  • 把备份的rdb文件拷贝过去,同时重启redis

  • 通过命令config set appendonly yes开启aof备份功能,执行命令后就会自动产生appendon ly.aof这个文件,此时rdb和aof文件数据同步了

  • 然后关闭redis,修改配置文件开启aof备份功能;

  • 然后开启redis,此时才叫数据恢复成功。

6.3 安装3.2.12并备份数据

# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
# wget http://download.redis.io/releases/redis-4.0.0.tar.gz
tar -zxvf redis-3.2.12.tar.gz -C /data/
mv /data/redis-3.2.12 /data/redis
mkdir /data/redis/data
yum install -y gcc gcc-c++ make tcl-devel
cd /data/redis && make &&     # make负责编译,make install负责将二进制文件安装到/usr/local/bin
cd /data/redis/src && make install && make test           # 测试确保编译无误
cp /data/redis/redis.conf /data/redis/redis.conf.bak
# redis-3.2.12.conf
supervised systemd
dir /data/redis/data
daemonize yes
pidfile /data/redis/redis.pid
port 6379
bind 0.0.0.0
requirepass w4RedisService

loglevel warning
maxclients 65535
tcp-backlog 10240
appendonly no
save 900 1
save 300 10
save 60 10000
maxmemory 50499420160
# /etc/systemd/system/redis.service
[Unit]
Description=Redis Single Service
After=network.target

[Service]
Type=notify
User=root
Group=root
TimeoutStartSec=120s
ExecStart=/data/redis/src/redis-server /data/redis/redis.conf
ExecStop=/data/redis/src/redis-cli shutdown -a w4RedisService
Restart=on-failure
RestartSec=30s
LimitNOFILE=100000
LimitNPROC=65535

[Install]
WantedBy=multi-user.target

插入数据

[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379>set company1 huanle1
127.0.0.1:6379>set company2 huanle2
127.0.0.1:6379>set company3 huanle3
127.0.0.1:6379>bgsave
127.0.0.1:6379>exit

#重启服务
[root@localhost redis]#systemctl restart redis

6.4 升级4.0.0并恢复数据

tar -zxvf redis-4.0.0.tar.gz
cd redis-4.0.0
make
cd src && make install
make test
# # redis-4.0.0.conf
# 先不要开启aof相关配置,否则数据无法同步
supervised systemd
daemonize no
dir /data/redis/data
#pidfile /data/redis/redis.pid
port 6379
bind 0.0.0.0
requirepass w4RedisService

loglevel warning
maxclients 65535
tcp-backlog 10240
save 900 1
save 300 10
save 60 10000
maxmemory 50499420160
appendonly yes
aof-use-rdb-preamble yes
# 重命名旧的目录和新版本目录
mv redis redis.bak
mv redis-4.0.0 redis
cd /data/redis/data
cp dump.rdb-bak dump.rdb
systemctl start redis
# 查看RDB数据是否已经恢复,命令行设置开启aof备份功能,执行命令后就会自动产生appendonly.aof这个文件,完成rdb和aof数据同步
[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379> keys *
1) "company1"
2) "company2"
3) "company3"
127.0.0.1:6379> config set appendonly yes
127.0.0.1:6379> exit

# 接着关闭redis,配置文件中设置永久开启AOF持久化
[root@localhost redis]# systemctl stop redis
[root@localhost redis]# cat redis.conf
appendonly yes
[root@localhost redis]# systemctl start redis

image-20220509165518126

# 配置混合持久化功能
[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379> config set aof-use-rdb-preamble yes  # 开启RDB+AOF混合持久化功能
OK
127.0.0.1:6379> bgrewriteaof  # 手动触发AOF重写
Background append only file rewriting started
127.0.0.1:6379> set name hanjianjuan
OK
127.0.0.1:6379> quit

# 接着关闭reids,配置文件中设置永久开启混合持久化
[root@localhost redis]# systemctl stop redis
[root@localhost redis]# cat redis.conf
aof-use-rdb-preamble yes
[root@localhost redis]# systemctl start redis

image-20220509165714865

结论:aof文件再经过bgrewriteaof之后,再次执行的命令会按照aof的方式进行存储,等下次再bgrewriteaof之后,再进行二进制存储。redis后台再进行bgrewriteaof的时候,这时候如果有客户端命令进来,会再后面进行追加。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐