Redis的数据操做都在内存中,redis崩掉的话,会丢失。Redis持久化就是对数据的更新异步的保存在磁盘上,以便数据恢复。java
将Redis内存中的数据,完整的生成一个快照,以二进制格式文件(后缀RDB)保存在硬盘当中。当须要进行恢复时,再从硬盘加载到内存中。python
Redis主从复制,用的也是基于RDB方式,作一个复制文件的传输。ios
save命令触发方式(同步)redis
redis> save OK
save执行时,会形成Redis的阻塞。全部数据操做命令都要排队等待它完成。
文件策略:新生成一个新的临时文件,当save执行完后,用新的替换老的。vim
bgsave命令触发方式(异步)缓存
redis> bgsave Background saving started
客户端对Redis服务器下达bgsave命令时,Redis会fork出一个子进程进行RDB文件的生成。当RDB生成完毕后,子进程再反馈给主进程。fork子进程时也会阻塞,不过正常状况下fork过程都很是快的。
文件策略:与save命令相同。
save与bgsave对比:安全
命令 | save | bgsave |
---|---|---|
IO类型 | 同步 | 异步 |
阻塞? | 是 | 是(发生在fork期间) |
复杂度 | O(n) | O(n) |
优势 | 不消耗额外内存 | 不阻塞客户端命令 |
缺点 | 阻塞客户端命令 | fork消耗额外内存 |
规则自动触发方式
某些条件达到时,自动生成RDB文件。
好比咱们配置以下:服务器
配置 | seconds | changes | 说明 |
---|---|---|---|
save | 900 | 1 | 900秒内改变1条数据,自动生成RDB文件 |
save | 300 | 10 | 300秒内改变10条数据,自动生成RDB文件 |
save | 60 | 10000 | 60秒内改变1万条数据,自动生成RDB文件 |
以上任一条件达到时,都会触发生成RDB文件。不过这种方式对RDB文件的生成频率不太好控制。若是写量大,RDB生成会很频繁。不是一种好的方式。
修改配置文件:网络
# 配置自动生成规则。通常不建议配置自动生成RDB文件 save 900 1 save 300 10 save 60 10000 # 指定rdb文件名 dbfilename dump-${port}.rdb # 指定rdb文件目录 dir /opt/redis/data # bgsave发生错误,中止写入 stop-writes-on-bgsave-error yes # rdb文件采用压缩格式 rdbcompression yes # 对rdb文件进行校验 rdbchecksum yes
save试验app
cd redis cd config cp ../redis.conf cp redis.conf redis-6379.conf vim redis-6379.conf
修改以下配置:
daemonize yes pidfile /var/run/redis-6379.pid port 6379 logfile "6379.log" # 先关闭自动生成RDB的配置 # save 900 1 # save 300 10 # save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump-6379.rdb dir /opt/soft/redis/data
保存配置
:wq
# 重启redis redis-server redis-6379.conf
# 客户端链接 redis-cli
# 暂时尚未Redis内存数据 127.0.0.1:6379> dbsize (integer) 0
而后写个简单for循环程序,往Redis执行大量的写命令,让内存数据足够大。
# 再看一下,这下内存数据有不少了 127.0.0.1:6379> dbsize (integer) 5000000 # 看下内存使用了904M,足够用以演示save的阻塞了 127.0.0.1:6379> info memory used_memory: 948306016 used_memory_human: 904.38M used_memory_rss: 1031897088 used_memory_peak: 981827104 used_memory_peak_human: 936.34M used_memory_lua: 36864 mem_fragmentation_ratio: 1.09 mem_allocator: libc
# 执行save,发现等待了若干秒后,才输出OK以及消耗时间 127.0.0.1:6379> save OK (8.94s)
/opt/soft/redis/data目录下也会生成dump-6379.rdb文件。
bgsave试验
验证bgsave的非阻塞:
# 咱们再开一个新窗口,在新窗口上链接redis客户端 redis-cli # 输好如下命令,先别执行 127.0.0.1:6379> get hello
# 而后在原窗口执行bgsave 127.0.0.1:6379> bgsave Background saving started
# 立刻切回新窗口,回车执行命令,发现world即刻返回,验证了bgsave的非阻塞 127.0.0.1:6379> get hello "world"
接下来验证bgsave会生成子进程:
# 在新窗口先查看下redis进程,过滤掉客户端和grep进程,发现就只有一个redis主进程 ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .86 redis-server *:6379
# 在原窗口再执行一次bgsave 127.0.0.1:6379> bgsave Background saving started
# 立刻切新窗口再次查看进程,发现多了个子进程redis-rdb-bgsave ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .91 redis-server *:6379 501 36954 1 0 10:28下午 ?? 0:02 .81 redis-rdb-bgsave *:6379 # 再看一次,子进程已经不在了。由于子进程已经完成了它生成rdb文件的工做 ps -ef | grep redis- | grep -v "redis-cli" | grep -v "grep" 501 36775 1 0 10:22下午 ?? 0:17 .91 redis-server *:6379
最后验证文件策略:
# 在新窗口/data目录查看文件 ls 6379.log dump-6379.log
# 在原窗口再执行一次bgsave 127.0.0.1:6379> bgsave Background saving started
# 切新窗口再次查看文件,多了个临时的rdb文件 ls 6379.log dump-6379.rdb temp-36985.rdb # 过会儿再查看一次,临时文件消失了 ls 6379.log dump-6379.rdb
自动生成试验
这个不演示了,本身修改配置文件save 60 5,配置60秒更新5次就自动生成RDB文件。重启redis后,咱们在客户端用set命令执行5次。观察/data下的rdb文件的时间戳是否变化了来验证。
咱们也能够查看下日志文件6379.log,输出了试验过程的相关日志内容。
就是写日志,每次执行Redis写命令,让命令同时记录日志(以AOF日志格式)。Redis宕机时,只要进行日志回放就能够恢复数据。
首先Redis执行写命令,将命令刷新到硬盘缓冲区当中。
三种策略对比
命令 | always | everysec | no |
---|---|---|---|
优势 | 不丢失数据 | 只丢一秒数据 | 不用管,操做系统去管 |
缺点 | IO开销大,通常的sata盘只有几百TPS | 丢了一秒数据 | 不可控,不知道何时刷盘,也不知道会丢失多少数据 |
一般使用everysec策略,这也是AOF的默认策略。
随着时间的推移,命令的逐步写入。AOF文件也会逐渐变大。当咱们用AOF来恢复时会很慢,并且当文件无限增大时,对硬盘的管理,对写入的速度也会有产生影响。Redis固然考虑到这个问题,因此就有了AOF重写。
原生AOF:
set hello world set hello java set hello python incr counter incr counter rpush mylist a rpush mylist b rpush mylist c 过时数据
重写后的AOF:
set hello python set incr 2 rpush mylist a b c
AOF重写就是把过时的、没用的、重复的以及可优化的命令,进行化简。只取最终有价值的结果。虽然写入操做很频繁,但系统定义的key的量是相对有限的。
AOF重写能够大大压缩最终日志文件的大小。从而减小磁盘占用量,加快数据恢复速度。好比咱们有个计数的服务,有不少自增的操做,好比有一个key自增到1个亿,对AOF文件来讲就是一亿次incr。AOF重写就只用记1条记录。
AOF重写配置
auto-aof-rewrite-min-size:AOF文件重写须要的尺寸
auto-aof-rewrite-percentage:AOF文件增加率
redis提供了aof_current_size和aof_base_size,分别用来统计AOF当前尺寸(单位:字节)和AOF上次启动和重写的尺寸(单位:字节)。
AOF自动重写的触发时机,同时知足如下两点):
修改配置文件:
# 开启正常AOF的append刷盘操做 appendonly yes # AOF文件名 appendfilename "appendonly-6379.aof" # 每秒刷盘 appendfsync everysec # 文件目录 dir /opt/soft/redis/data # AOF重写增加率 auto-aof-rewrite-percentage 100 # AOF重写最小尺寸 auto-aof-rewrite-min-size 64mb # AOF重写期间是否暂停append操做。AOF重写很是消耗磁盘性能,而正常的AOF过程当中也会往磁盘刷数据。 # 一般偏向考虑性能,设为yes。万一重写失败了,这期间正常AOF的数据会丢失,由于咱们选择了重写期间放弃了正常AOF刷盘。 no-appendfsync-on-rewrite yes
redis-cli 127.0.0.1:6379> dbsize (integer) 5000000 127.0.0.1:6379> exit
vim redis-6379.conf
appendonly yes appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes
配置修改后,要从新启动redis。
appendonly是支持动态配置,不用重启Redis:
127.0.0.1:6379> config get appendonly 1) "appendonly" 2) "no" 127.0.0.1:6379> config set appendonly yes OK # 从新加载配置 127.0.0.1:6379> config rewrite OK 127.0.0.1:6379> exit
先试验下正常AOF刷盘
# 客户端链接redis,执行一些命令: redis-cli 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 127.0.0.1:6379> exit
# 咱们查看data目录,appendonly.aof文件已经生成了 cd /opt/soft/redis/data ll -rw-r--r-- 1 carlosfu staff 16K 10 7 22:28 6379.log -rw-r--r-- 1 carlosfu staff 243B 10 7 22:29 appendonly.aof -rw-r--r-- 1 carlosfu staff 18B 10 7 22:19 dump-6379.rdb
再试验下AOF重写
redis-cli 127.0.0.1:6379> bgrewriteaof Background append only file rewriteing started 127.0.0.1:6379> dbsize (integer) 3
# 咱们再查看data目录,appendonly.aof文件变小了 cd /opt/soft/redis/data ll -rw-r--r-- 1 carlosfu staff 17K 10 7 22:33 6379.log -rw-r--r-- 1 carlosfu staff 137B 10 7 22:33 appendonly.aof -rw-r--r-- 1 carlosfu staff 18B 10 7 22:19 dump-6379.rdb
命令 | RDB | AOF | 说明 |
---|---|---|---|
启动优先级 | 低 | 高 | RDB和AOF都开启的状况下,Redis重启后,选择AOF进行恢复。大部分状况下它保存了比RDB更新的数据 |
体积 | 小 | 大 | RDB二进制模式存储,并且作了压缩。AOF虽然有AOF重写,可是体积相对仍是大不少,毕竟它是记日志形式 |
恢复速度 | 快 | 慢 | RDB体积小,恢复速度快。AOF体积大,恢复速度慢 |
数据安全 | 丢数据 | 根据策略决定 | RDB丢上次快照后的数据,AOF根据always、everysec、no策略决定是否丢数据 |
轻重 | 重 | 轻 | AOF是追加日志,因此比较轻的操做。而RDB是CPU密集型操做,对磁盘,以及fork时对内存的消耗都比较大 |
fork是一个同步操做。执行bgsave和bgrewriteaof时都会执行fork操做,
改善fork
bgsave和bgrewriteaof会进行fork操做产生子进程。
CPU
内存
硬盘
优化:
AOF阻塞定位
redis日志:
Asynchronous AOF fsync is taking to long(disk is busy?). Writing the AOF buffer whitout waiting for fsync to complete, this may slow down Redis
info persistence
能够查看上述日志发生的次数。
127.0.0.1:6379> info persistence ...... ...... aof_delayed_fsync: 100 ...... ......
改善方式 同子进程的硬盘优化