欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Redis学习(二):Redis 持久化

程序员文章站 2022-05-20 21:09:51
...

1. Redis持久化的取舍和选择

1. 什么是持久化

  • redis所有数据保持在内存中,对数据的更新将异步地保存到磁盘上。

2. 持久化方式

  • 快照
    • MySQL Dump
    • Redis RDB
  • 写日志
    • MySQL Binlog
    • Hbase HLog
    • Redis AOF

2. RDB

1. 什么是RDB

Redis学习(二):Redis 持久化

2. 触发机制 - 主要三种方式

1. save(同步)

  • 客户端向redis发送一条save命令,redis会帮我们生成RDB文件。
  • 问题:由于是同步命令,执行save的时候,假如我们的save非常慢(数据量多),会造成redis的阻塞。
  • 文件策略:如存在老的RDB文件,新替代老。
  • 复杂度:O(N)。

2. bgsave(异步)

  • 客户端执行bgsave命令,它使用了linux的fork()函数,生成了主进程的一个redis子进程,让子进程完成RDB的生成。RDB生成之后,会告诉主进程RDB生成成功。
  • 如果fork执行非常慢(大多数情况下非常快),依然会阻塞redis。
  • redis会正常响应客户端,因为createRDB这样重的操作是让子进程进行操作的。
  • 文件策略和复杂度与save相同。
命令   save   bgsave
IO类型   同步   异步
阻塞   是   是(阻塞发生在fork)
复杂度   O(N)   O(N)
优点   不会消耗额外内存   不阻塞客户端命令
缺点   阻塞客户端命令   需要fork,消耗内存

3. 自动

  • redis提供了save配置来进行自动持久化
配置   seconds   changes
save   900   1
save   300   10
save   60   10000
  • 在60秒改变了10000条数据,在300秒改变了10条数据,在900秒改变了一条数据,进行自动持久化。RDB文件生成是内部调用bgsave。
  • 具体配置可以修改。
  • 无法控制生成RDB频率。

4. 配置

  • 我们来看一下redis默认配置文件中给出的配置
  • save:自动持久化
  • dbfilename:RDB名字
  • dir:RDB等日志文件存放位置
  • stop-writes-on-bgsave-error:bgsave发生错误时是否停止写入
  • rdbcompression:RDB文件是否采用压缩的格式
  • rdbchecksum:是否对RDB文件进行校验和
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir ./
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

5. 最佳配置

  • 关闭自动持久化
  • dbfilename:使用端口号进行文件区别
  • dir:根据redis数量进行分盘
dbfilename dump-${port}.rdb
dir /bigdistpath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

3. 触发机制 - 不容忽略方式

1. 全量复制

2. debug reload

3. shutdown

4. 试验

  • 修改配置文件以便远程连接
    • bind 0.0.0.0
    • protected-mode no
  • 使用jedis随便添加些数据
127.0.0.1:6379> dbsize
(integer) 1000000

127.0.0.1:6379> info memory
# Memory
used_memory:105221280
used_memory_human:100.35M
  • 我们提前在另一个窗口准备好执行命令
127.0.0.1:6379> set hello word
OK
127.0.0.1:6379> get hello 
  • 在第一个窗口执行save,接着执行get hello,发现被阻塞
127.0.0.1:6379> save
OK
(4.77s)

127.0.0.1:6379> get hello
"word"
(2.22s)
  • 我们还可以去data目录(配置文件指定)下看到生成的RDB文件
[aaa@qq.com redis]# cd data/
[aaa@qq.com data]# ll
总用量 52428
-rw-r--r--. 1 root root     7365 12月 21 14:29 6379.log
-rw-r--r--. 1 root root     4809 12月 20 23:40 6382.log
-rw-r--r--. 1 root root 53666783 12月 21 14:29 dump-6379.rdb
  • 接下来我们验证一下bgsive
127.0.0.1:6379> bgsave
Background saving started
  • 使用命令发现调用子进程,同时get hello没有阻塞
[aaa@qq.com redis]# ps -ef | grep redis-
root       4987      1  1 14:21 ?        00:00:15 redis-server 0.0.0.0:6379
root       5271   3826  0 14:33 pts/0    00:00:00 redis-cli
root       5304   4987 56 14:36 ?        00:00:01 redis-rdb-bgsave 0.0.0.0:6379
root       5306   5143  0 14:36 pts/2    00:00:00 grep --color=auto redis-
  • 最后我们来看一下自动持久化策略
#save 900 1
#save 300 10
save 60 5
  • 可以通过flushall清空数据
127.0.0.1:6379> flushall
OK
(0.70s)
127.0.0.1:6379> dbsize
(integer) 0
  • 插入数据
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set c d
OK
127.0.0.1:6379> set e f
OK
127.0.0.1:6379> set g h
OK
127.0.0.1:6379> set i j
OK
127.0.0.1:6379> set m n
OK
  • 查看日志,发现进行了自动持久化
[aaa@qq.com data]# tail -f 6379.log

5475:M 21 Dec 14:45:03.075 * 5 changes in 60 seconds. Saving...
5475:M 21 Dec 14:45:03.077 * Background saving started by pid 5494
5494:C 21 Dec 14:45:05.018 * DB saved on disk
5494:C 21 Dec 14:45:05.019 * RDB: 10 MB of memory used by copy-on-write
5475:M 21 Dec 14:45:05.073 * Background saving terminated with success

5. 总结

  • RDB是Redis内存到硬盘的快照,用于持久化。
  • sava通常会阻塞Redis。
  • bgsava不会阻塞Redis,但是会fork新进程。
  • save自动配置满足任一就会被执行。
  • 有些触发机制不能忽视。

3. AOF

1. RDB有什么问题

1. 耗时,耗性能

  • RDB生成过程其实就是将内存中的数据dump到硬盘当中,形成一个RDB文件。
  • 首先是比较耗时的,我们要将所有数据进行一个dump,是一个O(N)的过程,本身的写也会消耗很多CPU。
  • 其次是一个内存的消耗,我们知道bgsive有一个fork的过程。
  • 还有就是IO性能的消耗。

2. 不可控,丢失数据

配置   动作
T1   执行多个写命令
T2   满足RDB自动创建的条件
T3   再次执行多个写命令
T4   宕机
  • T3到T4之间的数据写入就会丢失

2. AOF运行原理,创建

  • 客户端写一条数据,就在日志追加一条写命令

Redis学习(二):Redis 持久化

3. AOF的三种策略

  • always
    • redis在执行写命令的时候,实际上不是直接写在文件系统当中,而是写在硬盘的缓冲区当中。缓冲区会根据一些策略刷新到硬盘当中。
    • always是说每条命令fsync到硬盘,这样redis的写入数据就会不丢失。
  • everysec
    • everysec是说每秒把缓冲区fsync到硬盘。
    • 在高写入量时会适当保护硬盘。
    • 缺点是如果出现了故障,有可能会丢失一秒的数据。
    • 这是一个默认值。
  • no
    • OS决定fsync,由操作系统决定什么时候该写入硬盘。
命令   always   everysec   no
优点   不丢失数据   每秒一次fsync   不用管
缺点   IO开销较大,一般的sata盘只有几百TPS   丢一秒数据   不可控

4. AOF重写

  • set hello world set hello java set hello hehe => set hello hehe
  • incr counter incr counter => set counter 2
  • rpush mylist a rpush mylist b rpush mylist c => rpush mylist a b c
  • 过期数据 => 重写过程是没有用的

把一些可以优化的命令进行化简,从而达到两个目的

  • 减少硬盘占用量
  • 加速恢复速度

5. AOF重写实现的两种方式

1. bgrewriteaof

  • 客户端向redis发送一条命令bgrewriteaof,redis会返回OK并异步执行。redis接收到这个命令后会fork出一个子进程来完成AOF的重写。
  • 这里的AOF重写就是将redis内存中的数据进行一次回溯,回溯成AOF文件,是从redis内存中进行一个重写。

2. AOF重写配置

  • 配置
配置名   含义
auto-aof-rewrite-min-size   AOF文件重写需要的尺寸
auto-aof-rewrite-percentage   AOF文件增长率
  • 统计
统计名   含义
aof-current-size   AOF当前尺寸(单位:字节)
aof-base-size   AOF上次启动和重写的尺寸(单位:字节)
  • 自动触发时机
    • aof-current-size > auto-aof-rewrite-min-size
    • (aof-current-size - aof-base-size) / aof-base-size > auto-aof-rewrite-percentage

Redis学习(二):Redis 持久化

6. AOF配置

  • 我们修改一下redis默认配置文件中给出的配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
dir /home/redis/data
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
  • 进行一些简单操作
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> set hello java
OK
127.0.0.1:6379> set hello redis
OK
127.0.0.1:6379> incr counter
(integer) 1
127.0.0.1:6379> incr counter
(integer) 2
127.0.0.1:6379> rpush list a
(integer) 1
127.0.0.1:6379> rpush list b
(integer) 2
127.0.0.1:6379> rpush list c
(integer) 3
  • 查看AOF文件是否生成
[aaa@qq.com redis]# cd data
[aaa@qq.com data]# ll
总用量 40
-rw-r--r--. 1 root root 21736 12月 21 16:57 6379.log
-rw-r--r--. 1 root root  4809 12月 20 23:40 6382.log
-rw-r--r--. 1 root root   277 12月 21 16:58 appendonly.aof
-rw-r--r--. 1 root root   127 12月 21 15:22 dump-6379.rdb
  • 查看文件内容
[aaa@qq.com data]# more appendonly.aof 

*3
$3
set
$5
hello
$5
world
  • 我们稍微看一下文件格式

    • *3表示下面这个命令有3个参数
    • $3表示下面一个数据的字节长度
  • 下面我们来看下重写

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
  • 再次打开appendonly.aof,我们发现只保留了set hello redis。
*3
$3
SET
$5
hello
$5
redis

7. RDB和AOF的抉择

1. RDB和AOF比较

命令   RDB   AOF
启动优先级   低   高
体积   小   大
恢复速度   快   慢
数据安全性   丢数据   根据策略决定
轻重   重   轻

2. RDB最佳策略

  • “关”
  • 集中管理
  • 主从,从开?

3. AOF最佳策略

  • “开”:缓存和存储
  • AOF重写集中管理
  • everysec

4. 最佳策略

  • 小分片
  • 缓存或者存储
  • 监控(硬盘,内存,负载,网络)
  • 足够的内存

4. 开发运维常见问题

1. fork操作

1. 同步操作

2. 与内存量息息相关:内存越大,耗时越长(与机器类型有关)

3. info:latest_fork_usec

4. 改善fork

  • 优先使用物理机或者高效支持fork操作的虚拟化技术。
  • 控制redis实例最大可用内存:maxmemory。
  • 合理配置linux内存分配策略:vm.overcommit_memory=1。
  • 降低fork频率:例如放宽AOF重写自动触发时机,不必要的全量复制。

2. 子进程开销和优化

1. CPU

  • 开销:RDB和AOF文件生成,属于CPU密集型。
  • 优化:不做CPU绑定,不和CPU密集型部署。

2. 内存

  • 开销:fork内存开销,copy-on-write。
  • 优化:禁止支持大的内存页分配 : echo never > /sys/kernel/mm/transparent_hugepage/enabled。

3. 硬盘

  • 开销:AOF和RDB文件写入,可以结合iostat,iotop分析。
  • 优化:
    • 不要和高硬盘负载服务部署在一起:存储服务,消息队列等。
    • 不要进行AOF追加:no-appendfsync-on-rewrite = yes。
    • 根据写入量决定磁盘类型:例如ssd。
    • 单机多实例持久化文件目录可以考虑分盘。

3. AOF追加阻塞

  • 如果使用了AOF,我们通常会使用每秒刷盘的这样一个策略。
  • 首先主线程去写入AOF缓冲区,同时还有一个AOF同步线程去同步每秒刷盘的操作,同时还会记录最近的一次同步时间。
  • 主线程还会对比和上次AOF的时间,如果距离上次同步时间超过两秒,主线程会阻塞。
  • 解决方法主要参考上面关于硬盘的优化。

最后

大家可以关注我的微信公众号一起学习进步。

Redis学习(二):Redis 持久化