博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[redis读书笔记] 第二部分 单机数据库 数据库实现
阅读量:7123 次
发布时间:2019-06-28

本文共 3047 字,大约阅读时间需要 10 分钟。

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

  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列表进行发送。

      

转载于:https://www.cnblogs.com/jiangz222/p/6484259.html

你可能感兴趣的文章
KVM---GUI远程维护管理
查看>>
RHEL6Kickstart无人值守安装
查看>>
u盘安装centos
查看>>
rsync工具介绍、常用选项、通过ssh同步
查看>>
/usr/include/gnu/stubs.h:10:27: fatal error: gnu/stubs-64.h: No such file or directory
查看>>
python入门到放弃02
查看>>
expect 打开文件
查看>>
Bootstrap调研
查看>>
华佗教你睡觉 一定要看
查看>>
我的友情链接
查看>>
Linux中设置服务自启动的三种方式
查看>>
windows应用程序框架及实例
查看>>
frida Hook 重载方法
查看>>
【CentOS 7.1】 mount 3T
查看>>
iOS 性能优化:Instruments 工具的救命三招
查看>>
数据中心那些常见的问题
查看>>
Linux服务器关闭/开启ICMP协议(ping)
查看>>
我的友情链接
查看>>
Linux基础
查看>>
Linux逻辑卷快照及ssm的使用
查看>>