《Redis设计与实现》笔记——服务器中的数据库

服务器中的数据库

  • Redis中的所有的数据库都在redisServer结构的db数组里,db数组中每个元素都是一个redisDb结构,每个redisDb代表一个数据库。redisServer中的dbnum属性决定应该创建多少数据库,默认为16。

    《Redis设计与实现》笔记——服务器中的数据库_第1张图片

  • 切换数据库:通过select 命令来执行

    select 2  ------>切换到2号数据库
    

    服务器内部的redisClient结构的*db属性(一个指向redisDb的指针,指向redisServer.db数组中的其中一个元素)记录客户端当前的目标数据库。select的原理就是通过修改redisclient.db指针来打到切换数据库的目的的。
    《Redis设计与实现》笔记——服务器中的数据库_第2张图片

  • 数据库键空间:redisDb中的 * dict 字典保存Redis中所有的键值对。 * dict:键空间。键空间的键是数据库的键,键空间的值是数据库的值。
    《Redis设计与实现》笔记——服务器中的数据库_第3张图片
    对应的图示如下:
    《Redis设计与实现》笔记——服务器中的数据库_第4张图片

  • 添加新键:

    set date "2013.12.1"
    此时,在键空间新增一个新的键值对,键是字符串对象“date”,值是字符串对象“2013.12.1
  • 删除键:

    del book
    就是将键book以及他的值从键空间中删除
    
  • 更新键:实际上是对值进行更新

    set message “blah”
    直接在原位置,将原来的“hello world”更新为“blah”
    
  • 对键取值:

    get message  ----->返回“hello world”
    先查找键message,找到键之后再取到对应的字符串对象值
    
  • 清空数据库:flushdb,删除键空间中所有的键值对

  • 随机返回数据库中某个键:randomkey,在键空间中随机返回一个键

  • 读写键空间时的维护操作:

    • 读取一个键后(读写操作),服务器根据键是否存在来更新服务器的键空间命中次数键空间不命中次数。分别是INFO stats命令的keyspace_hitskeyspace_misses 属性。
    • 读取一个键后,服务器会更新键的LRU (最后一次使用)时间(键的闲置时间),使用OBJECT idletime 命令查看闲置时间。
    • 读取键后,发现键过期,服务器会删除过期键再进行余下操作。
    • 客户端使用watch 监视了键,服务器对这个键进行修改之后,会把这个键标记为,从而让程序注意到键被修改过。
    • 服务器开启了数据库通知功能后,如果对键进行了修改,服务器将按配置发送相应的数据库通知。
  • 设置键的生存时间和过期时间:EXPIRE或者PEXPIRE

    • 在经过指定时间后,服务器会自动删除生存时间为0的键
    • SETNX:设置一个字符串键的同时为键设置过期时间(原理同EXPIRE)。(只限用在字符串键上)
    • expireat、pexpireat的原理同expire
    • TTL、PTTL:返回这个键被服务器自动删除还有多长时间
  • 设置过期时间:

    EXPIRE key ttl :将key的生存时间设置为ttl秒
    PEXPIRE key ttl :将key的生存时间设置为ttl毫秒
    EXPIRE key timestamp :将key的过期时间设置为timestamp所指定的秒数时间戳
    PEXPIRE key timestamp :将key的过期时间设置为timestamp所指定的毫秒数时间戳
    
    实际上,expire、pexpire、expireat都是使用pexpireat来实现的
    
    当前时间加上TTL,得出毫秒格式的键过期时间
    

    《Redis设计与实现》笔记——服务器中的数据库_第5张图片

  • 保存过期时间:过期字典:redisDb结构的expires字典,保存了数据库中所有键的过期时间

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

    • 值是long long类型的整数,表示键的过期时间,毫秒级精度的UNIX时间戳

      typedef struct redisDb{
      	dict *expires
      }redisDb;
      
  • 移除键的过期时间:PERSIST, 就是pexpireat的反操作,在过期字典中查找给定的键,并解除键和值(过期时间)在过期字典中的关联。

  • 计算并返回剩余生存时间:TTL(秒)/PTTL(毫秒),这两个命令都是通过计算键的过期时间和当前时间之间的差来实现的。

  • 过期键的判定:

    1. 检查给定键是否存在于过期字段,如果存在,取得键的过期时间
    2. 检查当前UNIX的时间戳是否大于键的过期时间,是,键已过期;否则,键未过期。
    3. 另一种方法是使用ttl或者pttl命令,如果返回值大于等于0,说明该键未过期
  • 过期键删除策略:Redis实际使用的:惰性删除和定期删除(配合使用)

    • 主动删除:

      • 定时删除:设置键过期时间的同时,创建一个定时器,过期时定时器删除键。
        • 优点:对内存友好,键被删除,内存空间就会被释放
        • 缺点:对CPU时间不友好,影响服务器的响应时间和吞吐量。比如说,当前有大量请求在等待服务器处理,服务器居然去删除过期键。对请求的响应时间会变长。另外,定时器需要用到时间事件,时间事件的处理方式是无序链表,查找一个时间需要O(N),不能高效处理大量的时间事件。
      • 定期删除:每隔一段时间,程序检查数据库,删除过期键
        • 优点:通过限制删除操作执行时长和频率来减少对CPU时间的影响,有效减少了因为过期键带来的内存浪费
        • 缺点:难以缺点删除操作执行的时长和频率。
          • 删除操作执行太频繁,或者执行时间太长,就会退化成定时删除,会浪费过多的CPU时间
          • 执行的太少,或者时间太短,就会退化成惰性删除策略,浪费内存。
        • 实现:activeExpireCycle实现,每当redis的服务器周期性操作serverCron函数执行时,activeExpireCycle就会被调用。它在规定时间内,分多次遍历服务器中的各个数据库,从expires字典中随机 检查一部分键的过期时间,并删除过期键。
          • activeExpireCycle的工作模式:函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键。全局变量current_db会记录当前activeExpireCycle函数检查的进度,并在下一次函数调用时,接着上一次的进度进行处理,比如,上一次在遍历10号数据库的时候返回了,下一次函数调用时,就从11号数据库开始查找并删除过期键。随着函数的不断执行,所有的数据库都会被检查一遍,这时候函数会把current_db重置为0,然后进行新一轮的检查。
    • 被动删除:

      • 惰性删除:每次获得键时再检查键是否过期,过期就删除,否则返回改键。

        • 优点:对CPU时间友好,不会在删除无关的过期键上浪费任何的CPU时间

        • 缺点:对内存不友好。如果数据库中过期键没有被访问到,他们永远也不会被删除,除非用户手动执行flushdb。

        • 实现:由expireIfNeeded函数实现,所有读写命令在执行之前都会调用这个函数对键进行检查。如果过期,函数就将输入键从数据库删除,如果没过期,函数不做什么。因为每个被访问的键都可能因为过期被函数删除,所以每个命令的实现函数都必须能处理键存在以及键不存在的两种情况。比如,get命令:

        《Redis设计与实现》笔记——服务器中的数据库_第6张图片

  • AOF、RDB和复制功能对过期键的处理

    • 生成RDB文件:执行save、bgsave创建rdb文件时,程序会对键进行检查,过期的键不会被保存到rdb文件中。

    • 载入RDB文件:服务器以主服务器模式运行,那么在载入rdb时,会对文件中保存的键进行检查,过期键会被忽略,没过期的会被载入到数据库。如果服务器以从服务器模式运行,rdb文件中所有的键不管是否过期都会被载入到数据库中,主从服务器数据同步的时候,从服务器的数据会被情况,所以过期键被载入从服务器影响不大。

    • AOF文件写入:程序会向AOF文件追加DEL命令,来显式记录该键已被删除。比如说,客户端get message , 但是message已经过期了,服务器首先会把数据库中的message进行删除,然后追加一条DEL message 到AOF文件,最后,向执行get命令的客户端返回空回复。

    • AOF重写:程序会对键进行检查,过期的键不会被保存到aof文件中。

    • 复制:当服务器在复制模式下,从服务器的过期键删除动作由主服务器控制:

      • 主服务器在删除过期键之后,会显式地向所有从服务器发送一个DEL命令,告诉从服务器删除过期键。
      • 从服务器在执行客户端发送的读命令时,即使碰到过期键也不会删除,而是继续像处理未过期的键一样处理过期键。
      • 等到从服务器接收到主服务器发来的DEL命令后,才会删除过期键。

      通过主服务器来控制从服务器统一删除过期键,可以保证主从服务器数据的一致性。

  • 数据库通知:数据库键变化后,会通知订阅过的客户端。

    • 键空间通知:关注“某个键执行了什么命令”的通知
    • 键事件通知: 关注“某个命令被什么键执行了”的通知
    • 服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型:
      • 服务器发送所有类型的键空间通知和键事件通知,将选项的值设置为AKE。
      • 服务器发送所有类型的键空间通知,将选项的值设置为AK。
      • 服务器发送所有类型的键事件通知,将选项的值设置为AE。
      • 服务器只发送和字符串键有关的键空间通知,将选项的值设置为K$。
      • 服务器只发送和列表键有关的键事件通知,将选项的值设置为El。
  • 发送通知:

    • 由notifyKeyspaceEvent实现。

      void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid)
      type: 当前想要发送的通知的类型
      event:事件的名称
      key: 产生事件的键
      dbid:产生事件的数据库号码
      

你可能感兴趣的:(Redis,idea,spring,boot,java)