redis-数据库

Redis数据库使用redisDb结构表示每个数据库,其中键值对存储在dict字典中。键空间包含字符串、列表、哈希表等对象。过期键可通过EXPIRE命令设置,采用惰性删除和定期删除策略。惰性删除在访问键时检查是否过期,定期删除则在预设时间间隔内检查并删除过期键,平衡内存和CPU使用。
摘要由CSDN通过智能技术生成

redis-数据库

  • 数据库示例。

    Redis服务器将所有数据库都保存在服务器状态redisServer结构的db数组中,db数组的每个项都是一个redisDb结构,每个redisDb结构代表一个数据库。在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库,默认为16个。

digraph {      label = "\n 图 9-1    服务器数据库示例";      rankdir = LR;      node [shape = record];      //      redisServer [label = "redisServer | ... |  db | ... | dbnum \n 16 | ..."];      db [label = "{ <0> db[0] | <1> db[1] | <2> db[2] | ... | <15> db[15] }"];      //      redisServer:db -> db;  }

  • 数据库键空间示例。

    Redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由一个redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间(key space)

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

digraph {      label = "\n图 9-4    数据库键空间例子";      rankdir = LR;      node [shape = record];      //      redisDb [label = "redisDb | ... |  dict | ..."];      dict [label = " dict |  StringObject \n "alphabet" |  StringObject \n "book" |  StringObject \n "message""];      subgraph cluster_alphabet {          a [label = " StringObject \n "a" "];         b [label = " StringObject \n "b" "];         c [label = " StringObject \n "c" "];          a -> b -> c;          label = "ListObject";      }      //alphabet [label = " ListObject | { StringObject \n "a" | "b" | "c" }"];      book [label = " HashObject |  StringObject \n "name" |  StringObject \n "author" |  StringObject \n "publisher""];      //name [label = " StringObject \n "Redis in Action""];     name [label = " StringObject \n "Redis in Action""];      author [label = " StringObject \n "Josiah L. Carlson""];      publisher [label = " StringObject \n "Manning""];      message [label = " StringObject \n "hello world""];      //      redisDb:dict -> dict:dict;      dict:alphabet -> a;     dict:book -> book:head;     dict:message -> message;      book:name -> name;     book:publisher -> publisher;     book:author -> author;  }

  • 带有过期时间的字典示例

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

    通过EXPIREATPEXPIREAT命令,可以设定一个时间戳,该过期时间是一个UNIX时间戳,当键的过期时间来临时,服务器就会自动从数据库中删除这个键,可以通过TIME命令查看UNIX的时间

digraph {      label = "\n图 9-12    带有过期字典的数据库例子";      rankdir = LR;      node [shape = record];      //      redisDb [label = "redisDb | ... |  dict |  expires | ..."];      dict [label = " dict |  StringObject \n "alphabet" |  StringObject \n "book" |  StringObject \n "message""];      subgraph cluster_alphabet {          a [label = " StringObject \n "a" "];         b [label = " StringObject \n "b" "];         c [label = " StringObject \n "c" "];          a -> b -> c;          label = "ListObject";      }      book [label = " HashObject |  StringObject \n "name" |  StringObject \n "author" |  StringObject \n "publisher""];      name [label = " StringObject \n "Redis in Action""];      author [label = " StringObject \n "Josiah L. Carlson""];      publisher [label = " StringObject \n "Manning""];      message [label = " StringObject \n "hello world""];      //      expires [label = " dict |  StringObject \n "alphabet" |  StringObject \n "book""];      redisDb:expires -> expires:head;      alphabet_expire [label = " long long | 1385877600000"];     book_expire [label = " long long | 1388556000000"];      expires:alphabet -> alphabet_expire:head;     expires:book -> book_expire:head;      //      redisDb:dict -> dict:dict;      dict:alphabet -> a;     dict:book -> book:head;     dict:message -> message:head;      book:name -> name:head;     book:publisher -> publisher:head;     book:author -> author:head;  }

  • GET 命令判断是否需要删除过期键的过程。

digraph {      label = "\n图 9-16    GET 命令的执行过程";      node [shape = box];      //      get [label = "GET "];      key_exists_or_not [label = "键不存在?", shape = diamond];      key_expired_or_not [label = "键已过期?", shape = diamond];      return_nil [label = "返回空回复"];      return_value [label = "返回键 key 的值"];      //      get -> key_exists_or_not;      key_exists_or_not -> return_nil [label = "是"];      key_exists_or_not -> key_expired_or_not [label = "否"];      key_expired_or_not -> return_nil [label = "是\n删除过期键"];      key_expired_or_not -> return_value [label = "否"];  }

  • 删除策略
    • 定时删除
      在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。
      • 优点:对内存是最友好的,通过使用定时器,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期键所占用的内存。
      • 缺点:对CPU时间是最不友好的,在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分CPU时间,在内存不紧张但是CPU时间非常紧张的情况下,将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响
    • 惰性删除
      放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
      • 优点:对CPU时间来说是最友好的,程序只会在取出键时才对键进行过期检查,这可以保证删除过期键的操作只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的键,这个策略不会在删除其他无关的过期键上花费任何CPU时间。
      • 缺点:对内存是最不友好的,如果一个键已经过期,而这个键又仍然保留在数据库中,那么只要这个过期键不被删除,它所占用的内存就不会释放
    • 定期删除
      每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
      • 定期删除是一种较为综合的删除策略,能够兼顾CPU与内存
      • 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响
      • 通过定期删除过期键,定期删除策略有效地减少了因为过期键而带来的内存浪费
  • Redis中的删除策略

    Redis服务器实际使用的是惰性删除定期删除两种策略

    • 惰性删除策略的实现

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

      • 如果输入键已经过期,那么expireIfNeeded函数将输入键从数据库中删除
      • 如果输入键未过期,那么expireIfNeeded函数不做动作
    • 定期删除策略的实现

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

      • 函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键
      • 全局变量current_db会记录当前activeExpireCycle函数检查的进度,并在下一次activeExpireCycle函数调用时,接着上一次的进度进行处理。比如说,如果当前activeExpireCycle函数在遍历10号数据库时返回了,那么下次activeExpireCycle函数执行时,将从11号数据库开始查找并删除过期键
        le函数在遍历10号数据库时返回了,那么下次activeExpireCycle函数执行时,将从11号数据库开始查找并删除过期键
      • 随着activeExpireCycle函数的不断执行,服务器中的所有数据库都会被检查一遍,这时函数将current_db变量重置为0,然后再次开始新一轮的检查工作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值