redis持久化机制和服务器配置推荐

介绍

Redis所有的数据都保存在内存中,数据的更新将异步的保存到硬盘上,当需要恢复数据时,从硬盘上将数据再读取到内存中,这就是Redis的持久化过程。主流的持久化方式有两种:

快照:MySQL的Dump以及Redis的RDB等

写日志:MySQL的Binlog,Hbase的HLong以及Redis的AOF等

一、Redis的持久化机制

Redis将所有的数据都存储在内存中,那么如果服务器重启了,Redis中的数据怎么恢复呢?

为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中。Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。
图片

二、RDB方式

RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内 存中的所有数据进行快照并存储在硬盘上。进行快照的条件可以由用户在配置文件中自定 义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定 的数值时就会进行快照。RDB是Redis默认采用的持久化方式,在配置文件中已经预置了3个条 件:

save 900 1 save 300 10 save 60 10000
Redis默认会将快照文件存储在当前目录的dump.rdb文件中,可以通过配置dir和 dbfilename两个参数分别指定快照文件的存储路径和文件名。最佳配置实践:

dbfilename dump-${port}.rdb
快照的过程如下:

Redis使用fork函数复制一份当前进程(父进程)的副本(子进程)

父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件

当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完 成。

写时复制(copy-on-write)策略:在执行fork的时候操作系统会使用写时复制策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。

Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这样我们可以通过定时备份RDB文件来实现Redis数据库备份。

RDB文件是经过压缩的二进制格式:

可以配置rdbcompression参数以禁用压缩节省CPU占用,所以占用的空间会小于内存中的数据大小,更加利于传输。其他两个配置参数:

stop-writes-on-bgsave-error yes // bgsave发生错误,停止写入rdbchecksum yesrdbcompression yes
除了自动快照,还可以手动发送SAVE或BGSAVE命令让Redis执行快照,两个命令的区别:

SAVE是由主进程进行快照操作,会阻塞住客户端其他请求,不会消耗额外的内存

BGSAVE会通过fork子进程进行快照操作,不会阻塞客户端命令,fork会消耗内存

两者的时间复杂度都是o(n)

RDB文件触发机制

除了前面介绍的三种:自动,save,bgsave外,还有下面几种方式也会生成RDB文件:

全量复制:主从复制中,主节点会自动生成RDB文件给从节点同步使用

debug reload

shutdown

Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。

RDB方式的优点:

性能最大化,fork子进程来完成写操作,让主进程继续处理命令,使用单独子进程来进行持久化,保证了redis的高性能

当重启恢复数据的时候,数据量比较大时,Redis直接解析RDB二进制文件,生成对应的数据存储在内存中,比AOF的启动效率更高

RDB方式的缺点:

数据安全性低,RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失,所以这种方式更适合数据要求不严谨的时候

linux fork之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。

当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页的异常中断(page-fault),陷入kernel的一个中断例程

中断例程中,kernel的copyonwrite机制就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份,如果这时有大量的写入操作,会产生大量的分页错误,这样就得耗费不少性能在复制上

三、AOF方式

默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改:

appendfilename appendonly.aof
下面介绍AOF持久化的具体实现,假设在开启AOF持久化的情况下执行了如下4个命令:

SET foo 1 SET foo 2 SET foo 3 GET foo
Redis会将前3条命令写入AOF文件中,此时AOF文件中的内容如下:

2$6SELECT$103$3set$3foo$113$3set$3foo$123$3set$3foo$13
可见AOF文件是纯文本文件,其内容正是Redis客户端向Redis发送的原始通信协议的内容。

这里有一个问题是前2条命令其实都是冗余的, 因为这两条的执行结果会被第三条命令覆盖。随着执行的命令越来越多,AOF文件的大小也会越来越大。实际上每当达到一定条件时Redis就会自动重写AOF文件,这个条件可以在配置文件中设置:

auto-aof-rewrite-percentage 100 //代表当前AOF文件空间和上一次重写后AOF文件空间的比值auto-aof-rewrite-min-size 64mb //表示运行AOF重写时文件最小体积,默认64MB
auto-aof-rewrite-percentage参数的意思是当目前的AOF文件大小超过上一次重写时的AOF 文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据

auto-aof-rewrite-min-size参数限制了允许重写的最小AOF文件大小,通常在AOF文 件很小的情况下即使其中有很多冗余的命令我们也并不太关心

除了让Redis自动执行重写外,还可以主动使用BGREWRITEAOF命令手动执行AOF重写。

AOF文件重写后的内容为:

2$6SELECT$103$3set$3foo$13
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。下面是AOF重写的流程:

注意:虽然每次执行更改数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在Redis中我们可以通过appendfsync参数设置同步的时机:

appendfsync always appendfsync everysec # appendfsync no

默认情况下Redis采用everysec 规则,即每秒执行一次同步操作

always表示每次执行写入都会执行同步,这是最安全也是最慢的方式

no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安全的方式

AOF追加阻塞

主线程为了达到每秒刷盘的策略,它会执行AOF追加阻塞,流程如下:

所以可能产生的问题:

主线程阻塞,主线程需要执行我们日常命令的处理,所以主线程不能阻塞

每秒刷盘的策略不是只丢失1秒的数据,实际上可能丢失2秒的数据

AOF阻塞定位可以通过Redis日志:

Asynchronous AOF fsync is taking too long (disk is busy?).Writing the AOF buffer without waiting for fsync to complete,this may slow down Redis
也可以通过Redis命令:

127.0.0.1:6379> info persistence…aof_delayed_fsync:100…
也可以通过top命令观察硬盘IO资源比较紧张的情况:

AOF配置参数最佳实践

appendonly yesappendfilename appendonly-${port}.aofappendfsync everysec no-appendfsync-on-rewrite yes // aof重写时是否做aof的append操作(否)
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。

AOF方式的优点:

数据安全

AOF方式的缺点:

数据集大的时候,比RDB启动效率低

fork操作介绍

fork操作只是做一个内存页(4K)的拷贝而不是拷贝整个内存,所以在大部分情况下是非常快的。info:latest_fork_usec可以查看Redis持久化的时间。改善fork可以通过:

使用物理机或者高效支持fork操作的虚拟化技术

控制Redis实例最大可用内存:maxmemory

合理配置Linux内存分配策略:vm.overcommit_memory=1,当没有足够内存去做内存分配的时候就不去分配内存,默认值是0

降低fork频率,例如放宽AOF重写机制的触发时机,减少不必要的全量复制

子进程开销和优化

  1. CPU

开销:RDB和AOF文件生成,属于CPU密集型,大量写操作集中在这个时候

优化:不做CPU绑定,不和CPU密集型部署

  1. 内存

开销:copy-on-write,父子进程共享一个物理内存页,写时会fork一个副本

优化:不允许单机多部署时大量产生重写

  1. 硬盘

开销:RDB和AOF文件写入,可以结合iostat,iotop分析

优化:不要和高硬盘负载服务部署一起:存储服务,消息队列等;no-appendfsync-on-rewrite=yes;大写入量可以选用ssd;单机多实例持久化文件目录可以考虑分盘

四、RDB与AOF对比

命令 RDB AOF
启动优先级 低 高
体积 小 大
恢复速度 快 慢
数据安全性 丢数据 根据策略决定
操作量级 重 轻
五、混合持久化

可以通过参数设置:aof-use-rdb-preamble yes开启。

加载时,首先会识别AOF文件是否以REDIS字符串开头,如果是,就按RDB格式加载,加载完RDB之后继续按照AOF格式加载剩余部分。混合式持久化方案兼顾了RDB的速度和AOF的安全性。

推荐的redis服务器配置
16核 CPU
32G内存
硬盘200G-500G
(CPU:内存比 约为1:2 或是1:4 都可)

原文链接:https://blog.csdn.net/weixin_36469682/article/details/113489978

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值