第三章 数据库

时间:2021-08-24
本文章向大家介绍第三章 数据库,主要包括第三章 数据库使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

  1. 服务器中的数据库

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

                       

  2. 切换数据库  

   

  3. 数据库键空间

  Redis是一个键值对数据库服务器,服务器中的每个数据库由一个redis.h/redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中所有的键值对,称这个字典为键空间。

  3.1 添加新键

  

   

  3.2 删除键

  

   

  3.3 更新键

  

  

  3.4 对键取值

   

  3.5 读写键空间时的维护操作

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

  • 在读取一个键后(读和写操作都要对键进行读取),服务器会根据键是否存在来更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数
  • 在读取一个键后,服务器会更新键的LRU(最后一次使用)时间
  • 如果服务器在读取一个键时,发现键已过期,服务器会先删除过期键,再执行余下操作
  • 如果有客户端使用WATCH命令监视了某个键,服务器在对被监视的键进行修改后,会将这个键标记为脏(在事务一章会介绍)
  • 服务器每修改一个键之后,都会对脏键计数器的值增1,这个计数器会触发服务器的持久化和复制操作(在持久化和复制议长中介绍)
  • 如果服务器开启了数据库通知功能,在对键进行修改之后,服务器将按配置发送相应的数据库通知(发布和订阅一章中介绍)

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

  4.1 设置过期时间

  • EXPIRE<key> <ttl> 键的生存时间为 ttl ( time to live ) 秒
  • PEXPIRE<key> <ttl> 键的生存时间为 ttl ( time to live ) 毫秒
  • EXPIREAT <key> <timestamp> 命令用于将键的过期时间设置为timestamp所指定的秒时间戳
  • PEXPIREAT <key> <timestamp> 命令用于将键的过期时间设置为timestamp所指定的毫秒时间戳

  4.2 移除过期键

  PERSIST命令用于移除过期键。

  

  4.3 计算并返回剩余生存时间

  TTL 命令以秒返回键的生存时间,PTTL以毫秒返回键的生存时间。

  

  5. 过期键删除策略

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

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

  • 惰性删除(浪费内存,有内存泄漏风险)

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

  • 定期删除

  每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。

  6. Redis过期键删除策略

   Redis服务器使用惰性删除和定期删除两种策略。

  6.1 惰性删除策略

  

  6.2 定期删除策略的实现

  过期键的定期删除策略由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作redis.c/serverCron函数时,activeExpireCycle函数就会被调用,整个过程的伪码描述如下:

# 默认每次检查的数据库数量
DEFAULT_DB_NUMBERS = 16

# 默认每个数据库检查的键数量
DEFAULT_KEY_NUMBERS = 20

# 全局变量,记录检查进度
current_db = 0

def activeExpireCycle():
    # 初始化要检查数据库的数量
    # 如果服务器的数据库数量比DEFAULT_DB_NUMBERS 要小
    # 那么以服务器的数据库数量为准
    if server.dbnum < DEFAULT_DB_NUMBERS:
            db_numbers = server.dbnum
    else:
            db_numbers = DEFAULT_DB_NUMBERS
    
    # 遍历各个数据库
    for i in range(db_numbers):
            # 如果current_db的值等于服务器的数据库数量
            # 这表示检查程序已经遍历了服务器的所有数据库一次
            # 将current_db重置为0,开始新的一轮遍历
            if current_db == server.dbnum:
                    current_db = 0

            # 获取当前要处理的数据库
            redisDb = server.db[current_db]
            
            # 将数据库索引增1,指向下一个要处理的数据库
            current_db += 1

            # 检查数据库键
            for j in range(DEFAULT_KEY_NUMBERS):
                    # 如果数据库中没有一个键带有过期时间,那么跳过这个数据库
                    if redisDb.expires.size() == 0 : break
                    
                    # 随机获取一个带有过期时间的键
                    key_with_ttl = redisDb.expires.get_random_key()

                    # 检查键是否过期,如果过期就删除它
                    if is_expired(key_with_ttl):
                        delete_key(key_with_ttl)

                    # 已达到时间上限,停止处理
                    if reach_time_limit() : return

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

  7.1 生成RDB文件

  在执行SAVE或BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的RDB文件中。

  7.2 载入RDB文件

  在启动Redis服务器时,如果服务器开启了RDB功能,那么服务器会对RDB文件进行载入:

  • 如果服务器以主服务器模式运行,在载入RDB文件时,程序会对文件中保存的键进行检查,只有未过期的键会被载入到数据库中
  • 如果服务器以从服务器运行,载入RDB文件时,文件中保存的所有键,无论过期与否都会被载入到数据库中

  7.3 AOF文件写入

  当服务器以AOF持久化模式运行时,如果数据库中的某个键已经过期,且被惰性删除或定期删除之后,程序会向AOF文件追加一条DEL命令,显式记录该键已被删除。

  7.4 AOF重写

  和生成RDB文件时类似,在执行AOF重写的过程中,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中

  7.5 复制

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

  • 主服务器在删除一个过期键后,会显式地向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键
  • 从服务器在执行客户端发送的读命令时,即使碰到过期键,也不会将过期键删除
  • 从服务器只有在接到主服务器地DEL命令之后,才会删除过期键

原文地址:https://www.cnblogs.com/muxianbai/p/15178616.html