前面咱们花了不少的时间介绍了 redis 中基本的数据结构,及其内部的实现状况,这些都是很是基础的东西,可能不经意间你就会用到他们,但愿你花点时间了解一下。java
接下来,咱们将走近 redis 数据库,学习各类操做 redis 的命令,并介绍它的一些实现策略以及集群配置等等内容。git
server.h/redisServer 结构中有一个字段,db 字段:程序员
redisDb *db;
复制代码
db 被定义成一个 redisDb 数组,其中 redisDb 的定义以下:github
typedef struct redisDb {
dict *dict;
dict *expires;
dict *blocking_keys;
dict *ready_keys;
dict *watched_keys;
int id;
long long avg_ttl;
} redisDb;
复制代码
咱们常常说 redis 具备十六个数据库,能够切换不通的数据库作数据隔离,这里你就能够将一个 redisDb 实例理解为一个数据库,而 db 指针则能够访问 redis 预约义的全部数据库。正则表达式
其中,dict 是一个字典结构,用于实际存储数据,expires 也是一个字典结构,它存储的是数据库中全部设置过时时间的键值对,保存他们的过时时间,是一个 UNIX 时间戳。redis
blocking_keys 存储了被阻塞的键集合,ready_keys 存储的是能够解除阻塞的键集合,watched_keys 存储的是正在被 watch 命令监控的键的集合,id 记录的是当前数据库的一个编号,avg_ttl 收集了全部键剩余存活时间的一个平均值。这一部分的几个字段的值这里不作详细的解释,没有基本的知识储备,不容易理解的,后面咱们还会遇到的。数据库
server.h/redisServer 结构中还有一个字段,dbnum 字段:数组
int dbnum; /* Total number of configured DBs */
复制代码
与此同时,redis.conf 配置文件中,默认有这么一项配置。bash
因此,咱们启动 redis-server 的时候,会根据配置文件中给定的配置默认建立 16 个数据库。服务器
一、select 命令
select 命令用于咱们切换数据库,例如:
默认链接上 redis-server 的客户端使用 0 号数据库,鉴于 redis 并无提供给客户端查询当前使用数据库编号的命令,因此建议执行 redis 命令以前,尤为是修改、添加命令,先执行下切换数据库的命令。
二、set 命令
set 命令其实无需过多介绍,它向数据库中添加一个键值对,大部分状况下,键会是一个字符串对象,而值可取咱们 redis 的五大对象之一。
由于 redisDb 底层是字典结构,键不容许重复,故而 set 命令一样适用于更新操做。
三、del 命令
del 命令用于删除数据库中一个键值对,标准语法以下:
del [KEY]
复制代码
例如:
四、get 命令
get 命令用于获取一个键值对的值,标准语法是:
get [KEY]
复制代码
具体事例就再也不演示了,get 命令对应于 set 命令,只能获取由 set 命令添加的字符串对象键值对,而例如一些集合对象,或列表对象须要用相似于 sadd、zadd 等命令进行数据库的添加,天然 get 命令也是没法获得这些键值对对象值的。
五、其余命令
第一个咱们介绍 dbsize 命令,它返回当前数据库有多少键值对,基本语法格式以下:
dbsize
复制代码
第二个咱们要介绍的是 flushdb 命令,它用于清空当前数据库,这是一个很是危险的命令,谨慎使用,基本语法格式以下:
flushdb
复制代码
第三个咱们要介绍一个 kyes 命令,它会返回数据库中全部符合匹配规则的键的集合,这个规则起初我觉得是正则表达式,几番操做后发现匹配不上,查阅资料貌似不是正则,而且仅有如下三种规则:
正则表达式中的问号,用于匹配前一个字符出现零次或一次,即要么出现要么不出现,而咱们这里的 keys 模式,问号具备不一样的意义。
不过 keys 命令这种遍历整个数据库的命令是很是耗 CPU 的,可能会致使 redis 性能降低,不作推荐使用。
最后还有一个简单的命令就是 exists,它用于判断给定的 key 是否存在,返回 0 说明不存在,返回 1 说明存在。
有的时候咱们但愿给某些键一个过时时间,即但愿它存活一段时间就失效,咱们 redis 为咱们提供了这样的机制。
一、expire
expire 用于设定某个键的过时时间,单位是秒,基本语法格式以下:
expire [key] [time]
复制代码
能够看到,五秒后 redis 为咱们删除了键 hello。与之对应的有一个命令 pexpire,他会将咱们传入的 time 参数解析为毫秒,例如 「pexpire hello 5」会将键经过五毫秒以后删除。
二、expireat
expireat 用于设定某个键在某个具体 Unix 时间戳过时,单位秒,基本语法以下:
expireat [key] [time]
复制代码
过时键会在咱们指定 Unix 时间戳别删除。固然它也有一个对应毫秒单位的命令,pexpireat ,他会解析命令参数时间戳为毫秒,也就是你须要传入的时间戳再也不是秒单位的,而是毫秒单位的时间戳。
三、ttl 和 pttl
这两个命令用于查看某个过时键还剩余多少时间,基本语法格式以下:
ttl/pttl [key]
复制代码
ttl 命令输出的单位是秒,pttl 输出的单位是毫秒,仅此区别。
四、persist
persist 用于移除某个过时键的过时时间,也就是让这个键成为永久有效键。基本语法格式以下:
persist [key]
复制代码
以上就是 redis 中过时键相关的命令,以前也说过,redisDb 数据结构中有一个 expires 字典,它存储的就是库中全部过时键以及他们生存截止时间。
那么,你可能会好奇了,redis 只记录了某个过时键的截止有效时间,那么何时删除这些过时键呢?
由于 redis 经过 expires 字典记录全部的过时键以及他们的过时时间(一个 Unix时间戳),那么咱们只须要比对当前系统时间戳 Unix 是否大于键的过时时间戳便可判断键是否过时。
咱们直接介绍 redis 使用的两种删除策略,按期删除和惰性删除。
这两个策略,每个都有缺点,按期删除须要每间隔一段时间触发一次删除,因此须要用户对系统的业务量、请求峰谷点有熟悉的的了解,才能配置合适的频率,不然过于高频会平白增长 CPU 压力,过于低频会致使内存中过多无用内存占用,下降系统性能。
而惰性删除缺点很是直接,若是某些键过时了,且程序永远不会访问这些键,那么 redis 就永远不会释放这些键占用的内存,进而致使内存泄漏。
redis 中同时使用了这两种删除策略,一方面,每次读取键的时候会调用方法 db.c/expireIfNeeded 判断当前键是否过时,若是过时则删除并返回 nil。另外一方面,redis 中有一个按期的时间事件函数,server.c/serverCron,每次执行都会收集与更新一些与服务器状态相关的信息,好比更新服务器时间、计算对象空转时长,管理客户端链接资源的释放等等。
其中也会执行一个 expire.c/activeExpireCycle 函数,默认配置了一千微妙内返回,activeExpireCycle 会在时间内选定数据库,随机的处理这些过时键,并给予删除。
因此,其实上 redis 经过这两种策略的结合,按期删除保证不存在某些过时键永远得不到删除以进而引起内存泄漏,惰性删除使得 redis 不用集中大量时间处理这些过时键以引发 CPU 负载过大。
下一节,咱们讲 redis 如何作持久化存储,毕竟数据放在内存,一旦服务器宕机、断点,全部数据都会丢失,因此咱们也须要将数据备份磁盘。下节见~
关注公众不迷路,一个爱分享的程序员。 公众号回复「1024」加做者微信一块儿探讨学习! 每篇文章用到的全部案例代码素材都会上传我我的 github github.com/SingleYam/o… 欢迎来踩!