前面我们花了很多的时间介绍了 redis 中基本的数据结构,及其内部的实现情况,这些都是非常基础的东西,可能不经意间你就会用到他们,希望你花点时间了解一下。

接下来,我们将走近 redis 数据库,学习各种操作 redis 的命令,并介绍它的一些实现策略以及集群配置等等内容。

一、redis 中的数据库

server.h/redisServer 结构中有一个字段,db 字段:

redisDb *db;

db 被定义成一个 redisDb 数组,其中 redisDb 的定义如下:

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 时间戳。

blocking_keys 存储了被阻塞的键集合,ready_keys 存储的是可以解除阻塞的键集合,watched_keys 存储的是正在被 watch 命令监控的键的集合,id 记录的是当前数据库的一个编号,avg_ttl 收集了所有键剩余存活时间的一个平均值。这一部分的几个字段的值这里不做详细的解释,没有基本的知识储备,不容易理解的,后面我们还会遇到的。

server.h/redisServer 结构中还有一个字段,dbnum 字段:

int dbnum;  /* Total number of configured DBs */

与此同时,redis.conf 配置文件中,默认有这么一项配置。

所以,我们启动 redis-server 的时候,会根据配置文件中给定的配置默认创建 16 个数据库。

1、select 命令

select 命令用于我们切换数据库,例如:

默认连接上 redis-server 的客户端使用 0 号数据库,鉴于 redis 并没有提供给客户端查询当前使用数据库编号的命令,所以建议执行 redis 命令之前,尤其是修改、添加命令,先执行下切换数据库的命令。

2、set 命令

set 命令其实无需过多介绍,它向数据库中添加一个键值对,大部分情况下,键会是一个字符串对象,而值可取我们 redis 的五大对象之一。

因为 redisDb 底层是字典结构,键不允许重复,故而 set 命令同样适用于更新操作。

3、del 命令

del 命令用于删除数据库中一个键值对,标准语法如下:

del [KEY]

例如:

4、get 命令

get 命令用于获取一个键值对的值,标准语法是:

get [KEY]

具体事例就不再演示了,get 命令对应于 set 命令,只能获取由 set 命令添加的字符串对象键值对,而例如一些集合对象,或列表对象需要用类似于 sadd、zadd 等命令进行数据库的添加,自然 get 命令也是无法得到这些键值对对象值的。

5、其他命令

第一个我们介绍 dbsize 命令,它返回当前数据库有多少键值对,基本语法格式如下:

dbsize

第二个我们要介绍的是 flushdb 命令,它用于清空当前数据库,这是一个非常危险的命令,谨慎使用,基本语法格式如下:

flushdb

第三个我们要介绍一个 kyes 命令,它会返回数据库中所有符合匹配规则的键的集合,这个规则起初我以为是正则表达式,几番操作后发现匹配不上,查阅资料貌似不是正则,并且仅有以下三种规则:

  1. ?:用于匹配单个字符
  2. *:用于匹配零个或者多个字符
  3. []:可以用来指定模式的选择区间

正则表达式中的问号,用于匹配前一个字符出现零次或一次,即要么出现要么不出现,而我们这里的 keys 模式,问号具有不同的意义。

不过 keys 命令这种遍历整个数据库的命令是非常耗 CPU 的,可能会导致 redis 性能下降,不做推荐使用。

最后还有一个简单的命令就是 exists,它用于判断给定的 key 是否存在,返回 0 说明不存在,返回 1 说明存在。

二、过期键

有的时候我们希望给某些键一个过期时间,即希望它存活一段时间就失效,我们 redis 为我们提供了这样的机制。

1、expire

expire 用于设定某个键的过期时间,单位是秒,基本语法格式如下:

expire [key] [time]

可以看到,五秒后 redis 为我们删除了键 hello。与之对应的有一个命令 pexpire,他会将我们传入的 time 参数解析为毫秒,例如 「pexpire hello 5」会将键通过五毫秒之后删除。

2、expireat

expireat 用于设定某个键在某个具体 Unix 时间戳过期,单位秒,基本语法如下:

expireat [key] [time]

过期键会在我们指定 Unix 时间戳别删除。当然它也有一个对应毫秒单位的命令,pexpireat ,他会解析命令参数时间戳为毫秒,也就是你需要传入的时间戳不再是秒单位的,而是毫秒单位的时间戳。

3、ttl 和 pttl

这两个命令用于查看某个过期键还剩余多少时间,基本语法格式如下:

ttl/pttl [key]

ttl 命令输出的单位是秒,pttl 输出的单位是毫秒,仅此区别。

4、persist

persist 用于移除某个过期键的过期时间,也就是让这个键成为永久有效键。基本语法格式如下:

persist [key]

以上就是 redis 中过期键相关的命令,之前也说过,redisDb 数据结构中有一个 expires 字典,它存储的就是库中所有过期键以及他们生存截止时间。

那么,你可能会好奇了,redis 只记录了某个过期键的截止有效时间,那么什么时候删除这些过期键呢?

三、过期键删除策略

因为 redis 通过 expires 字典记录所有的过期键以及他们的过期时间(一个 Unix时间戳),那么我们只需要比对当前系统时间戳 Unix 是否大于键的过期时间戳即可判断键是否过期。

我们直接介绍 redis 使用的两种删除策略,定期删除和惰性删除。

  1. 定期删除:redis 每间隔一段时间进行一次小规模,有限时长的删除过期键操作。
  2. 惰性删除:redis 每次读取某个键的时候,会先判断这个键是否过期,如果过期,执行删除操作。

这两个策略,每一个都有缺点,定期删除需要每间隔一段时间触发一次删除,所以需要用户对系统的业务量、请求峰谷点有熟悉的的了解,才能配置合适的频率,否则过于高频会平白增加 CPU 压力,过于低频会导致内存中过多无用内存占用,降低系统性能。

而惰性删除缺点非常直接,如果某些键过期了,且程序永远不会访问这些键,那么 redis 就永远不会释放这些键占用的内存,进而导致内存泄漏。

redis 中同时使用了这两种删除策略,一方面,每次读取键的时候会调用方法 db.c/expireIfNeeded 判断当前键是否过期,如果过期则删除并返回 nil。另一方面,redis 中有一个定期的时间事件函数,server.c/serverCron,每次执行都会收集与更新一些与服务器状态相关的信息,比如更新服务器时间、计算对象空转时长,管理客户端连接资源的释放等等。

其中也会执行一个 expire.c/activeExpireCycle 函数,默认配置了一千微妙内返回,activeExpireCycle 会在时间内选定数据库,随机的处理这些过期键,并给予删除。

所以,其实上 redis 通过这两种策略的结合,定期删除保证不存在某些过期键永远得不到删除以进而引发内存泄漏,惰性删除使得 redis 不用集中大量时间处理这些过期键以引起 CPU 负载过大。

下一节,我们讲 redis 如何做持久化存储,毕竟数据放在内存,一旦服务器宕机、断点,所有数据都会丢失,所以我们也需要将数据备份磁盘。下节见~


关注公众不迷路,一个爱分享的程序员。

公众号回复「1024」加作者微信一起探讨学习!

每篇文章用到的所有案例代码素材都会上传我个人 github

https://github.com/SingleYam/overview_java

欢迎来踩!

Redis 中的数据库的更多相关文章

  1. Redis | 第4章 Redis中的数据库《Redis设计与实现》

    目录 前言 1. Redis中的数据库 2. 数据库的键空间 3. 键的生成时间与过期时间 4. Redis中的过期键删除策略 5. AOF.RDB和复制功能对过期键的处理 5.1 生成 RDB 文件 ...

  2. Redis中单机数据库的实现

    1. 内存操作层 zmalloc 系接口 redis为了优化内存操作, 封装了一层内存操作接口. 默认情况下, 其底层实现就是最简朴的libc中的malloc系列接口. 如果有定制化需求, 可以通过配 ...

  3. 深入理解Redis中的主键失效及其实现机制

    参考:http://blog.sina.com.cn/s/articlelist_1221155353_0_1.html 作为一种定期清理无效数据的重要机制,主键失效存在于大多数缓存系统中,Reids ...

  4. PHP中的数据库三、redis

    h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...

  5. Redis中的批量删除数据库中的Key

    本文参考:http://blog.csdn.net/spring21st/article/details/15771861 http://stackoverflow.com/questions/575 ...

  6. 22、redis中数据库默认是多少个db 及作用?

    redis下,数据库是由一个整数索引标识,而不是由一个数据库名称.默认情况下,一个客户端连接到数据库0.redis配置文件中下面的参数来控制数据库总数: /etc/redis/redis.conf 文 ...

  7. 如何将redis中的数据导入到本地MongoDB和MySQL数据库

    将redis中的数据导入到本地MongoDB数据库 创建一个process_items_mongodb.py文件(文件名自定义): #!/usr/bin/env python # -*- coding ...

  8. 多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中【我】

    多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中 package com.xxx.xx.reve.service; import java.util.ArrayL ...

  9. Redis使用场景一,查询出的数据保存到Redis中,下次查询的时候直接从Redis中拿到数据。不用和数据库进行交互。

    maven使用: <!--redis jar包--> <dependency> <groupId>redis.clients</groupId> < ...

随机推荐

  1. 使用Typescript重构axios(二十九)——添加baseURL

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  2. JQuery弹出菜单时禁止页面(body)滚动

    最近在做手机端的弹出菜单,但是菜单弹出来后滑动手机屏幕的话页面滚动总是会将菜单滑上去,体验非常不好,所以查了一下弹出菜单时禁止页面滚动的方法,整理如下: 方法一:弹出菜单时给body和html添加一个 ...

  3. 高性能Web动画和渲染原理系列(4)“Compositor-Pipeline演讲PPT”学习摘要

    目录 摘要 1.合成流水线 2. 预定义UI层 3. paint是什么意思 4. 分层的优势和劣势 5. 视图属性及其处理方式 6. Quads 7. Compositor Frame 8. 关于光栅 ...

  4. 开启docker中的mongodb认证授权

    前言: 开启MongoDB服务后,默认是没有权限验证的.直接通过IP加端口就可以远程访问数据库,并对数据库进行任意操作.下面介绍一下如何开启docker中MongoDB的权限认证. 安装完MongoD ...

  5. Magicodes.Pay,打造开箱即用的统一支付库,已提供ABP模块封装

    Magicodes.Pay,打造开箱即用的统一支付库,已提供ABP模块封装 简介 Magicodes.Pay,是心莱科技团队提供的统一支付库,相关库均使用.NET标准库编写,支持.NET Framew ...

  6. 为什么 HTTPS 比 HTTP 安全

    HTTP(超文本传输协议)是目前互联网应用最广泛的协议,伴随着人们网络安全意识的加强,HTTPS 被越来越多地采纳.不论是访问一些购物网站,或是登录一些博客.论坛等,我们都被 HTTPS 保护着,甚至 ...

  7. PHP Openssl 生成公钥私钥

    <?php //配置信息 $dn = array( "countryName" => "GB", "stateOrProvinceName ...

  8. nyoj 20-吝啬的国度 (DFS)

    20-吝啬的国度 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:12 submit:43 题目描述: 在一个吝啬的国度里有N个城市,这N个城市间只有 ...

  9. 攻克数通,斩获云计算!誉天Double HCIE学员考证秘笈揭晓

    不知不觉,已经过了四个月的时间了,我是六月多报名云计算的,本来是奔着邹Sir去的,但是当时邹sir已经上到HCIE的课程了,只能蹭学弟之前的录屏看.等到七月八号,又正式跟了曾曦老师上了一次完整的课程. ...

  10. golang学习--go中'继承'和多态

    golang中没有继承的概念,这个struct属性上的继承,但是可以用匿名字段来模拟这个过程,方法上面的继承要使用接口.多态可以通过接口实现.可以看一下代码. package main import ...