暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis

二十年学编程 2021-08-19
184

redis(Remote Dictionary Server)是一个key-value型的非关系型数据库。

Redis服务器的所有数据库都保存在redisServer.db数组中。数据库主要由dict和expires的两个字典构成,其中dict字典负责保存键值对,expires字典负责保存键的过期时间。

Redis对象类型

Redis数据库使用字典作为底层实现,每一个键值对都是由对象组成的。每一个键是字符串对象类型,而值可以为五种对象类型。每一个对象类型的底层实现有多种方式,适用于多种场合。

Redis键过期策略

Redis中expire字典的键指向数据库中的某个键,而值记录了数据库键的过期时间。通过使用惰性删除和定期删除两种策略来删除过期的键。

当一个过期键被删除后,服务器会追加一条Del命令到现有AOF文件的末尾,显示删除过期键,同时主服务器发送del命令到从服务器。

Redis的持久化

RDB

RDB持久化功能通过保存数据库中的键值对来记录数据库状态,生成的的RDB文件是一个经过压缩的二进制文件,可用于保存和还原Redis服务器中所有数据库里的键值对数据。RDB文件的载入是在服务器启动时自动检测的。

RDB的实现
  1. SAVE命令:阻塞服务器进程,直到RDB文件创建完毕

  2. BGSAVE命令:创建一个子进程,由子进程负责创建RDB文件。

  3. 满足条件自动保存:通过ditry这个计数器属性和lastsave这个时间点来计算是否满足条件。

Redisdb_versiondatabasesEOFcheck_sum
是否为RDB文件版本号包括数据库,类型,键值对标志文件正文内容结束校验和是否出错


AOF(Append Only File)

与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。写入AOF文件的命令是以Redis命令请求格式协议保存的。

AOF文件的更新频率比RDB文件的更新频率更高,所以如果服务器开启了AOF持久化功能,服务器会优先使用AOF文件来还原服务器状态。

AOF持久化功能的实现
  1. 命令追加:服务器执行完一个写命令后,会议协议格式将被执行的写命令追加到aof_buf缓冲区的末尾。

  2. 文件写入和同步:即将aof_buf缓冲区的内容写入和保存到AOF文件里面。根据appendfsync设置,同步的时间不同。

AOF载入与数据还原

AOF文件里包含了重建数据库命令所需的所有写命令,那么服务器只要读入并重新执行这些命令,就可以还原服务器关闭前状态。步骤如下

  1. 创建一个不带网络连接的伪客户端。redis的命令只能在客户端的上下文中执行。因此构造一个伪客户端用来执行AOF文件中的写命令。

  2. aof读取-客户端执行

AOF重写

因为随着服务器运行,AOF文件内容会逐渐增多,为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写的功能。Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,文件保存的数据库状态相同。

AOF文件重写是通过读取服务器当前的数据库状态来实现的,从数据库中读取键现在的值,用一条命令来记录键值对,代替之前的多条命令

后台重写:AOF重写在子进程里进行。为了解决子进程进行AOF重写期间新的命令对数据库状态造成的修改影响,Redis服务器设置了一个AOF重写缓冲区。这个重写缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写入命令后,这个命令会同时发给AOF缓冲区和AOF重写缓冲区。当子进程完成AOF重写工作后,会向父进程发送信号,父进程会将AOF重写缓冲区里的所有内容写入AOF新文件,使得两AOF文件所保存的数据库状态一致,并对AOF改名,原子地覆盖现有AOF文件,完成AOF的重写。

Redis客户端与服务器

Redis服务器可以与多个客户端建立网络连接,每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复。当一个客户端通过网络连接连上服务器时,服务器会为这个客户端创建相应的客户端状态。当出现网络关闭、发送了不合协议格式的命令请求、输出缓冲区超出大小限制,有killclient命令等,这些都会使得客户端关闭。

连接-文件事件处理器

Redis服务器是一个事件驱动程序,服务器处理的事件分为时间事件和文件事件两类。

Redis基于Reactor模式开发了自己的网络事件处理器,这个处理器称为文件事件处理器。

文件事件处理器由四部分构成:套接字、I/O多路复用程序、文件事件分派器、事件处理器。

Redis服务端通过套接字与客户端进行连接,套接字会有连接应答、读取、写入、关闭等操作。文件事件处理器采用I/O多路复用来同时监听多个套接字,将所有套接字放在一个队列里,根据套接字目前执行的操作将套接字逐一传递给分派文件事件分派器来处理。

服务器端

Redis服务器端使用clients这个属性(链表)来保存客户端状态,新添加的客户端会放在链表末尾。保存的客户端属性有:

  1. 套接字描述符

  2. 状态标志:记录了客户端的角色以及目前所在的状态

  3. 输入缓冲区:保存客户端发送的命令请求;

  4. 命令参数及命令参数个数:在服务器的输入缓冲区保存命令请求后,服务器会对命令请求内容分析,得出命令参数argv和命令参数的个数argc。

  5. 命令的实现函数:根据命令参数,在命令表中查找命令所对应的命令实现函数。

  6. 输出缓冲区:保存服务端发送的命令回复

服务器端从启动到能够处理客户端请求需要:初始化服务器,载入配置,初始化服务器数据结构,还原数据库状态,执行事件循环。

命令请求过程

一个命令请求从发送到完成包括:

  1. 客户端发送命令请求给服务器

  2. 服务器读取命令请求,分析命令参数,命令执行器根据参数查找命令的实现函数,然后执行函数并得到回复。

  3. 服务器将命令返回给客户端


主从复制

Redis中,用户可以通过SLAVEOF命令,让一个服务器去复制另一个服务器,被复制的服务器为主服务器,对主服务器进行复制的服务器称为从服务器。进行复制中的主从服务器双方数据数据库将保存相同的数据。实现数据热备份,故障恢复,负载均衡,是高可用的基石。

主从复制

Redis的复制功能分为同步(sync)命令传播(command propagate)两个操作:

  • 同步:将从服务的数据库状态更新至主服务器当前所处的数据库状态。

  • 命令传播:当主服务器的数据库状态被修改时,导致主从服务器数据库状态不一致,让两者数据库重回一致。

同步

客户端向服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器需要进行同步操作。

  1. 从服务器向主服务器发送SYNC命令

  2. 收到SYNC命令的主服务器执行BGSAVE命令,在后台生成RDB文件,并使用一个缓冲区记录从现在开始的写命令。

  3. 主服务器将RDB文件发送给从服务器,从服务器接收并使用它将自身服务器状态更新至主服务器执行BGSAVE命令时的数据库状态。

  4. 主服务器发送缓冲区里所有写命令给从服务器,这是主从服务器达成一致。

命令传播

在同步操作完成后,主从服务器两者数据库会达到一致,但这种一致不是一成不变的,会随着主服务器的运行相关命令后有所改变,这样主从将会不一致。

为了使主从再次回到一致状态,主服务器需要对从服务器进行命令传播操作:主服务器会将自己执行的写命令发送给从服务器执行,当从服务器也执行了写命令后,双方会再次回到一致。

心跳检测

命令传播阶段,从服务器会以每秒一次的频率,向主服务器发送命令:REPLCONF ACK <从服务器当前复制偏移量>。三个作用:

  1. 检测主从服务器的网络连接状态

  2. 辅助实现min-slaves配置选项:防止主服务器在不安全的情况下执行写命令。

  3. 检测命令丢失:主服务器收到replconf ack<>命令后,可以知道从服务器当前的复制偏移量,与自身的复制偏移量进行对比,可以检测出是否有命令丢失的情况。当出现命令丢失,主服务器可以在复制积压缓冲区找出从服务器缺失数据,再次发送。

新版复制功能的改进-psync

为了解决旧版主从服务器断线情况下重新复制发送整个RDB文件情况下的低效问题,redis使用psync命令来代替sync来执行复制的同步操作。sync非常消耗资源,包括主服务器生成RDB文件,发送,从服务器的接收处理。

pasync命令分为完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式。

  • 完整重同步:用于处理初次复制情况,通过让主服务器创建RDB文件,以及发送缓冲区里的写命令完成主从服务器的同步

  • 部分重同步:用于处理主从服务器断线后重新复制情况。当从服务器在断线后重新连接主服务器时,主服务器只需要最近的写命令发送给从服务器,而无需再次发送整个RDB文件。

部分重同步的实现

部分重同步由三部分构成:复制偏移量、复制积压缓冲区、运行ID

复制偏移量

主服务器和从服务器均会维护一个复制偏移量,当主服务器发送n个字节的数据时,主服务器的复制偏移量就加n;从服务器接收到n个字节数据时,从服务器的复制偏移量也加n;通过对比主从服务器的复制偏移量就可以得知主从服务器的数据库状态是否一致。

复制积压缓冲区

复制积压缓冲区是由主服务器维护的一个固定长度的先进先出的队列,默认为1m。

在主服务器进行命令传播时,主服务器不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区里,防止因断线导致的从服务器与主服务器状态不一致。复制积压缓冲区会为队列里每个字节记录相应的复制偏移量,根据复制偏移量来确定发送位置和发送策略。当断线时间太长,复制偏移量里的数据已经不在积压缓冲区就会进行完整重同步。否则就将复制积压缓冲区部分数据发送给从服务器。

服务器的运行ID

主服务器和从服务器都有自己的运行ID,由40个随机的16进制字符组成。

当从服务器对主服务器进行初次复制时,主服务器会将自己ID传递给从服务器,从服务器将其保存。等到断线重连,从服务器将保存的ID发送给主服务器,主服务器根据发送来的ID看是否是之前连接的从服务器,是的话进行部分重同步,不是之前的从服务器就进行完整重同步。

一个复制的完整流程

  1. 设置主服务器的地址和端口:客户端向从服务器发送SLAVEOF 127.0.0.1 6379命令后,从服务器将客户端给定的主服务器IP地址和端口号保存到服务器状态的masterhost属性和masterport属性。从服务器向客户端返回ok。

  2. 建立套接字连接:从服务器根据ip和端口号创建连接主服务器的套接字连接。从服务器会为这个套接字关联一个专门用于处理复制工作的文件事件处理器。主服务器会将从为这个套接字创建对应的客户端状态,把从服务器当成一个客户端来看待。

  3. 发送ping连接:从服务器成为主服务器的客户端后,从服务器第一件事就是向主服务器发送一个ping连接。两个作用:1、检查套接字的读写状态是否正常。2、检查主服务器是否能正常处理从服务器的命令请求。当网络不佳或主服务器暂时没法处理命令请求时,从服务器断开并重新创建连向主服务器的套接字。

  4. 身份验证:根据从服务器是否设置masterauth选项,决定是否要进行身份验证。

  5. 发送端口信息:从服务器向主服务器发送自身的监听端口号。主服务器收到后,会将端口号记录到从服务器所对应的客户端状态属性中。

  6. 同步:从服务器向主服务器发送PSYNC命令,执行同步操作,完成从服务器数据库状态的更新。同步操作后,主从服务器双方都是对方的客户端,只有这样他们才可以互相向对方发送命令请求和返回命令回复。

  7. 命令传播:主服务器将自己执行的写命令发送给从服务器,保存到复制积压缓冲区,同时进行心跳检测。

Sentinel-哨兵模式

Sentinel是redis高可用解决方案:由一个或多个sentinel实例组成的sentinel系统可以监视任意多个主服务器和他们的所有从服务器,当主服务器下线时,自动将下线主服务器的从服务器升级为新的主服务器,然后由新的主服务器继续处理命令请求。

Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过回复来得知两方面信息:一方面是的主服务器相关信息,一方面是主服务器的所有从服务器相关信息。Sentinel会创建连接到从服务器上。

sentinel启动流程

  1. 初始化服务器:Sentinel本质上是一个运行在特殊模式下的Redis服务器,需要初始化服务器状态结构

  2. 使用Sentinel专用代码

  3. 初始化Sentinel状态:服务器会初始化一个保存了所有和sentinel功能的状态,其中状态里的masters字典记录了被监视的主服务器的相关信息

  4. 创建连向主服务器的网络连接。sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关信息。sentinel会创建两个连向主服务器的异步网络连接,一个是命令连接,一个是订阅连接。



文章转载自二十年学编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论