Redis学习(二):Redis 持久化

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

1. 什么是持久化

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

2. 持久化方式

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

2. RDB

1. 什么是RDB

RDB

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

1. save(同步)java

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

2. bgsave(异步)linux

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

3. 自动ios

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

4. 配置redis

  • 咱们来看一下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 reloadbash

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文件
[root@localhost redis]# cd data/
[root@localhost 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没有阻塞
[root@localhost 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
复制代码
  • 查看日志,发现进行了自动持久化
[root@localhost 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. 不可控,丢失数据app

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

2. AOF运行原理,建立

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

AOF

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

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文件是否生成
[root@localhost redis]# cd data
[root@localhost 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
复制代码
  • 查看文件内容
[root@localhost 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的时间,若是距离上次同步时间超过两秒,主线程会阻塞。
  • 解决方法主要参考上面关于硬盘的优化。

最后

你们能够关注个人微信公众号一块儿学习进步。

相关文章
相关标签/搜索