redis学习笔记-day2

1.redis持久化

1.AOF日志
1.aof概念

aof日志是写后日志,就是redis先执行命令,把数据写入内存,才记录日志。记录的是redis收到的每一条命令,以文本形式保存。后写日志,可以不对命令进行语法检查,避免出现记录错误命令。但是有两个潜在风险,一执行完命令没有记录宕机了,命令没有记录,所以无法用日志进行恢复。二写日志是在主线程执行,写入磁盘,磁盘写压力大,导致写盘很慢,会导致后续操作无法继续执行。对次,aof提供我们三个选择也就是配置项appendsync的三个可选值:

  • always:同步写回,每个命令执行完,立马同步将日志写回磁盘 。优点可靠性高数据基本不丢失 缺点每个写命令都要落盘性能影响较大

  • everysec每秒写回。先把日志写到aof文件的的内存缓冲区,每隔一秒把缓冲区的内容写入磁盘。 优点性能适中 缺点 宕机时丢失一秒内的数据

  • no:操作系统控制的写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,由操作系统决定何时写回磁盘。优点性能好缺点宕机时丢失数据较多。

随着命令越来越多,aof文件越来越大,需要小心文件过大导致的性能问题:一是文件系统本身对文件大小有限制无法保存过大文件二是如果文件太大,之后追加命令记录的话,效率降低。三是如果发生宕机,aof记录的命令要一个个被重新执行用于故障恢复,如果文件太大,非常缓慢影响使用。

aof重写机制就是在重写时,redis根据数据库的现状创建一个新的aof文件,然后都每一个键值对用一条命令记录,就是多变一,多条命令变成一条命令。缩小文件的大小,但是重写还是非常耗时。

aof重写和主线程写回不同,重写过程是由后台进行bgwritreaof来完成的。重写的过程总结为一个拷贝两处日志。

  • 一个拷贝是指每次执行重写时,主线程fork出后台的bgwriteaof子进程,此时,fork会把主线程的内存拷贝一份给bgwriteaof子进程,这里面包含了数据库的最新数据,然后这个子进程在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。

  • 两处日志是第一处日志就是指向正在使用的aof日志,redis会把这个操作写到它的缓冲区。第二处日志就是指新的aof重写日志,这个操作也会写到重写日志的缓冲区

总结来说,每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。

2.AOF重写过程中,有没有其他潜在的风险?
  • Redis 主线程 fork 创建 bgrewriteaof 子进程时,内核需要创建用于管理子进程的相关数据结构,这些数据结构在操作系统中通常叫作进程控制块(Process Control Block,简称为 PCB)。内核要把主线程的 PCB 内容拷贝给子进程。这个创建和拷贝过程由内核执行,是会阻塞主线程的。而且,在拷贝过程中,子进程要拷贝父进程的页表,这个过程的耗时和 Redis 实例的内存大小有关。如果 Redis 实例内存大,页表就会大,fork 执行时间就会长,这就会给主线程带来阻塞风险。
  • bgrewriteaof 子进程会和主线程共享内存。当主线程收到新写或修改的操作时,主线程会申请新的内存空间,用来保存新写或修改的数据,如果操作的是 bigkey,也就是数据量大的集合类型数据,那么,主线程会因为申请大空间而面临阻塞风险。因为操作系统在分配内存空间时,有查找和锁的开销,这就会导致阻塞。
    AOF重写为什么不共享使用AOF本身的日志?
    都用AOF日志的话,主线程要写,bgwriteaof子进程也要写,两者会竞争文件系统的锁,对主线程的性能造成影响。
2.RDB 快照
1.rdb基本概念

内存快照。所谓内存快照就是指内存中的数据在某一时刻的状态记录。redis,把某一时刻的状态以文件的形式写到磁盘上,也就是快照,这个文件被称为RDB文件,就是Redis DataBase 的缩写。
记录某一时刻的数据,并不是操作,所以数据恢复直接把文件读入内存。

2.rdb的问题
  • 是给哪些内存数据做快照
    为了数据可靠性,全量快照,所有数据都记录。所以花费时间,数据越多,文件越大,越耗时。是否会阻塞主线程?
    redis提供2个命令生成RDB文件,save在主线程中执行,会导致阻塞。bgsave创建一个子进程,专门写入RDB文件,避免主线程的则赛,这也是RedisRDB文件生成的默认配置。
  • 快照时数据能修改吗
    redis会借助操作系统提供的写时复制技术,在执行快照同时,正常处理写操作。简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
3.做快照的频率

要想尽可能恢复数据,t值就要尽可能小,虽然bgsave执行时不阻塞主线程,但是频繁地执行全量快照,也会带来两方面开销。一:频繁将全量数据写入磁盘,会给磁盘带来很大压力,二:bgsave子进程需要通过fork操作从主线程创建出来,创建后不阻塞主线程,但是fork操作本身阻塞主线程。
我们可以做增量快照,就是做一次全量快照之后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。这么做的前提是需要记住哪些数据被修改了,会带来额外的开销。

4.新方案

redis4.0中提出了一个混合使用AOF日志和内存快照的方法。内存快照以一定的频率执行,两次快照之间,使用AOF日志记录这期间所以命令操作。这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

5.关于AOF和RDB的选择问题。
  • 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
  • 如果允许分钟级别的数据丢失,可以只使用 RDB;
  • 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。

2.主从复制

1.基础概念

Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。读操作:主库、从库都可以接收;写操作:首先到主库执行,然后,主库将写操作同步给从库。

2.配置

在配置文件中加入,随redis启动生效
在redis-server启动命令后加入
直接使用命令
replicaof 172.16.19.3 6379 slaveof 172.16.19.3 6379(5.0之前)

建立主从连接之后我们可以通过info replication命令查看复制相关状态

slave no one 来断开与主节点复制关系

注意:
1.主节点会通过requirepass参数进行秘密验证,这时所有的客户端需要配置masterauth来进行验证
2.默认情况下slave-read-only=yes 配置为只读
3.网络延迟问题 Redis 为我们提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP NODELAY,
当关闭时,主节点产生的命令数据无论大小都会及时发送给从节点,延迟变小,增加网络带宽消耗。适用于主从网络环境良好的场景,如同机架或同机房部署。
当开启时,主节点会合并较小的tcp数据包而节省带宽。默认发送时间间隔取决于linux内核,一般为40毫秒,节省带宽增加延迟。适用于主从网络环境复杂或带宽紧张的情景。如跨机房部署

主从复制原理:
1.保存主节点信息
2.主从建立socket连接(从节点内部通过每秒运行的定时任务发现新的主节点后,尝试连接,如果无法连接会无限重试直至成功或者执行slave no one)
3.发送ping命令
4.权限验证(设置requirepass,需要验证密码)
5.同步数据集(第一次同步,把持有数据全部发送,耗时最长)
6.命令持续复制
主从复制会把原本从节点的数据请空

3.主从库间如何进行第一次同步

建立链接,协商同步。从库和主库建立起连接,告诉主库即将进行同步,主库确认回复后,主从库间开始同步,具体过程是

  • 从库给主库发送psync命令,参数包括了主库的runid和赋值进度offset,第一次复制为-1.主库收到后,会用fullresync(表示第一次复制采用的是全量复制)命令带上两个参数主库runid和主库目前的复制进度offset,返回给从库。
  • 主库将所有数据同步给从库,从库收到数据后,在本地完成数据加载,这个过程依赖于RDB文件。具体来说,主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库。从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。但是,这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中。为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。
  • 主库把第二阶段执行过程中新收到的写命令,发送给从库,具体操作:主库完成RDB文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作。
4.主-从-从模式

一次全量复制中,主库要完成两个耗时操作,生成和传输RDB文件,如果从库数量很多,导致主库忙于fork子进程生成RDB文件,进行数据全量同步。这时候我们可以采用主从级联模式分担全量复制时的主库压力,就是主-从-从模式。

5.主从库间网络断了怎么办

redis2.8之前,网络断开后就会重新进行一次全量复制,开销很大。
redis2.8之后,断开之后,会采用增量复制的方式继续同步。全量复制是同步所有数据,而增量复制只会把主从库网络断连期间主库收到的命令,同步给从库。

6.增量复制时,主从库之间怎么保持同步?

当主从库断连后,主库会把断连期间收到的写操作命令,写入 replication buffer,同时也会把这些操作命令也写入 repl_backlog_buffer 这个缓冲区。repl_backlog_buffer 是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置。一开始,写读位置在一起,随着主库接收新的写操作,写位置会逐步偏离起始位置,对应偏移量master_repl_offset。主从库的连接恢复之后,从库首先会给主库发送 psync 命令,并把自己当前的 slave_repl_offset 发给主库,主库会判断自己的master_repl_offset 和 slave_repl_offset 之间的差距。在网络断连阶段,主库可能会收到新的写操作命令,所以,一般来说,master_repl_offset 会大于 slave_repl_offset。此时,主库只用把 master_repl_offset 和 slave_repl_offset 之间的命令操作同步给从库就行。
repl_backlog_buffer 是一个环形缓冲区,写满后,就会覆盖,所以需要调整repl_backlog_size这个参数。缓冲空间计算公式是,缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小。考虑到存在一些突发请求压力,我们一般扩大一倍,repl_backlog_size = 缓冲空间大小 * 2。
举个例子,如果主库每秒写入 2000 个操作,每个操作的大小为 2KB,网络每秒能传输 1000 个操作,那么,有 1000 个操作需要缓冲起来,这就至少需要 2MB 的缓冲空间。否则,新写的命令就会覆盖掉旧操作了。为了应对可能的突发压力,我们最终把 repl_backlog_size 设为 4MB。

7.主库挂了,如何不间断服务

主库挂了需要运行一个新主库,在redis主从集群中,哨兵机制是实现主从库切换的关键机制。哨兵主要负责三个任务:监控,选主和通知

  • 哨兵进程在运行时,周期性给所以主从库发送ping命令,监测它们是否在运行,如果没有在规定时间内响应,哨兵就会把它标记为下线状态。
  • 如果是主库没有响应,就开始自动切换主库流程。首先需要执行选主,哨兵要从很多个主库里,按照规则选择一个从库实例,把它作为新的主库。
  • 然后,哨兵会把新主库的连接信息发给其他库,让他们执行replicaof命令,和新主库建立连接,就行数据复制,同时,把新主库的连接信息通知给客户端。

哨兵对主库的下线判断有主观下线和客观下线。

哨兵进程会使用ping命令检测它自己和主从库的网络连接情况,用来判断实例的状态,如果哨兵发现主库或从库响应超时,就先把它标记为主观下线。

在集群网络压力较大,网络阻塞,或者主库本身压力较大的情况下,可能发生误判。为了减少误判,哨兵机制通常采用多实例组成的集群模式进行部署,被称为哨兵集群。多个哨兵一起判断,可以避免单个哨兵因为自身网络,而误判主库下线的情况。在判断主库是否下线是,只有大多数的哨兵实例,都判断主库下线了,主库才会被标记为客观下线,原则就是少数服从多数。N/2+1

8.如何选定新主库

筛选+打分。

先按照一定的筛选条件,把不符合的从库去掉,然后按照一定的规则,给剩下的从库逐个打分,将得分最高的从库选为新主库。

在选主时,除了要检查从库的当前在线状态,还要判断它之前的网络连接状态。你使用配置项 down-after-milliseconds * 10。其中,down-after-milliseconds 是我们认定主从库断连的最大连接超时时间。如果在 down-after-milliseconds 毫秒内,主从节点都没有通过网络联系上,我们就可以认为主从节点断连了。如果发生断连的次数超过了 10 次,就说明这个从库的网络状况不好,不适合作为新主库。

接下来打分,我们可以分别按照三个规则依次进行三轮打分,这三个规则分别是从库优先级、从库复制进度以及从库 ID 号。只要在某一轮中,有从库得分最高,那么它就是主库了,选主过程到此结束。如果没有出现得分最高的从库,那么就继续进行下一轮。

  1. 第一轮,优先级最高的从库得分最高,通过slave-priority 配置项,给不同的从库设置不同优先级。
  2. 第二轮,和旧主库同步程度最接近的从库得分高。主从库同步时有个命令传播的过程。在这个过程中,主库会用 master_repl_offset 记录当前的最新写操作在 repl_backlog_buffer 中的位置,而从库会用 slave_repl_offset 这个值记录当前的复制进度。我们想要找的从库,它的 slave_repl_offset 需要最接近 master_repl_offset。如果在所有从库中,有从库的 slave_repl_offset 最接近 master_repl_offset,那么它的得分就最高,可以作为新主库。
  3. 第三轮:Redis 在选主库时,有一个默认的规定:在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。
9.如果有哨兵实例在运行时发生了故障,主从库还能正常切换吗?

实际上,一旦多个实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作,包括判定主库是不是处于下线状态,选择新主库,以及通知从库和客户端。

哨兵实例之间可以相互发现,要归功于 Redis 提供的 pub/sub 机制,也就是发布 / 订阅机制。哨兵和主库建立连接,可以在主库上发布信息,也可以订阅信息,获得其他哨兵发布的连接信息,哨兵除了彼此之间建立起连接形成集群外,还需要和从库建立连接。哨兵是通过向主库发送INFO命令,来知道从库的ip地址和端口号。哨兵还需要知道客户端信息。

基于 pub/sub 机制的客户端事件通知从本质上说,哨兵就是一个运行在特定模式下的 Redis 实例,只不过它并不服务请求操作,只是完成监控、选主和通知的任务。所以,每个哨兵实例也提供 pub/sub 机制,客户端可以从哨兵订阅消息。哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。

事件相关频道
主库下线事件+sadown(实例进入主观下线状态)
主库下线事件-sadown(实例退出主观下线状态)
主库下线事件+odown(实例进入客观下线状态)
主库下线事件-odown(实例退出客观下线状态)
从库重新配置事件+salve-reconf-sent(哨兵发送slaveof命令重新配置从库)
从库重新配置事件+salve-reconf-inprog(从库配置了新主库,但尚未进行同步)
从库重新配置事件+salve-reconf-done(从库配置了新主库,且和新主库完成同步)
新主库切换+switch-master(主库地址发生变化)

有了这些事件通知,客户端不仅可以在主从切换后得到新主库的连接信息,还可以监控到主从库切换过程中发生的各个重要事件。这样,客户端就可以知道主从切换进行到哪一步了,有助于了解切换进度。

10.由哪个哨兵进行主从切换?

任何一个实例只要自身判断主库“主观下线”后,就会给其他实例发送 is-master-down-by-addr 命令。接着,其他实例会根据自己和主库的连接情况,做出 Y 或 N 的响应,Y 相当于赞成票,N 相当于反对票。

一个哨兵获得了仲裁所需的赞成票数后,就可以标记主库为“客观下线”。这个所需的赞成票数是通过哨兵配置文件中的 quorum 配置项设定的。

例如,现在有 5 个哨兵,quorum 配置的是 3,那么,一个哨兵需要 3 张赞成票,就可以标记主库为“客观下线”了。这 3 张赞成票包括哨兵自己的一张赞成票和另外两个哨兵的赞成票。此时,这个哨兵就可以再给其他哨兵发送命令,表明希望由自己来执行主从切换,并让所有其他哨兵进行投票。这个投票过程称为“Leader 选举”。因为最终执行主从切换的哨兵称为 Leader,投票过程就是确定 Leader。

在投票过程中,任何一个想成为 Leader 的哨兵,要满足两个条件:第一,拿到半数以上的赞成票;第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。以 3 个哨兵为例,假设此时的 quorum 设置为 2,那么,任何一个想成为 Leader 的哨兵只要拿到 2 张赞成票,就可以了。

要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值 down-after-milliseconds。

11.数据增多,该加内存还是加实例?

为了保存大量数据,我们使用了大内存云主机和切片集群两种方法。实际上,这两种方法分别对应着 Redis 应对数据量增多的两种方案:纵向扩展(scale up)和横向扩展(scale out)。

  • 纵向扩展
    升级单个redis实例的资源配置,包括增加内存容量,磁盘容量,更高配置cpu。
    好处:实施简单直接。但是存在两个问题:1.使用RDB对数据进行持久化时,数据量增加,需要内存也会增加,主线程fork子进程时就可能阻塞。2.收到硬件和成本限制,
  • 横行扩展
    增加redis实例个数
    在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择。但是,切片集群涉及到多个实例的分布式管理问题。

1.数据切片后,在多个实例之间如何分布

redis3.0之后,官方提供了Redis Cluster方案,采用哈希槽处理数据和实例之间的映射关系。一个切片集群有16384个哈希槽。每个键值对根据key,被映射到一个哈希槽中。具体的映射过程分为两大步:首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。也可以根据自己集群配置,使用 cluster addslots 命令手动分配哈希槽。

2.客户端怎么确定想要访问的数据在哪个实例上
一般来说,客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。但是,在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。

Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。但是哈希槽不是一直不变的,Redis Cluster提供了一种重定向机制。就是客户端给一个实例发送读写操作时,这个实例上没有相应的数据,客户端要给一个新实例发送操作命令,那客户端又是怎么知道重定向时的新实例的访问地址呢?当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址。


GET hello:key
(error) MOVED 13320 172.16.19.5:6379

GET hello:key
(error) ASK 13320 172.16.19.5:6379
//表明数据还在迁移中,ask命令并不会更新客户端缓存的哈希槽分配信息
12.主从库间的复制为什么不使用AOF?
  1. .RDB文件是二进制文件,无论是要把RDB写入磁盘还是要通过网络传输RDB,IO效率都比记录和传输AOD的高
  2. .在从库端进行恢复时,用RDB的恢复效率要高于AOF
13.主从切换过程中,客户端能否正常进行操作?

主从集群一般采用读写分离模式,当主库故障后,客户端仍然可以把读请求发送给从库,让从库服务,但是,对于写操作,客户端无法执行。

14.想要应用程序不感知服务的中断,还需要哨兵或者服务端再做些什么?
  • 一方面,客户端需要能缓存应用发送的写请求。只要不是同步写操作(Redis 应用场景一般也没有同步写),写请求通常不会在应用程序的关键路径上,所以,客户端缓存写请求后,给应用程序返回一个确认就行。
  • 另一方面,主从切换完成后,客户端要能和新主库重新建立连接,哨兵需要提供订阅频道,让客户端能够订阅到新主库的信息。同时,客户端也需要能主动和哨兵通信,询问新主库的信息。
15.哨兵实例是不是越多越好呢?如果同时调大 down-after-milliseconds 值,对减少误判是不是也有好处?

哨兵实例越多,误判率会越低,但是在判定主库下线和选举 Leader 时,实例需要拿到的赞成票数也越多,等待所有哨兵投完票的时间可能也会相应增加,主从库切换的时间也会变长,客户端容易堆积较多的请求操作,可能会导致客户端请求溢出,从而造成请求丢失。如果业务层对 Redis 的操作有响应时间要求,就可能会因为新主库一直没有选定,新操作无法执行而发生超时报警。调大 down-after-milliseconds 后,可能会导致这样的情况:主库实际已经发生故障了,但是哨兵过了很长时间才判断出来,这就会影响到 Redis 对业务的可用性。

3.常见问题

1.为什么 Redis 不直接用一个表,把键值对和实例的对应关系记录下来?

如果使用表记录键值对和实例的对应关系,一旦键值对和实例的对应关系发生了变化(例如实例有增减或者数据重新分布),就要修改表。如果是单线程操作表,那么所有操作都要串行执行,性能慢;如果是多线程操作表,就涉及到加锁开销。此外,如果数据量非常大,使用表记录键值对和实例的对应关系,需要的额外存储空间也会增加。基于哈希槽计算时,虽然也要记录哈希槽和实例的对应关系,但是哈希槽的个数要比键值对的个数少很多,无论是修改哈希槽和实例的对应关系,还是使用额外空间存储哈希槽和实例的对应关系,都比直接记录键值对和实例的关系的开销小得多。

2.Redis 什么时候做 rehash?

Redis 会使用装载因子(load factor)来判断是否需要做 rehash。装载因子的计算方式是,哈希表中所有 entry 的个数除以哈希表的哈希桶个数。Redis 会根据装载因子的两种情况,来触发 rehash 操作:

  • 装载因子≥1,同时,哈希表被允许进行 rehash;
    再有数据写入,如果此时,Redis 没有在生成 RDB 和重写 AOF,那么,就可以进行 rehash。
  • 装载因子≥5。立马开始做 rehash。
3.采用渐进式 hash 时,如果实例暂时没有收到新请求,是不是就不做 rehash 了?

不是的,redis 会执行定时任务,定时任务中就包含了 rehash 操作。在 rehash 被触发后,即使没有收到新请求,Redis 也会定时执行一次 rehash 操作,而且,每次执行时长不会超过 1ms,以免对其他任务造成影响。

4.线程和进程

从操作系统的角度来看,进程一般是指资源分配单元,例如一个进程拥有自己的堆、栈、虚存空间(页表)、文件描述符等;而线程一般是指 CPU 进行调度和执行的实体。

5.写时复制的底层实现机制

对 Redis 来说,主线程 fork 出 bgsave 子进程后,bgsave 子进程实际是复制了主线程的页表。这些页表中,就保存了在执行 bgsave 命令时,主线程的所有数据块在内存中的物理地址。这样一来,bgsave 子进程生成 RDB 时,就可以根据页表读取这些数据,再写入磁盘中。如果此时,主线程接收到了新写或修改操作,那么,主线程会使用写时复制机制。具体来说,写时复制就是指,主线程在有写操作时,才会把这个新写或修改后的数据写入到一个新的物理地址中,并修改自己的页表映射。

6.为什么有16384个哈希槽

CRC16算法产生的哈希值有16bit,该算法可以产生2^16=65536个值。1.如果设置槽位为65536,发送心跳的消息头为8k,心跳包65536/8/1024=8kb,浪费带宽。2.redis的集群节点数量基本上不可能超过1000个,集群节点越多,心跳包的消息体内带的数据越多,超过1000个,会导致网络拥堵,所以不建议节点超过1000个,那么对于1000以内的集群,16384个槽位够用了,没有必要扩展到65536个3.槽位越小,节点少的情况下,压缩比高,redis主节点配置信息中,所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmao的填充率,slots/N节点数很高的话,bitmap的压缩了就很低。16384/8=2kb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值