• 谈谈Redis你还不知道的


     学好Redis,走遍天下都不怕

    • 服务器保存数据库的方法
    • 客户端切换数据库的方法
    • 数据库保存键值对的方法
    • 数据库的增加,删除,更新,查看操作
    • 服务器保存键的过期时间的方法
    • 服务器自动删除过期键的方法

    1.服务器保存数据库的方

    struct redisServer{

     //...

     //一个数组,保存所有的数据库

      redisDb *db;

      //..

    }

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

    2.客户端切换数据库的方法

    每个Redis客户端都有自己的目标数据库

    默认情况下,Redis客户端的目标数据库为0号数据库,但客户端可以通过执行select命令来切换目标数据库

    代码示例:

    在服务器内部,客户端状态redisClient结构的db属性记录了客户端当前的目标数据库

    typeof struct redisClient{

    //..

    //记录客户端当前正在使用的数据库

    redisDb *db;

    //..

    }redisClient;

    redisClient.db指针指向redisServer.db数组的其中一个元素,而被指向的元素就是客户端的目标数据库。(仔细品。。)

    目标数据库为1号数据库时,客户端的状态和服务器状态之间的关系:

    当执行命令select 2,客户端的状态和服务器状态之间的关系更新为:

    通过修改redisClient.db指针,让它指向服务器中的不同数据库,从而实现切换目标数据库的功能——这就是select命令的实现原理

    3.数据库保存键值对的方法

    Redis是一个键值对数据库服务器,服务器中的每个数据都有一个redis.h/redisDb结构表示

    redisDb结构的dict字典保存了数据库中的所有键值对,这个字典就是键空间

    typedef struct redisDb{

    //..

    dict * dict;

    //..

    }redisDb;

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

    键空间中的键就是数据库的键,每个键都是字符串对象

    键空间中的值就是数据库的值,每个值可以是字符串对象,列表对象,哈希表对象,集合对象和有序集合对象的任意一种

    如图:

    4.数据库的增加,删除,更新,查看操作

    添加一个新键值对到数据库,实际上就是将一个新键值对添加到键空间字典里面

    删除数据库的一个键,实际上就是在键空间里面删除键所对应的键值对对象

    对一个数据库键进行更新,实际上就是对键空间里面键所对应的值对象进行更新,值对象类型不同,更新的具体方法也会有不同。

    对一个数据库键进行取值,实际上就是对键空间里面取出键所对应的值对象,值对象类型不同,取值的具体方法也会有不同。

    除了上面列出的添加,删除,更新,取值操作之外,还有:

    用于清空整个是数据库的flushdb命令,就是通过删除键空间中的所有键值对来实现的

    用于随机返回数据库中的某个键的randomkey命令,就是通过在键空间中随机返回一个键来实现的

    用于返回数据库数量的dbsize命令,就是通过返回键空间中包含的键值对数量来实现的

    5.读写键空间时的维护操作

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

    读取一个键之后(读操作和写操作都要对键进行读取),服务器会根据键是否存在来更新服务器的键空间 命中次数(hit)或不命中次数(miss),

    6.服务器保存键的过期时间的方法

    1)保存过期时间

    redisDb结构的expires字典保存了数据库中所有键的过期时间,这个字典也即过期字典

    过期字典的 键 是一个指针,指向键空间中的某个键对象

    过期字典的 值 是一个long类型的整数,保存了键所指向的数据库键的过期时间(一个毫秒精度的时间戳)

    typedef struct redisDb{

    //..

    //过期字典,保存键的过期时间

    dict *expires;

    //..

    }redisDb;

    键空间保存了数据库中的所有键值对,而过期字典中保存了数据库键的过期时间

    2)设置过期时间

    expire命令 以秒为单位 设置键的过期时间(生存时间)

    pexpire命令 以毫秒为单位 设置键的过期时间

    setex命令  设置一个字符串键的同时为键设置过期时间(只能用于字符串键)

    expireat命令     以秒为单位 设置键的过期时间   (过期时间是一个unix时间戳)

     

    pexpireat命令   以毫秒为单位 设置键的过期时间  (过期时间是一个unix时间戳)

    实际上,expire,pexpire, expireat,三个命令都是使用pexpireat命令来实现的, 无论客户端执行的是上述四个命令的哪一个,经过转换之后,最终的执行效果和执行pexpireat命令一样。

    3)移除过期时间

    persist命令 可以移除一个键的过期时间,它就是pexpireat命令的反操作

    persist命令在过期字典中查找给定的键,并解除键和值在过期字典中的关联

     

    4)计算并返回剩余生存时间

    ttl命令     以秒为单位返回键的剩余生存时间

    pttl命令    以毫秒为单位返回键的剩余生存时间

     

    7.服务器自动删除过期键的方法

     

    如果一个键过期了,那么它什么时候会被删除呐?

    这里有三种不同的删除策略:

     

    定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。

    惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

    定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删多少过期键,要检查多少个数据库,则有算法决定。

     

    1)定时删除

    定时删除对内存是友好的,通过使用定时器,定时删除策略可以保证过期键会尽快的被删除,并释放过期键所占用的内存。

     

    他对cpu时间是不友好的,在过期键比较多的情况下,删除过期键这一行为可能会占用相对一部分的cpu时间,在内促不紧张但cpu时间非常紧张的情况下,将cpu时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。

    除此之外,创建一个定时器需要用到Redis服务器中的时间事件,而当前时间事件的实现方式——无序链表,查找一个事件的时间复杂度为O(n),并不高效。

     

    因此,让服务器创建大量的定时器,从而实现定时删除策略,在现阶段并不现实。

    2)惰性删除

    惰性删除对cpu时间是友好的,程序只会在取出键时才会对键进行过期检查,并且删除的键仅限于当前处理的键,这个策略不会在删除其他无关的过期键上花费任何的cpu时间。

     

    它对内存是最不友好的,如果一个键已经过期,而这个键又仍然保留在数据库中,那么只要这个过期键不被删除,它所占用的内存就不会释放。

    3)定期删除

    定时删除和惰性删除这两种方式在单一使用时都有明显的缺陷

    定时删除占用太多cpu时间,影响服务器的响应时间和吞吐量

    惰性删除浪费太多内存,有内存泄露的危险

     

    定期删除策略是前两种策略的一种整合和折中:

    它每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对cpu时间的影响

    通过定期删除过期键,有效减少了因为过期键而带来的内存浪费

     

    定期删除策略的难点是确定删除操作执行的时长和频率:

    如果删除操作执行的太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除策略,以致于将C P U时间过多的消耗在删除过期键上面。

    如果删除操作执行的太少,或者执行的时间太短,定期删除策略又会和惰性删除策略一样,出现浪费内存的情况。

     

    因此,如果采用定期删除策略的话,服务器必须根据情况,合理的设置删除操作的执行时长和执行频率。

    Redis的过期键删除策略

    Redis服务器实际使用的是惰性删除和定期删除两种策略:提供两种删除策略的配合使用,服务器可以很好的使用cpu时间和避免浪费内存空间之间取得平衡。

     

    过期键的惰性删除由db.c/expireIfNeeded函数实现,所有读写数据库的Redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查:

     

    过期键的定期删除由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作redis.c/serverCron函数执行时, activeExpireCycle函数就会被调用,他在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expire字典中随机检查一部分键的过期时间,并删除其中的过期键。

    整个过程用伪代码描述如下:

     

     

    activeExpireCycle函数的工作模式可以总结为:

     

  • 相关阅读:
    Android 基础-2.0 拔打电话号码
    Android 基础-1.0 按钮4种点击事件
    Android Studio 技巧备忘
    Android Studio Mac版快捷键
    face++静态库转为动态库之二
    Podfile语法参考
    iOS 高级去水印,涂鸦去水印
    vector 用法小例子
    UltraCompare 激活
    linux 日志查询
  • 原文地址:https://www.cnblogs.com/yunhemeihe/p/12823731.html
Copyright © 2020-2023  润新知