Redis(8)—— Redis的服务器端

本文深入探讨Redis服务器的数据库结构与管理,包括客户端如何通过SELECT命令切换数据库,数据库键空间的维护,以及键的生存时间和过期时间设置。文章详细介绍了过期键的三种删除策略:定时删除、惰性删除和定期删除,并讨论了RDB、AOF和复制功能对过期键的处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

redis 服务器端默认保存着 16 个数据库,客户端可以通过 SELECT (0~15)来选择不同的服务器。

1. 服务器中的数据库结构

Redis 服务器将所有数据库都保存在服务器状态 redis.h/redisServer 结构的 db 数组中, db 数组每一项都是一个 redis.h/redisDB 结构,每个 redisDB 结构代表一个数据库

struct redisServer{
    //......
    
    //一个数组,保存着服务器中的所有数据库
    redisDB *db;
    
    //......
};

在初始化服务器的时候,程序会根据服务器状态 dbnum 属性来决定创建多少个数据库。

struct redisServer{
    //......
    
    //服务器的数据库的数量
    int dbnum;
    
    //.......
};

2. 客户端切换数据库

客户端通过 SElECT (数据库编号) 0 ~ 15 命令来切换不同的数据库,切换的原理是服务器改变 redisDB *db 的指针。

3. 数据库键空间

redisServer 中的 redisDB 结构中的 dict 字典保存了数据库中的所有键值对,这个字典被称为键空间(key space)。


键空间和用户所见的数据库是直接对应的:

  • 键空间的键也就是数据库的键,每个键都是一个字符串对象
  • 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象或者有序集合对象中的任何一种 Redis 对象。
typedef struct redisDB{
    //..........
    
    //数据库键空间,保存着数据库中的所有键值对
    dict *dict;
    
    //.........
}reidsDB;
读取键空间时的维护操作

当使用 Reids 命令对数据库进行读写时,服务器不仅会对 键空间执行指定的读写操作,还会进行一个额外的操作:

  • 在读取一个键之后,服务器会根据键是否存在来更新服务器的键空间命中(hit)次数和键空间不命中(miss)次数。
  • 在读取一个键之后,服务器会更新这个键的 LRU(最后一次使用)时间,这个值可以用来计算键的闲置时间(当前时间 - LRU)。
  • 如果服务器在读取一个键的时候已经过期,那么服务器会先删除这个过期键,然后才执行剩下的其他操作
  • 如果有客户端使用 WATCH 命令监视了某个键,那么服务器在对被监视的键进行修改之后,会将这个键标记为脏(dirty)
  • 服务器每次修改一个键之后,都会对脏(dirty)键计数器的值增 1,这个计数器会触发服务器的持久化操作以及复制操作。


4. 设置键的生存时间或过期时间

通过 EXPIRE 命令或者 PEXPIRE 命令,客户端可以以秒或者毫秒精度为数据库中的某个键设置生存时间(Time To Live, TTL),在经过执行的秒数或者毫秒数之后,服务器会自动删除生存时间为 0 的键。


过期时间是一个 Unix 时间戳,当键的过期时间来临时,服务器就会自动从数据库中删除这个键。


使用 TTL 或者 PTTL 命令可以查看一个键剩余生存时间,也就是这个键将在多久之后被删除。


4.1 设置过期时间

设置过期时间的命令:

  • EXPIRE 设置 key 的生存时间为 ttl 秒
  • PEXPIRE 设置 key 的生存时间为 ttl 毫秒
  • EXPIREAT 设置 key 的过期时间为 timestamp 指定的秒数时间戳(精度为秒)
  • PEXPIREAT 设置 key 的过期时间为 timestamp 指定的毫秒数时间戳 (精度为毫秒)
EXPIRE、PEXPIRE、EXPIREAT、PEXPIRE 四条指令的执行(都会转换成 PEXPIREAT 去执行)
  • EXPIRE:EXPIRE 会先转换成 PEXPIRE 然后再转换成 PEXPIREAT 去执行
  • PEXPIRE:PEXPIRE 会转换成 PEXPIRE 去执行
  • EXPIREAT:EXPIREAT 会转换成 PEXPIREAT 去执行

4.2 保存过期时间

redisDB 结构中的 expires 字典保存了数据库中所有键的过期时间,称之为 “过期字典”:

  • 过期字典的键为指向键空间某个键对象的指针
  • 过期字典的值为 long long 类型的整数,保存一个毫秒级的 Unix 时间戳 ———— 键的过期时间
typedef struct redisDb{
    //.....
    
    
    //过期字典
    dict *expires;
    
    //.....
}redisDb;

4.3 移除过期时间

PERSIST <key> ,这个命令可以移除 key 上的过期时间


4.4 判定键是否过期

判断键是否过期分为两个步骤:

  1. 判断键是否存在于过期字典中
  2. 如果键存在与过期字典中,则判断这个键的过期时间戳是否小于当前时间,小于则这个键过期。反之,这个键没有过期。


5. 过期键的删除策略

redis 中有三种过期键的删除策略:

  1. 定时删除:在设置键的过期时间的同时,设置一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。
  2. 惰性删除: 放任过期的键不管,当每一个键被访问的之后,就查看这个键是否过期。如果过期,就删除这个键;如果没有过期,就返回这个键。
  3. 定期删除:每隔一段时间就检查数据库的过期字典,删除掉过期的键。这个策略在扫描键的时候,会扫描所有的数据库,但是只会扫描每隔数据库中随机选择(一部分)的键。



6. AOF,RDB 和复制功能对过期键的处理。

RDB 和 AOF 为redis 数据库的两种持久化方式。

6.1 RDB 对过期键的处理

在生成 RDB 文件和载入 RDB 文件的时候对过期键都有相应的处理策略:

  • 生成 RDB 文件: 在生成 RDB 文件的时候(SAVE命令,BGSAVE 命令)的时候,会对数据库的键进行检查,过期的键不会被加入到 RDB 文件中。
  • 载入RDB:
    • 主服务器载入 RDB 文件时,过期的键不会被载入到服务器中
    • 从服务器载入 RDB 文件时,无论键是否过期,都会被载入到数据库中。(在主从服务器同步的时候,从服务器的数据就会被清空,所以这个没有影响)。
6.2 AOF 文件对过期键的处理
  • AOF 文件写入时:在一个键被惰性删除或者定期删除之后,程序会向 AOF 文件追加(appen)一条 DEL 命令,来表示这个键被删除。
  • AOP 文件重写时:在执行 AOF 重写的时候,已经过期的键不会被保存到重写后的 AOF 文件中。
6.3 主从服务器复制对过期键的处理

从服务器之后接受从主服务器传来的 DEL 命令的时候,才会删除过期键:

  • 主服务器再删除一个过期键之后,会显示地向所有的从服务器发送一条 DEL 命令。
  • 从服务器收到客户端传来的读命令时,即使碰到过期键也不会将过期键删除,而是正常返回
  • 从服务器只有接收到主服务器传来的 DEL 命令之后,才会删除过期键。


参考资料

[1].《Redis 设计与实现》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值