• redis的原理和源码-数据过期expire的介绍


    数据过期expire

    命令

    一般情况下,我们设置保存的缓存数据的时候都会设置一个过期时间。为什么呢?

    因为内存是有限的,如果缓存中的所有数据都是一直保存的话,分分钟直接Out of memory。

    Redis 自带了给缓存数据设置过期时间的功能,比如:

    127.0.0.1:6379> exp key  60 # 数据在 60s 后过期
    (integer) 1
    127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
    OK
    127.0.0.1:6379> ttl key # 查看数据还有多久过期
    (integer) 56
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:**Redis中除了字符串类型有自己独有设置过期时间的命令 setex 外,其他方法都需要依靠 expire 命令来设置过期时间 。另外, persist 命令可以移除一个键的过期时间。 **

    过期时间除了有助于缓解内存的消耗,还有什么其他用么?

    很多时候,我们的业务场景就是需要某个数据只在某一时间段内存在,比如我们的短信验证码可能只在1分钟内有效,用户登录的 token 可能只在 1 天内有效。

    如果使用传统的数据库来处理的话,一般都是自己判断过期,这样更麻烦并且性能要差很多。

    保存过期时间

    Redis 通过一个保存在redisDb中的expires字典来保存数据过期的时间。

    • 过期字典的键指向Redis数据库中的某个key对象
    • 过期字典的值是一个long long类型的整数,这个整数保存了key所指向的数据库键的过期时间,是一个毫秒精度的UNIX时间戳。

    过期字典是存储在redisDb这个结构里的:

    typedef struct redisDb {
        ...
        
        dict *dict;     //数据库键空间,保存着数据库中所有键值对
        dict *expires   // 过期字典,保存着键的过期时间
        ...
    } redisDb;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    过期键判定

    通过过期字典,程序可以用以下步骤检查一个给定键是否过期:

    • 检查给定键是否存在于过期字典:如果存在,那么取得键的过期时间。
    • 检查当前UNIX时间截是否大于键的过期时间:如果是的话,那么键已经过期;否则的话,键未过期。

    过期键删除策略

    如果假设你设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?

    常用的过期数据的删除策略就两个(重要!自己造缓存轮子的时候需要格外考虑的东西):

    1. 定时删除:在设置键的过期时间的同时,创建一个定时器( timer ),让定时器在键的过期时间来临时,立即执行对键的删除操作。
    2. 惰性删除 :只会在取出key的时候才对数据进行过期检查。这样对CPU最友好,但是可能会造成太多过期 key 没有被删除。
    3. 定期删除 : 每隔一段时间抽取一批 key 执行删除过期key操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。

    定时删除对内存友好,但对CPU最不友好。惰性删除对CPU更加友好。而定期删除是前两种的整合和折中,但是间隔时间不好控制,如果执行间隔太过频繁,就会变成定时删除,如果执行间隔较长,就会变成惰性删除。

    Redis 采用的是 定期删除+惰性/懒汉式删除

    但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就Out of memory了。

    怎么解决这个问题呢?答案就是: Redis 内存淘汰机制。

    RDB和AOF以及复制

    RDB:

    • 生成RDB:在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中。
    • 读取RDB:在服务器启动时,若服务器是以主服务器模式运行,载入RDB文件时会对保存的键进行检查,过期的键不会被载入数据库;若服务器是以从服务器模式运行,载入RDB文件时不管是否过期都载入,因为当主服务器进行数据同步时从服务器数据库会被清空。

    AOF:

    • 写入:当服务器以AOF持久化模式运行时,如果数据库中的某个键已经过期,但它还没有被惰性删除或者定期删除,那么AOF文件不会因为这个过期键而产生任何影响。当过期键被惰性删除或者定期删除之后,程序会向AOF文件追加( append)一条DEL命令,来显式地记录该键已被删除。
    • 重写:和生成RDB文件时类似,在执行AOF重写的过程中,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。(但我看redis5.0中的rewriteAppendOnlyFileRio源码部分依然是写入的,redis3.0是跳过的)
  • 相关阅读:
    [python] 基于diagrams库绘制系统架构图
    图像处理:边缘检测
    11.QA模型选择,欠拟合和过拟合
    CycleGAN模型之Pytorch实战
    L1-098 再进去几个人 - java
    融合透镜成像反向学习的精英引导混沌萤火虫算法(Matlab)
    如何将webp格式转换成png
    Learn-1
    Kafka生产者消息发送流程
    java毕业设计基于BS架构的疫情包联信息管理系统的设计与实现mybatis+源码+调试部署+系统+数据库+lw
  • 原文地址:https://blog.csdn.net/qq_44766883/article/details/126203553