背景
我们都知道,Redis是一个内存数据库,数据保存在内存中,访问速度是相当快的。
但是内存中的数据,服务器每次重启之后就会丢失,redis是如何做到持久化的呢?redis持久化设计有哪些巧妙之处呢?
目前,Redis 的持久化主要有两大机制,即 AOF(Append Only File)日志和 RDB 快照。
AOF
格式
我们以 Redis 收到“set testkey testvalue”命令后记录的日志为例,看看 AOF 日志的内容。其中,“*3”表示当前命令有三个部分,每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值。这里,“数字”表示这部分中的命令、键或值一共有多少字节。例如,“$3 set”表示这部分有 3 个字节,也就是“set”命令。
写入方式
AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的,也就是说每一条命令都会生成一条AOF日志。
那么假如说这条命令是语法有误的命令呢?也会记录吗?
Redis 是先执行命令,把数据写入内存,然后才记录日志,如下图所示:
Redis 使用写后日志这一方式的一大好处是,可以避免出现记录错误命令的情况
这样的AOF还是有风险的,执行完命令后宕机了,AOF丢失,如果redis作为数据库就会有数据丢失的风险
三种回写策略
- Always:同步写回:每个命令执行完,立马同步到磁盘
- Everysec:缓冲区每秒写回磁盘
- No:操作系统控制
AOF重写
AOF重写结果其实就是 对旧日志文件中的多条命令,在重写后的新日志中变成了一条命令。
重写会影响主线程?
AOF日志是由主线程写的,但是AOF重写的 过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,但是fork子进程有可能会使主线程阻塞
- Redis主线程fork子进程时,内核需要创建用于管理子进程的相关数据结构,子进程要拷贝父进程的页表,这个过程耗时与redis实例的内存大小有关
- 子进程会和主线程共享内存。当主线程收到新写或修改的操作时,主线程会申请新的内存空间,用来保存新写或修改的数据,如果操作的是bigkey,主线程会因为申请大空间而面临阻塞风险
RDB
RDB是redis内存快照
两个命令来生成 RDB 文件:save、bgsave
- save:在主线程中执行,会导致阻塞
- bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞
写时复制
bgsave子进程是由主线程fork生成的,共享主线程的所有内存数据。bgsave子进程运行后,开始读取主线程的内存数据,并把它们写入RDB文件
采用写时复制策略,主线程更新数据会拷贝数据副本,在副本修改数据
fork期间会阻塞父进程?
- fork完成之前,会阻塞父进程,主要是父进程需要拷贝进程中的内存页表给子进程,每个进程都要有自己的内存页表
- 拷贝内存页表也需要花费时间,进程占用的内存越大,拷贝时间越久
一般采用混合模式:快照+AOF模式
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
2562.找出数组的串联值 class Solution { public: //返回两数串联后的值 long long is(int m,int n){ long long服务器托管网 ans=n; int i=0; while(n){ n/=10; i++…