概览Redis篇三:RDB快照

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 什么是RDB 所谓RDB,即Redis DataBase。是对Redis做的一个内存快照,即将内存中的数据在某一个时刻的状态记录。 对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写到磁盘上,也就是快照。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为 RDB 文件。 和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。 給哪些内存数据做快照 給哪些内存数据做快照,这关系到快照的执行效率。 Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照,也就是说,把内存中的所有数据都记录到磁盘中。这样做的好处是,一次性记录了所有数据,一个都不少。 但给内存的全量数据做快照,把它们全部写入磁盘也会花费很多时间。而且,全量数据越多,RDB 文件就越大,往磁盘上写数据的时间开销就越大。 这里我们要做一个“灵魂之问”:RDB文件的生成会阻塞主线程吗? Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。 save:在主线程中执行,会导致阻塞; bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。 因此我们可以使用bgsave命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对 Redis 的性能影响。 快照时数据能修改吗 这个问题非常重要,这是因为,如果数据能被修改,那就意味着 Redis 还能正常处理写操作。否则,所有写操作都得等到快照完了才能执行,性能一下子就降低了。 如果我们使用save命令,显然是不能修改的,以为主线程已经被阻塞掉了。 如果使用bgsave命令,看起来数据还是可以修改的,因为主线程没有被阻塞。但避免阻塞和正常处理写操作并不是一回事。此时,主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。 为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。 简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。 此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。...

July 22, 2022 · 1 min · 李昌

概览Redis篇五:哨兵

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 什么是哨兵,哨兵有什么用 哨兵其实就是一个运行在特殊模式下的 Redis 进程,主从库实例运行的同时,它也在运行。哨兵主要负责的就是三个任务:监控、选主(选择主库)和通知。 有了哨兵,我们就可以在主库故障的情况下快速实现主从库自动切换。 哨兵机制的基本流程 监控 哨兵在运行时,会周期性地给所有的主从库发送 PING 命令,检测它们是否仍然在线运行。如果从库没有在规定时间内响应哨兵的 PING 命令,哨兵就会把它标记为“下线状态”;同样,如果主库也没有在规定时间内响应哨兵的 PING 命令,哨兵就会判定主库下线,然后开始自动切换主库的流程。 选主 主库挂了以后,哨兵就需要从很多个从库里,按照一定的规则选择一个从库实例,把它作为新的主库。 通知 在选出新的主库后,哨兵会把新主库的连接信息发给其他从库,让它们执行 replicaof 命令,和新主库建立连接,并进行数据复制。同时,哨兵会把新主库的连接信息通知给客户端,让它们把请求操作发到新主库上。 哨兵如何判断主库是否下线 主观下线 哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为“主观下线” 如果检测的是从库,那么,哨兵简单地把它标记为“主观下线”就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。 但是,如果检测的是主库,那么,哨兵还不能简单地把它标记为“主观下线”,开启主从切换。因为很有可能存在这么一个情况:那就是哨兵误判了,其实主库并没有故障。可是,一旦启动了主从切换,后续的选主和通知操作都会带来额外的计算和通信开销。 因此我们要特别注意误判的情况。 为了减少误判,可以采用多实例组成的集群模式进行部署,这也被称为哨兵集群。引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。 客观下线 当大多数的哨兵实例,都判断主库已经“主观下线”了,主库才会被标记为“客观下线”,这个叫法也是表明主库下线成为一个客观事实了。 如何选择新主库 简单来说,哨兵选择新主库的过程可以描述为“筛选+打分”。筛选是说,我们在多个从库中,先按照一定的筛选条件,把不符合条件的从库去掉。而打分意思是按照一定的规则,给剩下的从库逐个打分,将得分最高的从库选为新主库, 那么筛选和打分的标准是怎样的? 在筛选时,除了要检查从库的当前在线状态,还要判断它之前的网络连接状态。使用配置项 down-after-milliseconds * 10。其中,down-after-milliseconds 是我们认定主从库断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从库的网络状况不好,不适合作为新主库。 筛掉了不适合做主库的从库后,需要对剩下的从库进行打分。分别按照一下三个规则进行三轮: 优先级最高的从库得分高。 用户可以通过 slave-priority 配置项,给不同的从库设置不同优先级。...

July 22, 2022 · 1 min · 李昌

概览Redis篇六:切片集群

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 什么是切片集群,有什么用 切片集群,也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存。 当Redis保存大量数据时,其在进行RDB持久化时需要fork一个子进程,而fork子进程的用时和Redis的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长。因此如果Redis保存了大量数据,会导致Redis响应变慢。 数据切片后,在多个实例之间如何分布 从 3.0 开始,官方提供了一个名为 Redis Cluster 的方案,用于实现切片集群。Redis Cluster 方案中就规定了数据和实例的对应规则。 Redis Cluster 方案采用哈希槽Hash Slot,来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。 具体的映射过程分为两大步:首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。 在部署 Redis Cluster 方案时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。当然,也可以使用cluster meet命令手动建立实例间的连接,形成集群,再使用cluster addslots 命令,指定每个实例上的哈希槽个数。在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。...

July 22, 2022 · 1 min · 李昌

概览Redis篇四:主从

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 Redis的高可靠性 Redis 具有高可靠性,又是什么意思呢?其实,这里有两层含义:一是数据尽量少丢失,二是服务尽量少中断。 AOF 和 RDB 保证了前者,而对于后者,Redis 的做法就是增加副本冗余量,将一份数据同时保存在多个实例上。即使有一个实例出现了故障,需要过一段时间才能恢复,其他实例也可以对外提供服务,不会影响业务使用。 Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。 读操作:主库、从库都可以接收; 写操作:首先到主库执行,然后,主库将写操作同步给从库。 为什么要读写分离 如果在上图中,不管是主库还是从库,都能接收客户端的写操作,那么,一个直接的问题就是:如果客户端对同一个数据(例如 k1)前后修改了三次,每一次的修改请求都发送到不同的实例上,在不同的实例上执行,那么,这个数据在这三个实例上的副本就不一致了(分别是 v1、v2 和 v3)。在读取这个数据的时候,就可能读取到旧的值。 当然我们可以使这个数据在三个实例上保持一致,但这涉及到加锁,实例间协商等一系列操作,会带来巨额的开销。 而主从库模式一旦采用了读写分离,所有数据的修改只会在主库上进行,不用协调三个实例。主库有了最新的数据后,会同步给从库,这样,主从库的数据就是一致的。 主从库如何进行第一次同步 当我们启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。 例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据: replicaof 172.16.19.3 6379 主从库间数据第一次同步有三个阶段: 主从库间建立连接、协商同步。主要是为全量复制做准备。在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。 具体来说,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数. runID,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。...

July 22, 2022 · 2 min · 李昌

概览Redis篇二:AOF日志

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 AOF: Append Only File AOF日志的WAL 数据库中的WAL是Write-Ahead Logging, 为先写日志后执行。而Redis中的WAL为Write Ahead Log,先执行后写日志。 为了避免额外的开销,Redis在向AOF里面记录日志时,不回去对这些命令进行语法检查,因此,如果先记录日志再执行命令的话,日志中有可能记录了错误的命令,Redis在使用日志恢复数据时,就可能会出错。 AOF日志中记录了什么内容 有如下命令: set testkey testvalue 则AOF日志内容为: *3 $3 set $7 testkey $9 testvalue 其中“*3”表示当前命令有3个部分,每部分都由“$+数字”开头,后面紧跟具体的命令、键或值。 AOF的潜在风险 AOF使用先执行,再写日志的方式,这样可以避免记录错误的命令,同时不会阻塞当前的写操作。 但这样也带来了一些潜在风险: 刚执行完一个命令,没来得及记日志就宕机了,这个命令和相应的数据就有丢失的风险。 AOF避免了对当前命令的阻塞,但AOF写日志是在主线程中执行的,可能会给下一个操作带来阻塞风险。 这就需要我们对AOF写日志的实际进行把控。 AOF的三种写回策略 Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘; Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘; No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。 针对避免主线程阻塞和减少数据丢失问题,这三种写回策略都无法做到两全其美。原因如下: “同步写回”可以做到基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,不可避免地会影响主线程性能; 虽然“操作系统控制的写回”在写完缓冲区后,就可以继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了; “每秒写回”采用一秒写回一次的频率,避免了“同步写回”的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。所以,这只能算是,在避免影响主线程性能和避免数据丢失两者间取了个折中。 总结一下:...

July 18, 2022 · 1 min · 李昌

概览Redis篇一:单线程模型

极客时间《Redis 核心技术与实战》学习笔记 概览Redis篇一:单线程模型 概览Redis篇二:AOF日志 概览Redis篇三:RDB快照 概览Redis篇四:主从 概览Redis篇五:哨兵 概览Redis篇六:切片集群 Redis单线程模型 Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。 为什么Redis采用单线程 通常的程序设计都采用多线程来提高性能,获得更快的响应速度。 但采用多线程模型将不可避免地面对以下问题: 多个线程对同一资源的数据竞争 因解决数据竞争而导致的性能损耗 增加系统复杂度,降低系统代码的易调试性和可维护性 为啥Redis单线程还这么快 主要是两点: Redis大部分操作在内存上完成,并采用了高效的数据结构 Redis采用了多路复用机制

July 9, 2022 · 1 min · 李昌