1. 预备
1.1 全局命令
(1)查看所有键: keys*
线上禁止使用,复杂度O(n)。
(2)键总数: dbsize
不会变量所有键,而是查询键的总数变量, 时间复杂度 O(1)
(3)检查键是否存在 exists key
存在返回1,不存在返回0
(4)删除键 del key [key…]
返回删除键个数,如果删除不存在的key,返回为0。删除多个键有空格分割 del key1 key2 …
(5)键过期 expire key seconds
ttl 指令返回兼得剩余时间,>=0 表示剩余过期时间。-1键没有设置过期时间,-2 键不存在。
(6)键的数据结构 type key
1.2 数据结构和内部编码
(1)string — raw,int,enbstr
(2)hash — hashtable,ziplist
(3)list — linkedlist,ziplist
(4) set — hashtable,intset
(5)zset — skiplist, ziplist
1.3 单线程架构
(1)Redis 采用单线程架构和I/O多路复用。
(2)客户端每次调用都经历了发送命令,执行命令,返回结果,所有命令都进入一个队列中。
(3)为什么单线程那么快?
(a)纯内存访问。(b)非阻塞I/O, 使用 epoll 做I/O 多路复用技术。(c)单线程避免线程切换和竞态产生的消耗。
(4)问题:一个命令执行时间过程过长,会造成阻塞。
2.字符串
2.1 常用指令
VALUE 大小< 512M
(1)设置值
set key value
a. ex seconds
b. px milliseconds
c. nx 键必须不存在,才能设置成功
d. xx 键必须存在才能设置成功
setex key value
setnx key value (多个客户端同时执行setnx key value),根据setnx的特性只有一个客户端设置成功,setnx 可以作为分布式锁的一种实现方案。
(2)获取值
get key
(3)批量设置值
mset key value value key value
(4)批量获取
mget key1 key2 key3
批操作可以有效提高开发效率(节省网络时间)
没有mget : n次get时间 = n 次网络时间 + n 次命令时间
有mget: n次get= 1次网络时间 + n次命令时间
(5)计数
incr key
incrby
decrby
incrbyfloat key increment (自增浮点数);
a. 值不是整数,返回错误
b. 值是整数,返回自增后的结果
c. 键不存在,按照0自增,返回结果为1
(6)追加值
append key value
(7)字符串长度
strlen key
(8)设置并返回原值
getset key value
2.2 内部编码
(1)int: 8个字节的长度
(2)embstr: <=39字节
(3)raw: > 39字节
2.3 典型使用场景
2.3.1 缓存功能
Redis + Mysql 组成的缓存存储架构
2.3.2 计数
比如,视屏播放。没播放一次,统计数字+1。真实情况中考虑防作弊,不同维度统计,数据持久到数据库等问题。
2.3.3 共享Session
使用Redis将用户的Session进行集中管理。要保证Redis高可用,每次用户查询或者更新登录信息都直接从Redis中集中获取。
2.4 限速
使用Redis做限速功能,比如一个IP地址不能在1秒钟内访问超过n次。使用
isExists = redis.set(key, 1, "EX 60", "NX"),
if (isExist != null || redis.incr(key) <=5) {
// 通过
}else{
// 限速
}
3. 哈希
键对应的值本身是一个键值对结构 value = {{field1,value1},{field, value}…}
3.1 命令
(1)设置值:hset key field value
(2)获取值:hget key field
(3)删除field:hdel key field
(4)计算field个数 hlen key
(5)判断field是否存在:hexists key field
(6)获取所有field:hkeys key
(7)获取所有的value: hvals key
3.2 内部编码
(1)ziplist :压缩列表
当hash元素个数<512 且 所有值<64个字节。
(2)hashtable 哈希表
当不满足(1)条件时。
4. 列表
一个列表最多存储2^32-1个元素。两个特点:(1)列表中元素是有序的,可以通过索引找到某个元素。(2)元素可以使重复。
4.1 命令
(1)插入
a. 从右边插入 rpush key value
b. 在某个元素前或者后面插入 linsert key before|after pivot value
(2)查找
a. 获取指定范围内的元素列表 lrange key start end
b. 获取列表指定索引下标的元素 lindex key index
c. 获取列表长度 llen key
(3)删除
a. 从列表左侧弹出元素 lpop
b. 删除指定元素 lrem key count value
(4)修改
lset key index newValue
(5)堵塞操作
4.3 使用场景
(1)消息队列
(2)文章列表
5. 集合
不允许重复元素,元素是无序的,不能通过索引下标获取。
5.1 命令
(1)添加元素 sadd key element
(2)删除元素 srem key element
(3)计算元素个数 scard key 时间复杂度度 O(1)
(4)判断元素是否在集合中 sismember key element
(5)从集合中返回指定个数元素 srandmember key count 时间复杂度 O(l)
(6)从集合和随机弹出元素 spop key
5.2 内部编码
(1) intset
(2)hashtable
5.3 使用场景
5.3.1 标签
(1)给用户增加标签
sadd user:1:tage tag1 tag2
(2)给标签增加用户
sadd tag1:users user:1 user:3
注意:用户和标签的关系维护应该在一个事务类执行。redis 事务和Lua。
6. 有序集合
集合元素不可重复,score可以重复,元素可以排序,给每个元素设置一个分数(score)做为排序的依据。
6.1 命令
(1)增加成员 zadd key score member
(2)计算成员个数 zcard key O(1)
(3)计算某个成员分数 zscore key member
(4)计算成员的排名 zrank key member
(5) 删除成员 zrem key member
注意:注意命令的时间复杂度!
6.3 使用场景
典型使用场景是排行榜。
7. 键管理
7.1 单个键管理
(1)键重新命名
rename key newKey :由于重命名键期间会执行del命令删除旧的键,如果对应的值比较大,会阻塞Redis的可能性。不要忽略。
(2)键过期
expire key seconds 在seconds 妙后过期
expireat key timestamp 在秒级时间戳过期
(3)persist 将键的过期时间清除掉
(4)对于字符串类型的键,执行set会清除掉过期时间!!!
(5)迁移键
a. move key db
在一个redis实例内部的不同数据库进行迁移。 (不建议生产上在一个redis实例上建立多个数据库)
b. dump + restore
实现在不同redis实例之间的数据迁移。步骤如下:
- 在源Redis上,dump命令会把键值序列化,格式采用的是RDB格式。
- 在目标Redis上,restore 命令将上面序列化的值进行复原。
- 注意: 整个迁徙过程不是原子的,是通过客户端分部完成的。
c. migrate
(1)migrate 也是用于redis实例间进行数据迁移,是将dump,restore,del 三个命令进行组合,具有原子性。
(2)直接在源redis和目标redis上操作。
(3)目标redis完成restore之后,发送OK给源Redis,源redis再根据migrate选项决定是否在源Redis上删除对应的键。
7.2 遍历键
(1)全量遍历键 keys pattern:
注意:不建议在生产上使用。
(2)渐进式遍历 (redis 2.8)
解决可能带来的阻塞问题,时间复杂度为O(1)。
scan cursor matchpattern count number
cursor = 0 时 表示遍历完了。
(3)注意:如果scan 在遍历的过程中,有key的变化,新增的键可能没有遍历到,遍历出重复键的情况,scan 并不能保证完成的遍历键,要注意。