这个东西没有仔细看,但是大概知道是啥功能的。我想了一下,可以使用这个功能来完成跨平台之间消息的推送。比如我开发了一个app,分别有web版本、ios版本、Android版本、Symbian版本。那么,我可以结合模式+频道,将消息推送到所有安装此应用的平台上。
3. Lua脚本这是redis2.6版本最大的亮点。但是我们好像木有用过- -所以,以后有需求的时候再好好研究一下吧。
4. 慢查询日志慢查询日志是redis系统提供的一个查看系统性能的功能。它的每一条记录的是一条命令的执行时间。所以,你可以在redis.conf中设置当超过slowlog_log_slower_than的时候,将这个命令记录下来;因为慢查询日志是一个FIFO队列(用链表实现的),所以还有一个slowlog_max_than来限制队列长度,如果溢出,就从队头删除最旧的,将最新的添加到队尾。
五 前言这一章是讲redis内部运作机制的,所以算是redis的核心。在这一章中,将会学习到redis是如何设计成为一个非常好用的nosql数据库的。下面我们将要讨论这些话题:
redis是如何表示一个数据库的?它的操作是如何进行的?
redis的持久化是怎样触发的?持久化有什么作用(memcache就没有)
redis如何处理用户的输入?又试如何将运行结果返回给用户呢?
redis启动的时候,都需要做什么初始化工作?传入服务器的命令又是以什么方法执行的?
带着这几个问题,我们就来学习一下redis的内部运作机制,当然,我们重点是学习它为什么要这样设计,这样设计为什么是最优的?有没有可以改进的地方呢?对细节不必太追究,先从整体上理解redis的框架是如何搭配的,然后对哪个模块感兴趣再去看看源码,好像2.6版本的代码量在5W行左右吧。
1. 数据库嗯,好像一直用的都是默认的数据库。废话不说,直接上一个数据库结构:
typedef struct redisDb { //数据库编号 int id; //保存数据库所有键值对数据,也成为键空间(key space) dict *dict; //保存着键的过期信息 dict *expires; //实现列表阻塞原语,如BLPOP dict *blocking_keys; dict *ready_keys; //用于实现WATCH命令 dict *watched_keys }主要来介绍3个属性:
id:数据库编号,但是不是select NUM这个里面的,id这个属性是为redis内部提供的,比如AOF程序需要知道当前在哪个数据库中操作的,如果没有id来标识,就只能通过指针来遍历地址相等,效率比较低
dict:因为redis本身就是一个键值对数据库,所以这个dict存放的就是整个数据库的键值对。键是一个string,值可以是redis五种数据结构的任意一种。因为数据库本身是一个字典,所以对数据库的操作,基本都是对字典的操作
键的过期时间:因为有些数据是临时的,或者不需要长期保存,就可以给它设置一个过期时间(当然,key不会同时存在在key space和expire的字典中,两者会公用一个内存块)
这其中比较好的一个是redis对于过期键的处理,我当时看到这里想,可以弄一个定时器,定期来检查expire字典中的key是否到了过期时间,但是这个定时器的时间间隔不好控制,长了的话已经过期的键还可以访问;短了的话,又注定会影像系统的性能。
定时删除:定时器方法,和我想法一致
懒惰删除:这个类似线段树的lazy操作,很巧妙(总算数据结构没白学啊。。。)
定期删除:上面2个都有短板,这个是结合两者的一个折中策略。它会定时删除过期key,但是会控制时间和频率,同时也会减少懒惰删除带来的内存膨胀
lazy机制:
当你不用这个键的时候,我才懒得删除。当你访问redis的某个key时,我就检查一下这个key是否存在在expire中,如果存在就看是否过期,过期则删除(优化是标记一下,直接返回空,然后定时任务再慢慢删除这个);反之再去redis的dict中取值。但是缺点也有,如果用于不访问,内存就一直占用。加入我给100万个key设置了5s的过期时间,但是我很少访问,那么内存到最后就会爆掉。
所以,redis综合考虑后采用了懒惰删除和定期删除,这两个策略相互配合,可以很好的完成CPU和内存的平衡。
2. RDB因为当前项目用到了这个,必须要好好看看啊。战略上藐视一下,就是redis数据库从内存持久化到文件的意思。redis一共有两种持久化操作:
逐个来说,先搞定RDB。
对于RDB机制来说,在保存RDB文件期间,主进程会被阻塞,直到保存成功为止。但是这也分两种实现:
SAVE:直接调用rdbSave,阻塞redis主进程,直到保存完成,这完成过程中,不接受客户端的请求