当前位置: 首页 > 后端技术 > Java

漫画理解Redis持久化与主从复制

时间:2023-04-01 14:15:57 Java

内存与磁盘为了便于理解,假设一个公司将文件临时存放在一个有多个格子的柜子里,柜子里有一个专门的管理员小张。他的工作是按公司员工的命令,将数据(值)存储在某个网格(键)中,并检索数据(值)。为了方便快速取用,这个柜子在办公室里没有关门也没有上锁。总之,很方便。除了这个可以存放数据的柜子外,公司还有专门的数据仓库也可以存放数据,并且仓库有专人看守,保证正常情况下数据不会丢失。这个小张和柜子是redis,柜子是内存,访问速度快,但是一重启数据就清空了。这个数据仓库是一个磁盘,访问比较慢,但是文件不会丢失。公司员工相当于客户,可以向张某下达命令访问数据。内阁只有一个管理员,小张,对应redis的单线程。本文例子中的所有人物都相当于执行程序的cpu,他们的大脑记忆为0,只能用纸笔记录。一天,RDB的一位领导说,这个柜子用起来很方便,但希望数据不要丢失。于是有人提出了一个方案,叫做RDB。这个想法比较简单。每隔一段时间,将当前数据存储的位置和内容记录在快照文件中,并将快照文件放入存储仓库。快照文件的格式类似如下有一天打扫来了,清空了柜子,数据全丢了(相当于重启了redis),按照仓库中的快照文件恢复数据即可。它多久保存一次?有很多原则,比如“60秒内至少有100个格子被改变”,然后快照。redis:RDB快照(snapshot)是redis默认的持久化方案。只要设置保存(多次)的时间策略,RDB就会默认开启。另外还可以设置快照文件名和保存路径等:save36001#3600seconds1keychangesave300100#300seconds100keychangesave6010000#60seconds10000key更改dbfilenamedump.rdb##存储文件名dir./##存储路径storage之后,下次重启会直接根据rdb文件恢复数据(实现持久化)。内容如下(以二级系统的形式压缩保存)。起初,小张自己记录快照并存储在数据仓库中,但这个过程非常缓慢,导致其他人在这期间保存数据不得不等待。为了解决这个问题,公司新添了一个人小李,让小张继续做之前的工作。小李负责在指定条件下记录和存储快照文件。小李工作期间(记录到数据仓库Storage),如果有新的存储变化,小张也会通知小李。Redis:上面的小张相当于主线程。从主线程快照和持久化的方法称为保存。此进程同步阻止客户端请求。小李的加入相当于一个新的fork,多了一个专门处理RDB的子线程。这个叫做bgsave(后台保存),这个过程是异步的,不会阻塞客户的请求,过程中新的变化会被同步(Copy-On-Write)。Redis默认使用bgsave。总结一下:bgsave在性能上肯定比save好,因为它不会阻塞请求,但是开启一个新的进程肯定会消耗更多的资源。RDB解决方案有一个致命的问题。小李在回去做快照工作之前需要触发一定的条件,比如十分钟一次,但是在这十分钟内,cleaning来了,清柜(相当于重启redis),这是很不一样的。小李里面新加的信息还没来得及记录就丢了,再也找不回来了。redis:与之对应,rdb存储最大的问题就是容易造成数据丢失。比如新的数据还没来得及做快照,redis就重启了,这些新加入的数据就丢失了。AOF为了解决文件丢失的问题,公司提出了一种新的解决方案,叫做AOF(append-only-file),就是让柜员小张在柜子里放一张纸。完成后,将要求的内容记录在纸上,并适时将记录转入仓库(安置)。那么什么是合适的时间呢?公司提出三个方案:方案A,每次有入库需求就记录下来。计划B。记录每一秒。PlanC发布的命令。公司将被记录一次。小张可以根据公司的要求转换计划。有了这个AOF文件,清理完所有的柜子文件后,只要按照AOF文件的记录一个一个的做,就可以把柜子还原成原来的样子了。再看一下AOF的第一条和第四条和第五条记录,分别是01中的A、B、C。看来文件中无用的指令太多了,因为最终目的是恢复数据,所以只保存第五项:“Cisstoredincell01”即可,前两个数据冗余,会造成大文件,读写时间慢,数据恢复慢。这时,本案的另一闲人小李上台了。他负责整理AOF文件,也??就是重写。结果如下:redis:上面的过程就是redis的AOF。启用AOF持久化模式,需要修改配置appendonlyyes#开启AOFappendfsyncalways#每次向AOF文件追加新命令时执行fsync,速度很慢,也很安全。appendfsynceverysec#每秒fsync一次,足够快,失败时只丢失1秒的数据。appendfsyncno#从不fsync,将数据交给操作系统处理。更快,更不安全的选择。其中,appendfsync可以选择三种存储方式,分别对应实时同步、每秒同步、操作系统同步。安全性从高到低,效率从低到高。默认值为每秒。打开后执行一条命令setpq217查看AOF文件内容如下,其实就是记录每条命令。上面的例子中,小李的工作是AOF重写,目的是删除冗余指令,通过fork一个新的线程来重写redis,可以通过配置auto-aof-rewrite-参数来调整重写策略。比较:RDB方式不安全,容易丢数据,AOF更安全,但是文件大,一条一条执行命令恢复数据需要很长时间(即使有重写,效果RDB无法实现)。MixedPersistentRDB和AOF两种方案各有优缺点,所以很快就有人发现为什么不把这两种方式结合起来使用。计划如下:小李再改写的时候看一眼AOF文件。比如当前行是10行。记住,然后新建一个文件,以RDB格式存储快照数据。小张将原始AOF文件保存下来,小李抓拍完后看一看原始AOF文件。比如,如果到了第12行,说明这期间增加了两行,然后将这两行剪切下来粘贴到新文件中,最后用新文件替换覆盖原来的AOF文件(最后AOF文件是这两种格式的混合)。恢复的时候,先恢复RDB部分,再执行少量的AOF命令。数据快速恢复,安全有保障。Redis:使用redis的时候很少用RDB做持久化,因为会丢失很多数据。通常使用AOF日志重放,但是重放AOF日志的性能相对于RDB非常慢,所以最好使用混合持久化。开启混合持久化需要配置(默认开启)aof-use-rdb-preambleyes#开启混合持久化从上面的例子我们可以看出混合持久化是基于AOF重写的(只是使用RDB技术),所以必须启用AOF(并配置重写策略)。重写后的AOF启用后一般如下好处上面也说了,安全同时重启快。主从复制公司不断壮大,使用机柜的人也越来越多,而且大部分是用来检查的。柜子够用了,只是小张很累。为了减轻小张的压力,公司决定再增加几个柜子,每个柜子配备不同的管理员。为了统一资源,每个柜子里存放的文件都是一模一样的。每个人都需要保存数据并找到小张。如果需要读取数据,可以找其他柜的管理员。紧张。按照上面的方案,小张是master,其他管理员都是slave。这是典型的主从结构。那么问题来了,要保证每个柜子里存放的文件完全一样,如何实现主从复制呢?注意:上面介绍了持久化方案,但是主从复制时可能没有开启持久化。数据库中可能不存在AOF和RDB文件,所以不能依赖持久化解决方案如下:比如下面某柜管理工作人员是小梅1.小梅告诉小张我要同步数据2.小张通知下属小李做一个RDB快照文件(bgsave),同时小张继续接受请求,记录请求内容(类似AOF,但不存入数据仓库)3.小李不需要保存RDB快照,直接发给小梅4.小梅根据RDB快照清柜,重新排柜5.小张上报这期间有新请求发送指令给小梅6.小梅修改根据新命令的机柜数据。此时两个机柜的数据是一致的。同步redis:Redis按照上例的思路实现主从复制:master收到同步命令后,会通过bgsave异步生成最新的rdb快照文件。在此期间,master会不断接收客户端请求,它会将这些可能修改数据集的请求缓存在内存中。rdb完成后,master将rdb发送给slave,slave将接收到的数据加载到内存中。然后,master将之前缓存在内存中的指令集发送给slave。主从复制(断点续传)还是上面的例子。小梅的柜子一直通过主从复制和小张保持一致,但是出现了一个问题:小梅有时候要上厕所(从节点掉线了),所以这一段时间小张的柜子里新增的数据无法同步到小美的储物柜。为了解决这个问题,小张每次收到一个新的写命令,都会记录在一个小本子里,存放在柜子(内存)中,只保留最近的几条记录,比如10条(不要太多),一是查找费力,二是占用柜子空间),其他的都删除了,每条记录都有序号01、02、03……,同步命令的时候,小美也记录了她当前流水号(offset),这样小美上厕所回来,只需要告诉小张流水号,小张就会把流水号后面的命令发给小美,中断的传输就完成了.小梅身体不舒服,上厕所就跑了半天,回来就把序号报给小张。能。Redis:断点续传和上面的例子基本一样。master会在内存中开辟一个缓存队列来缓存最近一段时间的指令。master及其所有slave维护复制的数据下标偏移量。因此,当网络连接断开后,slave会请求master继续未完成的复制,从记录的数据下标开始。如果slave节点数据的下标偏移量太旧,已经不在master的缓存队列中,则会进行全量数据拷贝。总结其实不管是持久化还是主从复制,redis都有一个共同的诉求,那就是不阻塞用户请求。在jvm垃圾回收中也有类似的诉求,就是尽量避免STW(stop-the-world)。解决方案简单总结一下:增量更新,即对于同一个数据,后台线程在用户请求变化的同时进行记录,记录过程中发生了什么变化,最后根据变化的内容调整结果,完成最终的数据备份。over~新人求好评!