个人主页:道友老李
欢迎加入社区:道友老李的学习社区
Redis底层原理
持久化
Redis固然是个内存数据库,但是Redis支持RDB和AOF两种持久化机制,将数据写往磁盘,可以有效地避免因进程退出造成的数据丢失题目,当下次重启时使用之前持久化的文件即可实现数据规复。
RDB
RDB持久化是把当前进程数据生成快照保存到硬盘的过程。所谓内存快照,就是指内存中的数据在某一个时候的状态记录。这就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。RDB 就是Redis DataBase 的缩写。
给哪些内存数据做快照?
Redis 的数据都在内存中,为了提供全部数据的可靠性保证,它执行的是全量快照,也就是说,把内存中的全部数据都记录到磁盘中。但是,RDB 文件就越大,往磁盘上写数据的时间开销就越大。
RDB文件的生成是否会阻塞主线程
Redis 提供了两个手动下令来生成 RDB 文件,分别是 save 和 bgsave。
save:在主线程中执行,会导致阻塞;对于内存比较大的实例会造成长时间阻塞,线上情况不建议使用。
bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是Redis RDB 文件生成的默认配置。
下令实战演示
除了执行下令手动触发之外,Redis内部还存在主动触发RDB 的持久化机制,例如以下场景:
1)使用save相关配置,如“save m n”。表示m秒内数据集存在n次修改时,主动触发bgsave。
2)假如从节点执行全量复制操纵,主节点主动执行bgsave生成RDB文件并发送给从节点。
3)执行debug reload下令重新加载Redis 时,也会主动触发save操纵。
4)默认情况下执行shutdown下令时,假如没有开启AOF持久化功能则主动执行bgsave。
关闭RDB持久化,在课程报告的Redis版本(6.2.4)上,是将配置文件中的save配置改为 save “”
bgsave执的行流程
为了快照而暂停写操纵,肯定是不能接受的。所以这个时候,Redis 就会借助操纵系统提供的写时复制技能(Copy-On-Write, COW),在执行快照的同时,正常处理写操纵。
bgsave 子进程是由主线程 fork 生成的,可以共享主线程的全部内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
假如主线程对这些数据也都是读操纵(例如图中的键值对 A),那么,主线程和bgsave 子进程相互不影响。但是,假如主线程要修改一块数据(例如图中的键值对 B),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。
这既保证了快照的完整性,也允许主线程同时对数据举行修改,避免了对正常业务的影响。
RDB文件
RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配置指定。
可以通过执行config set dir {newDir}和config set dbfilename (newFileName}运行期动态执行,当下次运行时RDB文件会保存到新目录。
Redis默认采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存巨细,默认开启,可以通过参数config set rdbcompression { yes |no}动态修改。
固然压缩RDB会消耗CPU,但可大幅降低文件的体积,方便保存到硬盘或通过网维示络发送给从节点,因此线上建议开启。
假如 Redis加载破坏的RDB文件时拒绝启动,并打印如下日志:
- Short read or OOM loading DB. Unrecoverable error,aborting now.
复制代码 这时可以使用Redis提供的redis-check-rdb工具(老版本是redis-check-dump)检测RDB文件并获取对应的错误报告。
RDB的优缺点
RDB的优点
RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。
好比每隔几小时执行bgsave备份,并把 RDB文件拷贝到长途呆板或者文件系统中(如hdfs),,用于劫难规复。
Redis加载RDB规复数据远远快于AOF的方式。
RDB的缺点
RDB方式数据没办法做到实时持久化/秒级持久化。由于bgsave每次运行都要执行fork操纵创建子进程,属于重量级操纵,频繁执行成本过高。
RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的题目。
Redis中RDB导致的数据丢失题目
针对RDB不得当实时持久化的题目,Redis提供了AOF持久化方式来解决。
如下图所示,我们先在 T0 时候做了一次快照(下一次快照是T4时候),然后在T1时候,数据块 5 和 8 被修改了。假如在T2时候,呆板宕机了,那么,只能按照 T0 时候的快照举行规复。此时,数据块 5 和 8 的修改值由于没有快照记录,就无法规复了。
所以这里可以看出,假如想丢失较少的数据,那么T4-T0就要尽大概的小,但是假如频繁地执行全量
快照,也会带来两方面的开销:
1、频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,轻易造成恶性循环。
2、另一方面,bgsave 子进程需要通过 fork 操纵从主线程创建出来。固然子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。假如频繁fork出bgsave 子进程,这就会频繁阻塞主线程了。
所以基于这种情况,我们就需要AOF的持久化机制。
AOF
AOF(append only file)持久化:以独立日志的方式记录每次写下令,重启时再重新执行AOF文件中的下令到达规复数据的目标。AOF的重要作用是解决了数据持久化的实时性,现在已经是Redis持久化的主流方式。理解把握好AOF持久化机制对我们兼顾数据安全性和性能非常有帮助。
使用AOF
开启AOF功能需要设置配置:appendonly yes,默认不开启。
AOF文件名通过appendfilename配置设置,默认文件名是appendonly.aof。保存路径同RDB持久化方式一致,通过dir配置指定。
AOF的工作流程
AOF的工作流程重要是4个部门:下令写入( append)、文件同步( sync)、文件重写(rewrite)、重启加载( load)。
下令写入
AOF下令写入的内容直接是RESP文本协议格式。例如lpush lijin A B这条下令,在AOF缓冲区会追加如下文本:
- *3\r\n$6\r\nlupush\r\n$5\r\nlijin\r\n$3\r\nA B
复制代码 看看 AOF 日志的内容。其中,“*3”表示当前下令有三个部门,每部门都是由“$+数字”开头,后面紧跟着 详细的下令、键或值。这里,“数字”表示这部门中的下令、键或值一共有多少字节。例如,“$3 set”表示这部门有 3 个字节,也就是“set”下令。
1 )AOF为什么直接采用文本协议格式?
文本协议具有很好的兼容性。开启AOF后,全部写入下令都包含追加操纵,直接采用协议格式,避免了二次处理开销。文本协议具有可读性,方便直接修改和处理。
2)AOF为什么把下令追加到aof_buf中?
Redis使用单线程相应下令,假如每次写AOF文件下令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入缓冲区aof_buf中,尚有另一个利益,Redis可以提供多种缓冲区同步硬盘的计谋,在性能和安全性方面做出平衡。
Redis提供了多种AOF缓冲区同步文件计谋,由参数appendfsync控制。
always
同步写回:每个写下令执行完,立马同步地将日志写回磁盘;
everysec
每秒写回:每个写下令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
no
操纵系统控制的写回:每个写下令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操纵系统决定何时将缓冲区内容写回磁盘,通常同步周期最长30秒。
很显着,配置为always时,每次写入都要同步AOF文件,在一般的SATA 硬盘上,Redis只能支持约莫几百TPS写入,显然跟Redis高性能特性南辕北辙,不建议配置。
配置为no,由于操纵系统每次同步AOF文件的周期不可控,而且会加大每次同步硬盘的数据量,固然提拔了性能,但数据安全性无法保证。
配置为everysec,是建议的同步计谋,也是默认配置,做到兼顾性能和数据安全性。理论上只有在系统突然宕机的情况下丢失1秒的数据。(严格来说最多丢失1秒数据是禁绝确的)
想要获得高性能,就选择 no 计谋;假如想要得到高可靠性保证,就选择always 计谋;假如允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择everysec 计谋。
重写机制
随着下令不断写入AOF,文件会越来越大,为相识决这个题目,Redis引入AOF重写机制压缩文件体积。AOF文件重写是把Redis进程内的数据转化为写下令同步到新AOF文件的过程。
重写后的AOF 文件为什么可以变小?有如下原因:
1)进程内已经超时的数据不再写入文件。
2)旧的AOF文件含有无效下令,如set a 111、set a 222等。重写使用进程内数据直接生成,如许新的AOF文件只保留最终数据的写入下令。
3)多条写下令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为: lpush list a b c。为了防止单条下令过大造成客户端缓冲区溢出,对于list、set、hash、zset等范例操纵,以64个元素为界拆分为多条。
AOF重写降低了文件占用空间,除此之外,另一个目标是:更小的AOF文件可以更快地被Redis加载。
AOF重写过程可以手动触发和主动触发:
手动触发:直接调用bgrewriteaof下令。
主动触发:根据auto-aof-rewrite-min-size和 auto-aof-rewrite-percentage参数确定主动触发时机。
auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默以为64MB。
auto-aof-rewrite-percentage :代表当前AOF 文件空间(aof_currentsize)和上一次重写后AOF 文件空间(aof_base_size)的比值。
别的,假如在Redis在举行AOF重写时,有写入操纵,这个操纵也会被写到重写日志的缓冲区。如许,重写日志也不会丢失最新的操纵。
重启加载
AOF和 RDB 文件都可以用于服务器重启时的数据规复。redis重启时加载AOF与RDB的顺序是怎么样的呢?
1,当AOF和RDB文件同时存在时,优先加载AOF
2,若关闭了AOF,加载RDB文件
3,加载AOF/RDB成功,redis重启成功
4,AOF/RDB存在错误,启动失败打印错误信息
文件校验
加载破坏的AOF 文件时会拒绝启动,对于错误格式的AOF文件,先举行备份,然后采用redis-check-aof --fix下令举行修复,对比数据的差别,找出丢失的数据,有些可以人工修改补全。
AOF文件大概存在末了不完整的情况,好比呆板突然掉电导致AOF尾部文件下令写入不全。Redis为我们提供了aof-load-truncated 配置来兼容这种情况,默认开启。加载AOF时当遇到此题目时会忽略并继续启动,同时如下警告日志。
RDB-AOF混淆持久化
通过 aof-use-rdb-preamble 配置项可以打开混淆开关,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改
该状态开启后,假如执行bgrewriteaof下令,则会把当前内存中已有的数据弄成二进程存放在aof文件中,这个过程模拟了rdb生成的过程,然后Redis后面有其他下令,在触发下次重写之前,依然采用AOF追加的方式
Redis持久化相关的题目
主线程、子进程和背景线程的联系与区别?
进程和线程的区别
从操纵系统的角度来看,进程一般是指资源分配单元,例如一个进程拥有本身的堆、栈、虚存空间(页表)、文件描述符等;
而线程一般是指 CPU 举行调度和执行的实体。
一个进程启动后,没有再创建额外的线程,那么,如许的进程一般称为主进程或主线程。
Redis 启动以后,本身就是一个进程,它会接收客户端发送的请求,并处理读写操纵请求。而且,接收请求和处理请求操纵是 Redis 的重要工作,Redis 没有再依赖于其他线程,所以,我一般把完成这个重要工作的 Redis 进程,称为主进程或主线程。
主线程与子进程
通过fork创建的子进程,一般和主线程会共用同一片内存区域,所以上面就需要使用到写时复制技能确保安全。
背景线程
从 4.0 版本开始,Redis 也开始使用pthread_create 创建线程,这些线程在创建后,一般会自行执行一些使命,例如执行异步删除使命
Redis持久化过程中有没有其他潜在的阻塞风险?
当Redis做RDB或AOF重写时,一个必不可少的操纵就是执行fork操纵创建子进程,对于大多数操纵系统来说fork是个重量级错误。固然fork创建的子进程不需要拷贝父进程的物理内存空间,但是会复制父进程的空间内存页表。例如对于10GB的Redis进程,需要复制约莫20MB的内存页表,因此fork操纵耗时跟进程总内存量痛痒相关,假如使用虚拟化技能,特别是Xen虚拟机,fork操纵会更耗时。
fork耗时题目定位:
对于高流量的Redis实例OPS可达5万以上,假如fork操纵耗时在秒级别将拖慢Redis几万条下令执行,对线上应用延迟影响非常显着。正常情况下fork耗时应该是每GB消耗20毫秒左右。可以在info stats统计中查latest_fork_usec指标获取近来一次fork操纵耗时,单元微秒。
如何改善fork操纵的耗时:
1)优先使用物理机或者高效支持fork操纵的虚拟化技能
2)控制Redis实例最大可用内存,fork耗时跟内存量成正比,线上建议每个Redis实例内存控制在10GB 以内。
3)降低fork操纵的频率,如适度放宽AOF主动触发时机,避免不必要的全量复制等。
为什么主从库间的复制不使用 AOF?
1、RDB 文件是二进制文件,无论是要把 RDB 写入磁盘,还是要通过网络传输 RDB,IO服从都比记录和传输 AOF 的高。
2、在从库端举行规复时,用 RDB 的规复服从要高于用 AOF。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |