内存和磁盘
为了不便了解,假如某公司暂存文件材料的柜子
,有多个格子,柜子还有一个专门的管理员小张
,他的工作就是按公司员工的命令在某个格子(key)存材料(value),取材料(value)。
这个柜子在办公室内为了不便疾速存取,也不关门也不锁,总之就是不便。
公司除了这个柜子
能够存储材料,还有一个专门的材料仓库
也能够存储材料,而且仓库有专人守护,保障材料个别状况必定丢不了。
这个小张
和柜子
就是是redis,其中柜子
就是内存,存取很快,但一重启数据就清空。
这个材料仓库
就是磁盘,存取比较慢,但文件不会失落。
公司员工就相当于客户端,能够给小张
发命令存取材料。
柜子只有一个管理员小张
对应redis的单线程。
本文例子里的所有人物就相当于执行程序的cpu
,脑子忘性为0,只能靠纸笔记录。
RDB
某天有个领导说这个柜子
用的很不便,但心愿材料不会失落。
于是有人提出计划,计划名叫RDB,思路比较简单,每隔一段时间,把以后材料存储的地位和内容全都记录到一个快照文件里,并把快照文件放到存储仓库
,快照文件的格局相似如下
某天保洁来了把柜子
清空了,材料都失落了(相当于redis重启),按仓库
中的快照文件还原材料即可。
具体隔多久存一次呐?能够有多种准则,比方 "60 秒内有至多有 100 个格子被改变"就快照一次。
redis:
RDB快照(snapshot)是redis默认的长久化计划,只有设置好保留的工夫策略(能够多个)就默认开启rdb,除此之外还能够设置快照文件名和保留的门路等:
save 3600 1 #3600 秒1次key变更save 300 100 #300秒100次key变更save 60 10000 #60 秒10000次key变更dbfilename dump.rdb ##存储文件名dir ./ ##存储门路
存储好之后,下次重启会间接按rdb文件复原数据(实现了长久化)。
内容如下(以二级制的模式压缩保留)
刚开始小张
本人去记录快照并去材料仓库存储,然而这个过程很慢,导致这期间其他人想存材料只能等。
为了解决这个问题,公司新给他配加一个人小李
,这样小张
还是干之前的活,小李
负责在规定条件下记录并存储快照文件,在小李
工作的期间(记录并去材料仓库存储),如果有新的存储变动,小张
还会告诉小李
。
redis:
下面小张
相当于主线程,由主线程去快照并长久化的形式叫save
,该过程是同步的阻塞客户端申请,小李
退出相当于新fork一个子线程专门解决rdb,这种叫bgsave(background save)
,该过程是异步的不阻断客户申请,而且过程中有新的变动还会同步(Copy-On-Write),redis默认应用bgsave
。
总结一下:bgsave
必定在性能上优于save
,因为不阻塞申请,然而新开一个过程必定要消耗更多资源。
RDB计划有一个致命的问题,小李
须要触发肯定条件才回去做快照工作,比方十分钟做一次,但在这十分钟内保洁来了把柜子清掉了(相当于redis重启),这非常种内新增的材料小李
还没来得及记录就丢了,而且再也找不回来了。
redis:
与其对应,rdb存储最大的问题就是容易造成数据失落,比方新数据还没来得及做快照,redis就重启了,那么这些新增的数据就丢了。
AOF
为了解决文件失落的问题,公司提出一个新计划,名曰AOF(append-only-file),就是让柜子管理员小张
在柜子
里放一张纸,每次收到员工的存储申请,解决完就把申请内容用记录到纸上,并在失当的机会把记录转到仓库
(落盘)。
那么什么是失当的机会呐?公司提出三种计划:
PlanA.每次有存储申请就记录一次。
PlanB.每隔一秒记录一次。
PlanC.公司下发的命令就记录一次。小张
能够依据公司要求切换计划。
有了这份AOF文件,当保洁清理掉所有柜子文件后,只有依照AOF文件的记录一条一条执行就会复原柜子原来的样子。
再看一眼AOF的记录
第一条和第四五条别离是01格存了A,B,C,这样显得文件有太多没用的指令,因为最终目标是为了复原数据,所以只有存第五条:“在01格存储了C”即可,前两条数据多余,而且会造成文件大,读写工夫慢,复原数据也慢。
这时候本分案另一个闲置人员小李
退场了,他负责整顿AOF文件,也就是重写,后果如下:
redis:
以上过程就是redis的AOF,开启AOF长久化形式,须要批改配置
appendonly yes # 开启AOFappendfsync always # 每次有新命令追加到 AOF 文件时就执行一次 fsync ,十分慢,也十分平安。appendfsync everysec# 每秒 fsync 一次,足够快,并且在故障时只会失落 1 秒钟的数据。appendfsync no # 从不 fsync ,将数据交给操作系统来解决。更快,也更不平安的抉择。
其中appendfsync三选一,别离对应实时同步,每秒同步,操作系统同步三种存储形式,安全性从高到低,效率从低到高,默认是everysec。
开启之后执行一条指令
set pq 217
查看AOF文件
外面的内容如下
其实就是记录每条命令。
上例中小李
的工作就是AOF重写,目标就是删除多余指令,redis是通过新fork一个线程来做重写的,能够通过配置auto-aof-rewrite-
参数来调整重写的策略。
比照一下: RDB形式不平安容易失落数据,AOF比拟平安,然而文件大、一条条命令执行来复原数据工夫长(即便有重写也达不到rdb的成果)
混合长久化
RDB、AOF两种计划各有优缺点,于是很快就有人发现了,为什么不两种形式混合应用呐。
计划如下:小李
再做重写的时候看一眼AOF文件,比方以后行是10行,记住,而后新做一个文件,存储RDB格局的快照数据,在这期间如果有新的指令来了小张
会存入原AOF文件,小李
做完快照看一眼原AOF文件,比方到了12行,代表这期间新增了两行,那么把这两行剪切下来粘到新文件中,最初用新的文件替换并笼罩原AOF文件(最终的AOF文件两种格局混搭),复原时候先复原RDB局部,再执行大量的AOF命令,很快就复原了数据而且还保障了平安。
redis:
应用redis很少应用 RDB形式来进行长久化,因为会失落大量数据。通常应用 AOF 日志重放,然而重放 AOF 日志性能绝对 RDB来说要十分慢,所以应用混合长久化形式最好,开启混合长久化须要配置(默认是开启的)
aof-use-rdb-preamble yes # 开启混合长久化
从下面的例子能够看出混合长久化是基于AOF的重写(只是应用RDB技术),所以AOF必须开启(并且配置重写策略),重写后的AOF个别如下
开启之后的益处下面也说了,平安的同时又重启快。
主从复制
公司一直壮大,用柜子的人也越来越多,而且大部分是为了查看,柜子倒是够用,但小张
及其疲乏,为了加重小张
的压力,公司决定多上几个柜子,每个柜子都配置不同的管理员,为了资源对立,每个柜子寄存的文件截然不同,大家须要存材料对立找小张
,须要读材料去找其它柜子的管理员即可,这样大大加重了小张
的压力。
按以上计划,小张
是主,其它管理员是从,这就是一个典型的主从构造。
那么问题来了,要保障每个柜子寄存的文件截然不同,怎么实现主从复制?
留神:下面介绍了长久化的计划,然而在主从复制时不肯定开启了长久化,资料库
可能不存在AOF和RDB文件,所以不能依附长久化来解决
计划如下:
比方上面的某个柜子管理员叫小美
1.小美
通知小张
我要同步数据
2.小张
告诉上司小李
做一个RDB快照文件(bgsave),与此同时小张
持续承受申请,并记录申请的内容(相似AOF,但不存入材料仓库)
3.小李
做完RDB快照也不必存库,间接发给小美
4.小美
清空柜子,按RDB快照从新安排柜子
5.小张
把这段时间新增的申请指令发给小美
6.小美
按新增命令批改柜子数据,此时两个柜子数据统一
7.之后小张
承受新命令时本人存完,再通知小美
存一下,此时两个柜子实时同步
redis:
redis实现主从复制就是依照下面例子的思路来的:
master收到同步命令后,会通过bgsave异步生成最新的rdb快照文件,这期间期间,master会持续接管客户端的申请,它会把这些可能批改数据集的申请缓存在内存中。rdb实现当前,master会把这份rdb发送给slave,slave会把接管到的数据加载到内存中。而后,master再将之前缓存在内存中的指令集发送给slave。
主从复制(断点续传)
还是下面的例子,小美
的柜子通过主从复制始终放弃和小张
统一,然而问题呈现了:小美
有时候要去上厕所(从节点掉了),那么这段时间小张
柜子里的新增的数据就没方法同步到小美
的柜子里了。
为了解决这个问题,小张
每次接管到新的写命令都会记录在一个小本上存到柜子里(内存),而且只保留最近的几条记录,比方10条(不能存太多,一是查找吃力,二是占用柜子空间),其它都删掉,并且每条记录都有序号01,02,03...,再同步命令的时候,小美
也记录下本人以后的序号(偏移量),这样小美
上厕所回来后只有通知小张
序号,小张
把序号前面的命令发给小美
,就实现了断点续传。
如果小美
身材不难受,去厕所去了很久,回来之后把序号报给小张
,小张
发现这个序号早就不在本人的小本本上了,这时候就依照之前的初始复制计划整体复制一遍即可。
redis:
断点续传根本就是如上例这么个形式,master会在其内存中开拓缓存队列,缓存最近一段时间的指令,master和它所有的slave都保护了复制的数据下标offset,因而,当网络连接断开后,slave会申请master持续进行未实现的复制,从所记录的数据下标开始。如果从节点数据下标offset太旧,曾经不在master的缓存队列里了,那么将会进行一次全量数据的复制。
总结
其实长久化也好,主从复制也好,redis的诉求都一样,就是不阻塞用户申请,在jvm垃圾回收也有相似的诉求,即尽量避免stw(stop-the-world)。
而解决的计划简略概括:增量更新,也就是对于同一数据后盾线程一边记,用户申请一边改,在过程中记录改了什么,最初把后果按改变内容调整一下就实现了最终的数据备份。
over~新人求赞!