`

数据库实现

阅读更多
        Redis 服务器将其所有的数据库都保存在 redisServer 结构的 db 数组中,db 数组中的每项都是一个 redisDb 结构,代表一个数据库。而在服务器内部,客户端当前的目标数据库则都保存在 redisClient 结构的 db 属性中。这三个结构的关键定义如下。
struct redisServer{
    /* ... */
    redisDb *db;        // 用于保存服务器中的所有数据库的数组
    int dbnum;          // 服务器的数据库数量
    /* ... */
};

typedef struct redisClient{
    /* ... */
    redisDb *db;       // 记录客户端当前正在使用的数据库
    /* ... */
} redisClient;

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

        服务器初始化时,会根据 redisServer 结构的 dbnum 属性来决定应该创建多少个数据库,该属性值默认为 16,可通过 database 配置选项来修改。
        每个 Redis 客户端都有自己的目标数据库,以作为客户端执行命令的操作对象。redisClient 结构的 db 属性指针指向 redisServer.db 数组的其中一个元素,被指向的元素就是客户端的目标数据库。默认的 Redis 客户端的目标数据库为 0 号数据库,可以通过 SELECT 命令来切换目标数据库(实则就是修改了 redisClient.db 指针)。要注意的是,在处理多数据库程序时,目前 Redis 并没有可以返回客户端目标数据库的命令,因此在数次切换数据库之后,可能会忘记自己当前所处的数据库,所以为了避免误操作,在执行类似 FLUSHDB 这样危险的命令之前,最好显示地执行一个 SELECT 命令,然后才执行别的命令。
        对于 Redis 中的每个数据库,都是使用一个 redisDb 结构来表示的,其中的 dict 字典指针保存了对应数据库中的所有键值对,该字典也被称为键空间(key space)。键空间和用户所见的数据库是直接对应的:
        (1)键空间的键就是数据库的键,每个键都是一个字符串对象。
        (2)键空间的值就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中的任意一种(见Redis 五种对象)。
        因为数据库的键空间是一个字典,所以所有针对数据库的操作,如添加或者删除一个键值对、清空整个数据库的 FLUSHDB 命令、随机返回数据库中某个键的 RANDOMKEY 命令和返回数据库键数量的 DBSIZE 命令等,实际上都是通过对键空间字典进行操作来实现的。
        redisDb 结构的 expires 字典保存了数据库中所有键的过期时间,被称为过期字典。过期字典的键是一个指针,指向键空间中的某个键对象(也就是某个数据库键),过期字典的值是一个 long long 类型的整数,保存了对应键的过期时间——一个毫秒精度的 UNIX 时间戳(PEXPIREAT 命令的执行结果,其他三个用于设置过期时间和生存时间的 EXPIRE、PEXPIRE 和 EXPIREAT 命令,实际上都是使用 PEXPIREAT 命令来实现的。键的过期时间可以通过 PERSIST 命令来移除,而键的剩余生存时间则可以通过 TTL 或者 PTTL 命令来返回)。
        当对数据库进行读写时,服务器不仅会对键空间执行指定的操作,还会执行以下一些额外的维护操作。
        (1)在读取一个键(写操作也要对键进行读取)后,服务器会根据键是否存在来更新服务器的键空间命中(hit)次数或不命中(miss)次数,这两个值可以在 INFO stats 命令的 keyspace_hits 属性和 keyspace_misses 属性中查看。
        (2)在读取一个键后,服务器会更新键的 LRU(最后一次使用)时间,该值可以用于计算键的闲置时间,使用 OBJECT idletime <key> 命令可以查看键 key 的闲置时间。
        (3)如果服务器在读取一个键时发现其已过期,则服务器会先删除该键,然后再执行余下的其他操作。
        (4)如果有客户端使用 WATCH 命令监视了某个键,则服务器在对被监视的键进行修改后,会将其标记为脏(dirty),从而让事务程序注意到这个键已经被修改过。
        (5)服务器每次修改一个键后,都会将脏键计数器的值加 1,这个计数器会触发服务器的持久化以及复制操作。
        (6)如果服务器开启了数据库通知功能,则在对键进行修改后,服务器将按配置发送相应的数据库通知。
        在对过期键进行删除时,有三种不同的删除策略,其中第一种和第三种为主动删除策略,第二种为被动删除策略。
        (1)定时删除:在设置键的过期时间时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行删除操作。这种方式对内存是最友好的,但是对 CPU 时间却是最不友好的。一方面,使用定时器可以保证过期键会尽可能地被删除,并释放其所占用的内存。但另一方面,在过期键较多时,删除过期键这一行为可能会占用相当一部分 CPU 时间,这在内存不紧张但 CPU 时间非常紧张(如有大量的命令请求等待服务器处理)的情况下,无疑会对服务器的响应时间和吞吐量造成影响。
        (2)惰性删除:放任键过期不管,但在每次从键空间中获取键时,都检查取得的键是否过期,如果是的话就删除该键,否则就返回该键。这种方式对 CPU 时间来说是最友好的,但对内存却是最不友好的。它虽然可以保证删除过期键的操作只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的键,但如果数据库中有大量的过期键,而这些过期键又恰好没有被访问到的话,那么则可能永远也不会被删除(除非用户手动执行 FLUSHDB 命令),这种情况甚至可以被看作是一种内存泄漏。比如,对于一些和时间有关的数据,如日志,在某个时间点后,对它们的访问就会大大减少,甚至不再访问。如果这类过期数据大量地积压在数据库中,而它们的键所占用的内存也没有释放,那么造成的后果肯定是非常严重的。
        (3)定期删除:每隔一段时间,程序就对数据库进行一次检查,以删除里面的过期键。至于要删除多少过期键,以及要检查多少数据库,则由算法决定。毫无疑问,这种方式是定时删除和惰性删除的一种整合和折中:它通过限制删除操作执行的时长和频率来减少了定时删除操作对 CPU 时间的影响,而通过定期删除过期键,则有效地减少了惰性删除因为过期键而可能带来的内存浪费。但定期删除策略的难点是确定删除操作执行的时长和频率,如果配置不当,则容易使其退化成定时删除或惰性删除策略。因此采用这种策略时,必须要根据服务器的使用情况来合理的设置删除操作的执行时长和频率。
        在 Redis 中,服务器实际使用的是惰性删除和定期删除两种策略,通过配合使用这两种策略,服务器可以很好地在合理使用 CPU 时间和避免浪费内存之间取得平衡。Redis 在使用定期策略时,它会分多次依次遍历服务器中的各个数据库,从各数据库的 expires 字典中随机检查一部分键的过期时间,并删除其中的过期键。
        过期键也会影响到 Redis 服务器中的 RDB 持久化功能、AOF 持久化功能以及复制功能。
        对于 RDB 文件的生成,在执行 SAVE 或者 BGSAVE 命令创建一个新的 RDB 文件时,程序会检查数据库中的键,已过期的键不会保存到新创建的 RDB 文件中。而对于 RDB 文件的载入,如果启动 Redis 服务器时开启了 RDB 功能,则服务器将按照下列两种模式进行载入:
        (1)如果服务器以主服务器模式运行,那么程序会对载入的 RDB 文件中保存的键进行检查,未过期的键会被载入到数据库中,而过期键则会被忽略。因此过期键对载入 RDB 文件的主服务器不会造成影响。
        (2)如果服务器以从服务器模式运行,那么不论载入的 RDB 文件中保存的键过期与否,都会被载入到数据库中。不过由于主服务器在进行数据同步时会清空从服务器数据库,所以一般过期键也不会影响载入 RDB 文件的从服务器。
        对于 AOF 文件的写入,当服务器以 AOF 持久化模式运行时,如果数据库中的某个键已经过期,但还没有被惰性删除或者定期删除,则 AOF 文件不会因为这个过期键而产生任何影响。但当过期键被删除后,程序将会向 AOF 文件追加一条 DEL 命令,来显示地记录该键已被删除。比如,如果客户端试图使用“GET message”命令访问过期的 message 键,则服务器将执行以下三个动作:
        (1)从数据库中删除 message 键。
        (2)追加一条“DEL message”命令到 AOF 文件。
        (3)向该客户端返回空回复。
        对于 AOF 文件的重写类似于 RDB 文件的生成,程序会检查数据库中的键,已过期的键不会被保存到重写后的 AOF 文件中。
        在复制方面,当服务器运行在复制模式下时,从服务器的过期键删除动作完全由主服务器控制:
        (1)主服务器在删除一个过期键后,会显示地向所有从服务器发送一个 DEL 命令,告知从服务器删除这个过期键。
        (2)从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将其删除,而是像处理未过期的键一样来进行处理。从服务器只有在接到主服务器发来的 DEL 命令后,才会删除过期键。
        通过由主服务器来控制从服务器统一地删除过期键,可以保证主从服务器数据的一致性。
分享到:
评论

相关推荐

    java+数据库实现个人通讯录的各种操作

    以下是对"java+数据库实现个人通讯录的各种操作"这一主题的详细解释。 首先,我们需要理解Java在其中的角色。Java是一种广泛使用的面向对象的编程语言,其跨平台特性使得它非常适合开发这种多平台兼容的应用程序。...

    JavaWeb开发技术教程第六章连接数据库实现图书管理系统源代码.pdf

    JavaWeb开发技术教程第六章连接数据库实现图书管理系统源代码.pdf 本资源是关于JavaWeb开发技术的第六章教程,主要介绍了如何使用JavaWeb连接数据库实现图书管理系统。该资源包括连接数据库、实现图书管理系统的源...

    基于QT+sqlite数据库实现员工信息管理系统源码+项目说明.zip

    基于QT+sqlite数据库实现员工信息管理系统源码+项目说明.zip基于QT+sqlite数据库实现员工信息管理系统源码+项目说明.zip基于QT+sqlite数据库实现员工信息管理系统源码+项目说明.zip基于QT+sqlite数据库实现员工信息...

    《数据库实现与维护》课件—04销售管理数据库中的对象.pdf

    《数据库实现与维护》课件—04销售管理数据库中的对象.pdf《数据库实现与维护》课件—04销售管理数据库中的对象.pdf《数据库实现与维护》课件—04销售管理数据库中的对象.pdf《数据库实现与维护》课件—04销售管理...

    使用zTree框架完成树形框架链接到数据库实现增删改

    在实现“使用zTree框架完成树形框架链接到数据库实现增删改”的过程中,主要涉及以下几个步骤: 1. **数据获取**:首先,需要从数据库获取树形结构的数据。通常,这可以通过执行SQL查询完成,将结果转化为JSON格式...

    基于QMediaPlayerQt+数据库实现的视频播放器源码.zip

    基于QMediaPlayerQt+数据库实现的视频播放器源码.zip基于QMediaPlayerQt+数据库实现的视频播放器源码.zip基于QMediaPlayerQt+数据库实现的视频播放器源码.zip基于QMediaPlayerQt+数据库实现的视频播放器源码.zip基于...

    中科大(高级数据库)数据库实现,期末试题(大题部分)

    中科大(高级数据库)数据库实现(金培权),期末考试试题(大题部分)

    数据库文档源码 数据库实现方法

    本文将深入探讨“数据库文档源码”和“数据库实现方法”,旨在为IT行业的专业人士提供丰富的知识资源。 首先,让我们关注“数据库文档”。数据库文档是描述数据库结构、内容、操作规则和设计原理的详细资料,它包括...

    基于sqlite数据库实现的机票管理系统源码+项目说明.zip

    基于sqlite数据库实现的机票管理系统源码+项目说明.zip基于sqlite数据库实现的机票管理系统源码+项目说明.zip基于sqlite数据库实现的机票管理系统源码+项目说明.zip基于sqlite数据库实现的机票管理系统源码+项目说明...

    用JavaBean连接数据库实现简单的用户登录操作

    本项目是基于java的,在jsp中通过访问数据库里的数据实现实现用户登录操作。里面有部分js代码,希望对新手学web有帮助

    CoBase数据库实现源码,仅用于教学

    《CoBase数据库实现源码解析》 CoBase数据库是一款具有中国特色的开源数据库系统,它的源码为我们提供了一次深入理解数据库内部运作机制的宝贵机会。本文将围绕CoBase数据库的实现,结合其提供的源码,从多个方面...

    基于Tensorflow搭建CNN卷积神经网络+CK数据库实现表情识别python源码+模型.zip

    基于Tensorflow搭建CNN卷积神经网络+CK数据库实现表情识别python源码+模型.zip基于Tensorflow搭建CNN卷积神经网络+CK数据库实现表情识别python源码+模型.zip基于Tensorflow搭建CNN卷积神经网络+CK数据库实现表情识别...

    java考勤管理系统数据库实现.doc

    "java考勤管理系统数据库实现" 本文主要讲述了Java考勤管理系统数据库实现的知识点,涵盖了Java语言、数据库、开发语言等方面的内容。 Java语言 Java语言是本系统的核心语言,用于开发整个考勤管理系统。Java是一...

    餐厅点餐系统数据库实现.doc

    餐厅点餐系统数据库实现 一、数据库设计概述 餐厅点餐系统数据库实现需要满足用户需求,包括订单信息、餐馆菜单信息、管理员信息、发票信息等。数据库设计需要考虑数据的安全性、完整性和一致性。 二、数据库设计...

    数据库实现作业

    数据库实现是IT领域中的核心部分,它涉及到数据的存储、管理、检索以及更新等操作。在武汉大学的数据库实现作业中,学生们会深入学习这一关键主题。以下是对压缩包文件内容的详细解读: 1. **数据库系统实现第15章...

    java 连接数据库实现用户登录功能

    在Java编程中,连接数据库并实现用户登录功能是一项基本任务,尤其对于初学者而言,这是一个很好的实践项目。这里我们将深入探讨如何使用Java连接Oracle数据库,创建登录界面,并处理登录验证。 首先,`LoginFrame....

    基于javaGUI+MySQL数据库实现的学生信息管理系统源码(高分项目).zip

    基于javaGUI+MySQL数据库实现的学生信息管理系统源码(高分项目).zip使用说明 修改resource包下jdbc的配置 创建对应的数据库 在mysql登录使用对应的数据库 进行 source: 命令把sql文件放上去运行 4、之后在代码页面...

    基于Qt6、C++以及MySQL数据库实现的新冠疫苗接种管理系统

    【作品名称】:基于Qt6、C++以及MySQL数据库实现的新冠疫苗接 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:基于Qt6...

    利用MFC ODBC操作Access数据库实现显示、添加、修改、删除等功能

    【MFC ODBC操作Access数据库实现显示、添加、修改、删除功能详解】 MFC(Microsoft Foundation Classes)是微软提供的一套面向对象的C++库,用于简化Windows应用程序开发。ODBC(Open Database Connectivity)是一...

    android利用数据库实现搜索联想功能

    以上就是使用Android的SQLite数据库实现搜索联想功能的基本步骤。需要注意的是,为了提高性能,可以考虑使用`AsyncTask`或`LiveData`等异步机制来避免主线程阻塞,并对数据库操作进行优化,如创建合适的索引、缓存...

Global site tag (gtag.js) - Google Analytics