zoukankan      html  css  js  c++  java
  • [redis读书笔记] 第二部分 单机数据库 数据库实现

    一 数据库基本实现/命令下发的实现

      redis.c里,大家能看到redisCommandTable[] 的实现,列出了支持的所有命令。大部分的入参为redisClient *c,当一条REDIS命令下发,调用流程如下

    在createClient里会组装下传的client,其中就会调用selectDb()来选择数据库(redis所有的数据库都存在redisServer.db里),而数据库中存储了一个字典结构dict *dict,这个dict里的键就是执行REDIS命令的键,值即redis对象robj。

     redisDb里的结构如下,下图已经是个抽象的图,比如HashObject,理论上应该有个redisObjct的结构,然后ptr指到一个dict的结构,然后才到一个个的entry等:

     那么所有的对DB的读、新增、更新,都是现在redisDb.dict里找/新增 键值(对象的键值)(比如上图的book),然后更新dict里对应键的那个值(robj,比如HashObject)里的内容(比如name,author或者publisher):

    二 键的生存/过期时间

    如下,redisDb中的expires字典保存了数据库中键的过期时间,我们称之为过期字典。

    typedef struct redisDb {
    .......
        // 键的过期时间,字典的键为键,字典的值为过期事件 UNIX 时间戳
        // [JZ]:expires里键即上面的dict的键,即数据库的键,值为一个object
        dict *expires;              /* Timeout of keys with a timeout set */
    }

    过期时间可以增加/修改/移除,可用来计算剩余时间。

    三 过期键的删除策略:

        1.定时删除,即设置过期时间时,设置定时器,到时删除。 优点,节省内存,保证了尽快删除,但是耗CPU,而且实现定时器需要用到redis服务器里的时间事件,复杂度为o(N),不够高效

        2.惰性删除,每次操作键时,判断是否过期,进行相应操作。优点是节省CPU,但是过期键可能长时间存在(如果键不被操作,就会一直存在,那么相当于内存泄露),因而消耗内存

        3.定期删除,每隔一段时间进行键的扫描,过期删除。优点是改进了上面两种方法的缺点,一方面不会对CPU时间影响大,另一方面不会有内存的泄露和浪费。缺点是: 如果删除操作太频繁,或者执行时间太长,定期删除策略就会退化成定时删除,以至于CPU时间过多的耗费在删除过期键的操作上。 如果删除操作执行太少,或者执行时间太短,那么又会有内存浪费的情况(怎么优点缺点像是换个角度说同一件事情.......)

    REDIS最终是是用惰性删除(expireIfNeeded())和定期删除(activeExpireCycle())结合的方式,实现了过期键的清理。

    四 RDB文件

     RDB文件即第一小节讲的DB的来源,redis.c里的main函数里,loadDataFromDisk()->rdbLoad()实现了DB文件的load功能,文件的名字来自于$REDIS_DEFAULT_RDB_FILENAME(AOF:$REDIS_DEFAULT_AOF_FILENAME)

        载入RDB文件时

        1.如果服务器为master,那么会检查文件中的键的过期,已经过期的键就不会载入内存

        2.额如果是slave,不检查键是否过期,全都载入。

        复制: 当服务器运行在复制模式:

        1.主服务器删除一个过期键,会向所有从服务器发送DEL命令

        2.从服务器执行读命令时,即使碰到过期键也不删除,而是忽略过期,照常处理

        3.只有从服务器收到主服务器的DEL时才删除过期键

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

    当服务器以AOF持久化模式运行时,如果有某个键过期,且没有被惰性删除或者定期删除,那么AOF文件不会因为这个过期键而产生任何影响。

    当过期键被删除,程序会想AOF文件追加一条DEL命令记录。

    五 数据库通知

    通过客户端的订阅,客户端可以得到键的被操作(键空间通知key-space notification)或者命令的执行(键事件通知key-event notification)的通知。

    当服务器启动时,配置的 server.notify_keyspace_events决定了支持哪些通知,列表如下,如果配置为AKE,就是支持键空间通知和键事件通知

    #define REDIS_NOTIFY_KEYSPACE (1<<0)    /* K */
    #define REDIS_NOTIFY_KEYEVENT (1<<1)    /* E */
    #define REDIS_NOTIFY_GENERIC (1<<2)     /* g */
    #define REDIS_NOTIFY_STRING (1<<3)      /* $ */
    #define REDIS_NOTIFY_LIST (1<<4)        /* l */
    #define REDIS_NOTIFY_SET (1<<5)         /* s */
    #define REDIS_NOTIFY_HASH (1<<6)        /* h */
    #define REDIS_NOTIFY_ZSET (1<<7)        /* z */
    #define REDIS_NOTIFY_EXPIRED (1<<8)     /* x */
    #define REDIS_NOTIFY_EVICTED (1<<9)     /* e */
    #define REDIS_NOTIFY_ALL (REDIS_NOTIFY_GENERIC | REDIS_NOTIFY_STRING | REDIS_NOTIFY_LIST | REDIS_NOTIFY_SET | REDIS_NOTIFY_HASH | REDIS_NOTIFY_ZSET | REDIS_NOTIFY_EXPIRED | REDIS_NOTIFY_EVICTED)      /* A */

        1.键的操作通知的实现,在 void notifyKeyspaceEvent(int type, char *event, robj *key, int dbid);event是时间名称,keys是产生事件的键,以及产生时间的数据库号

        - 函数会先判断传入的第一个参数type是否包含在server.notify_keyspace_events,如果没有包含,就直接退出,不用通知。

        - 然后server.notify_keyspace_events定义了什么,就通知什么类型,比如REDIS_NOTIFY_KEYEVENT,先组建一个通知 __keyevent@dbid__:KEY(最终组成一个ROBJ结构),传给pubsubPublishMessage()发送

              - pubsubPublishMessage()里,以上面的通知作为key,在字典server.pubsub_channels里查找到一个列表,这个列表存储了谁需要这种类型的通知,然后将通知加入REPLY列表进行发送。

          

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/jiangz222/p/6484259.html
Copyright © 2011-2022 走看看