1、什么是Redis?
Redis是一个高可用的key-value内存数据库。value可以支持多种类型。包括字符串(string)、链表(list)、集合(set)、有序集合(zset sorted set)和哈希(hash)。类似于java中的HashMap也是key-value,value可以存放多种数据结构。
Redis是内存数据库,并且是key-value类型,没有复杂的关系。所以读取与存入比mysql这种传统的关系型数据库快。
相比于memcached内存数据库,它可以通过RDB或AOF的方式将内存数据存入磁盘空间,达到数据的持久化。并且Redis也可以通过主从复制,哨兵,集群等方式实现高可用。
2、Redis数据库
2.1 Redis数据库
Redis默认有16个数据库。
redisServer结构中保存着一个redisDb数组,int dbnum 保存着数据库数量。dbnum默认是16。
struct redisServer{
// 一个数组,保存着服务器中的所有数据库
redisDb *db ;
//服务器的数据库数量
int dbnum ;
}
每个数据库对应一个redisDb结构,redisDb结构中的dict字典(键空间)保存了改数据库的所有的键值对 。
struct redisDb{
// 数据库键空间,保存着数据库中的所有键值对
dict *dict ;
}
切换数据库select 1
当客户端切换到1号数据库时,数据结构示意图:
image.png
切换数据库select 2
当客户端切换到2号数据库时,数据结构示意图:
image.png
2.2 数据库建空间示意图
- alphabet 是一个列表键,键的名字是字符串’alphabet’,键的值是一个包含三个元素的列表对象。
- book是一个哈希表键,键的名字是字符串’book’,键的值是一个包含三个元素的哈希表对象。
message是一个字符串键,键的名字是字符串’message’,键的值是一个字符串对象’hello world’
image.png
2.3 数据库操作
执行命令set date "2013.12.1"
添加一个新键值对到数据库,就是将键值对添加到对应数据库(redisDb)的字典(dict)中
date
删除book键del book
del
更新message键set message "blah blah"
set
取值alphabet lrange alphabet 0 -1
lrange
清空数据库flushdb
针对数据库本身的redis命令,基本上都是针对redisDb的字典(dict)进行操作。
2.4 键生存时间及过期策略
设置键过期时间,可以以秒或者毫秒精度
命令 | 描述 |
---|---|
expire <key> <ttl> | 设置键key的生存时间为ttl 秒 |
pexpire <key> <ttl> | 设置键key的生存时间为ttl 毫秒 |
expireat <key> <timestamp> | 设置键key的过期时间为timestamp所指定的秒数时间戳 |
pexpireat <key> <timestamp> | 设置键key的过期时间为timestamp所指定的毫秒数时间戳 |
expire test 5
:设置key test过期时间为5秒以后
pexpire test 6000
:设置key test过期时间为6000毫秒以后
expireat test 1377333100
:设置key test过期时间为1377333100
pexpireat test 1377333100000
:设置key test过期时间为1377333100000
实际上expire,pexpire ,expireat 三个命令都是使用pexpireat 命令实现的,redis会将其他类型的过期时间最终都转化为毫秒时间戳保存。
过期时间的保存
redisDb结构的expires字典保存了数据库中的所有键的过期时间,称为过期字典。
过期字典的key为指针,指向键空间的某个键对象。
过期字典的value为long long 整数,保存着过期时间戳-毫秒精度的unix时间戳。
struct redisDb{
//过期字典,保存着键的过期时间
dict *expires ;
}
expires
为了展示方面,图示中的键空间与过期字典会出现两次alphabet及book对象,实际中,键空间的key与过期字典的key指向的是同一个键对象,不会出现重复对象。
过期键的删除策略
删除策略 | 描述 | 优点 | 缺点 |
---|---|---|---|
定时删除 | 设置键的过期时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作 | 及时删除过期键,释放内存 | 过期键数量较大时,会创建大量定时器,占用相当一部分cpu时间,不采用 |
惰性删除 | 放任过期键不管,当获取键时,判断是否过期,过期的话,就删除掉,未过期,返回该键 | 不用创建定时器,不占用cpu时间 | 过期键会占用大量内存,导致数据积压 |
定期删除 | 每隔一段时间,程序对数据库进行一次检查,删除过期键,至于删除多少过期键,检查多少个数据库,有算法决定 | 是前两种策略的折中方案,既能比较及时释放内存,又能不占用大量cpu时间 | 难点在于确定操作执行的时长和频率,既不能让删除操作执行太频繁而占用cpu时间,又不能执行太少,浪费内存 |
Redis服务器使用了惰性删除及定期删除两种策略。
惰性删除:所有读写Redis命令在执行之前都会调用expireIfNeeded函数对输入键进行检查。expireIfNeeded就像一个过滤器,将过期键删除。
expireIfNeeded
定期删除:redis的周期性函数serverCron会在规定时间内多次遍历各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。
RDB对过期键的处理
生成RDB文件
save
及bgsave
命令只会对未过期的键进行保存操作,保存至rdb文件。
载入RDB文件
如果服务器以主服务器模式运行,那么载入RDB文件时,不会将过期键导入。
如果服务器以从服务器模式运行,那么载入RDB文件时,会将过期键导入,等主服务器同步数据时,再删除掉过期数据。
AOF对过期键的处理
AOF文件写入
当服务器以AOF持久化模式运行时,对于未被删除的过期数据,AOF不会因为过期键产生任何影响。
对于已被删除的数据,程序会像AOF追加(append)一条DEL命令,来显示地记录该键已被删除。
AOF重写
在执行AOF重写的过程中,程序会对数据库中的键进行检查,已过期的键不会被保存至重写后的AOF文件中。
复制对过期键的处理
当服务器运行在复制模式下,从服务器的过期删除动作由主服务器控制。
主服务器在删除一个过期键时,会向从服务器发送一个DEl命令,告知从服务器删除过期键
从服务器执行客户端发送的命令时,即使碰见过期键也不会将过期键删除,而是会继续像处理未过期键一样进行处理。
从服务只有接收到主服务器的DEl命令,才会删除过期键。