第2章 API的理解和使用
2.1全局命令
- 查看所有键keys *
- 键总数 dbsize
- 检查键是否存在 exists key
- 删除键 del key [key …]
- 键过期 expire key seconds
- 键的数据结构类型type key
- 键重命名 rename key newkey
- 随机返回一个键 randomkey
- 键过期expire key seconds:键在seconds秒后过期
- ·expireat key timestamp:键在秒级时间戳timestamp后过期。ttl命令和pttl都可以查询键的剩余过期时间,但是pttl精度更高可以达到
毫秒级别,有3种返回值:
·大于等于0的整数:键剩余的过期时间(ttl是秒,pttl是毫秒)。
·-1:键没有设置过期时间。
·-2:键不存在。 - 毫秒级的过期方案
- pexpire key milliseconds:键在milliseconds毫秒后过期
- pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过
期但
无论是使用过期时间还是时间戳,秒级还是毫秒级,在Redis内部最
终使用的都是pexpireat。
1)如果expire key的键不存在,返回结果为0:
2)如果过期时间为负值,键会立即被删除,犹如使用del命令一样
3)persist命令可以将键的过期时间清除:
4)对于字符串类型键,执行set命令会去掉过期时间,这个问题很容易
在开发中被忽视
- 迁移键
(1)move key db
(2)dump+restore
(3)migrate - flushdb/flushall
flushdb/flushall命令用于清除数据库,两者的区别的是flushdb只清除当
前数据库,flushall会清除所有数据库 - 切换数据库
select dbIndex
Redis默认配置中是有16个数据库: databases 16
2.2 数据结构和内部编码
[外链图片转存失败(img-fNGUXJX2-1562315025063)(C:\Users\yx20180503\AppData\Roaming\Typora\typora-user-images\1561452468712.png)]
[外链图片转存失败(img-TKpeeWx7-1562315025064)(C:\Users\yx20180503\AppData\Roaming\Typora\typora-user-images\1561452477286.png)]
单线程架构:Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库,每次客户端调用都经历了发送命令、执行命令、返回结果三个过程,因为Redis是单线程来处理命令的,所以一
条命令从客户端达到服务端不会立刻被执行,所有命令都会进入一个队列中,然后逐个被执行。不会产生并发问题
2.为什么单线程还能这么快
第一,纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
第二,非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间
第三,单线程避免了线程切换和竞态产生的消耗
2.3 字符串
2.3.1 字符串类型的值实际可以是
- 字符串(简单的字符串、复杂的字符串(例如JSON、XML))
- 数字(整数、浮点数)
- 甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。
2.3.2 命令
常用命令:
-
设置值 set key value [ex seconds] [px milliseconds] [nx|xx]set命令有几个选项:
·ex seconds:为键设置秒级过期时间。
·px milliseconds:为键设置毫秒级过期时间。
·nx:键必须不存在,才可以设置成功,用于添加。
·xx:与nx相反,键必须存在,才可以设置成功,用于更新。
除了set选项,Redis还提供了setex和setnx两个命令:
setex key seconds value
setnx key value -
获取值get key
-
批量设置值 mset key value [key value …]
-
批量获取值 mget key [key …]
-
计算 incr key
-
decr key(自减)
incrby key increment (自增指定数字)
decrby key decrement (自减指定数字)
incrbyfloat key increment (自增浮点数) -
追加值 append key value
-
字符串长度 strlen key
-
设置并返回原值 getset key value
-
设置指定位置的字符 setrange key offeset value
-
获取部分字符串 getrange key start end
批量操作命令可以有效提高开发效率,假如没有mget这样的命令,要执行n次get命令需要消耗多余的网络时间
Redis可以支撑每秒数万的读写操作,但是这指的是Redis服务端的处理能力,对于客户端来说,一次命令除了命令时间还是有网络时间,假设网络时间为1毫秒,命令时间为0.1毫秒(按照每秒处理1万条命令算),那么执行1000次get命令和1次mget命令的区别,因为Redis的处理能力已经足够高,对于开发人员来说,网络可能会成为性能的瓶颈。
2.3.3 内部编码
字符串类型的内部编码有3种:
-
int:8个字节的长整型。
-
embstr:小于等于39个字节的字符串。
-
raw:大于39个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
2.3.4 典型使用场景
- 缓存功能
其中Redis作为缓存层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用 - 计数
使用Redis作为视频播放数计数的基础组件,用户每
播放一次视频,相应的视频播放数就会自增1: - 共享Session
可以使用Redis将用户的Session进行集中管理 - 限速
但是为了短信接口不被频繁访问,会限制用
户每分钟获取验证码的频率,例如一分钟不能超过5次
2.4哈希hash
2.4.1 命令
- 设置值 hset key field value
- 获取值 hget key field
- 删除field hdel key field [field …]
- 计算field个数 hlen key
- 批量设置或获取field-value
hmget key field [field …]
hmset key field value [field value …] - 判断field是否存在
hexists key field - 获取所有field
hkeys key - 获取所有value
hvals key - 获取所有的field-value
hgetall key - 计算value的字符串长度
hstrlen key field
2.4.2 内部编码
哈希类型的内部编码有两种:
-
ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64
字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。 -
hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。
-
1)当field个数比较少且没有大的value时,内部编码为ziplist:
2.1)当有value大于64字节,内部编码会由ziplist变为hashtable:
2.2)当field个数超过512,内部编码也会由ziplist变为hashtable:
2.4.3 使用场景
1.法缓存用户信息 每个用户属性使用一对field-value,但是只用一个键保存。
[外链图片转存失败(img-2XpGFPK2-1562315025065)(C:\Users\yx20180503\AppData\Roaming\Typora\typora-user-images\1561454081638.png)]
2.5列表list
2.5.1 命令
(1)从右边插入元素 rpush key value [value …]
(2)从左边插入元素 lpush key value [value …]
(3)向某个元素前或者后插入元素 linsert key before|after pivot value
2.查找
(1)获取指定范围内的元素列表 lrange key start end
(2)获取列表指定索引下标的元素 lindex key index
(3)获取列表长度 llen key
3.删除
(1)从列表左侧弹出元素 lpop key
(2)从列表右侧弹出 rpop key
(3)删除指定元素 lrem key count valuek
·count>0,从左到右,删除最多count个元素。
·count<0,从右到左,删除最多count绝对值个元素。
·count=0,删除所有。
(4)按照索引范围修剪列表 ltrim key start end
4.修改
修改指定索引下标的元素 lset key index newValue
5.阻塞操作
阻塞式弹出如下:
blpop key [key …] timeout
brpop key [key …] timeout
1)列表为空:如果timeout=3,那么客户端要等到3秒后返回,如果
timeout=0,那么客户端一直阻塞等下去:
127.0.0.1:6379> brpop list:test 3
(nil)
(3.10s)
127.0.0.1:6379> brpop list:test 0
…阻塞…
如果此期间添加了数据element1,客户端立即返回:
127.0.0.1:6379> brpop list:test 3
- “list:test”
- “element1”
(2.06s)
2)列表不为空:客户端会立即返回。
127.0.0.1:6379> brpop list:test 0
- “list:test”
- “element1”
127.0.0.1:6379> brpop list:1 list:2 list:3 0
…阻塞…
此时另一个客户端分别向list:2和list:3插入元素:
client-lpush> lpush list:2 element2
(integer) 1
client-lpush> lpush list:3 element3
(integer) 1
客户端会立即返回list:2中的element2,因为list:2最先有可以弹出的
元素:
127.0.0.1:6379> brpop list:1 list:2 list:3 0
- “list:2”
- “element2_1”
第二点,如果多个客户端对同一个键执行brpop,那么最先执行brpop命
令的客户端可以获取到弹出的值。
2.5.2 内部编码
- ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置
(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时
(默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使
用。 - linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用
linkedlist作为列表的内部实现。
2.5.3 使用场景
-
消息队列
Redis的lpush+brpop命令组合即可实现阻塞队列,生产
者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令
阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用
性。 -
文章列表
每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以
考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。1)每篇文章使用哈希结构存储,例如每篇文章有3个属性title、timestamp、content:
hmset acticle:1 title xx timestamp 1476536196 content xxxx…
hmset acticle:k title yy timestamp 1476512536 content yyyy…
2)向用户文章列表添加文章,
user:{id}:articles作为用户文章列表的
键:
lpush user:1:acticles article:1 article3…
lpush user:k:acticles article:5…
3)分页获取用户文章列表,例如下面伪代码获取用户id=1的前10篇文章:
articles = lrange user:1:articles 0 9
for article in {articles}
hgetall {article}
2.6集合set
[外链图片转存失败(img-X27UC1RE-1562315025065)(C:\Users\yx20180503\AppData\Roaming\Typora\typora-user-images\1561537926791.png)]
2.6.1命令
1.集合内操作
(1)添加元素 sadd key element [element …]
(2)删除元素 srem key element [element …]
(3)计算元素个数 scard key
(4)判断元素是否在集合中 sismember key element
(5)随机从集合返回指定个数元素 srandmember key [count]
(6)从集合随机弹出元素 spop key
(7)获取所有元素 smembers key
2.集合间操作
(1)求多个集合的交集 sinter key [key …]
(2)求多个集合的并集 suinon key [key …]
(3)求多个集合的差集 sdiff key [key …]
(4)将交集、并集、差集的结果保存
sinterstore destination key [key …]
suionstore destination key [key …]
sdiffstore destination key [key …]
2.6.2 内部编码
集合类型的内部编码有两种:
- intset(整数集合):当集合中的元素都是整数且元素个数小于set-maxintset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实
现,从而减少内存的使用。 - hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使
用hashtable作为集合的内部实现
2.6.3 使用场景
(1)给用户添加标签
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
…
sadd user:k:tags tag1 tag2 tag4
(2)给标签添加用户
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
…
sadd tagk:users user:1 user:2
(3)删除用户下的标签
srem user:1:tags tag1 tag5
(4)删除标签下的用户。
srem tag1:users user:1
srem tag5:users user:1
(3)和(4)也是尽量放在一个事务执行。
(5)计算用户共同感兴趣的标签
sinter user:1:tags user:2:tags
2.7 有序集合
[外链图片转存失败(img-qMnkV16N-1562315025066)(C:\Users\yx20180503\AppData\Roaming\Typora\typora-user-images\1561538732941.png)]
2.7.1命令
1.集合内
(1)添加成员 zadd key score member [score member …]
(2)计算成员个数 zcard key
(3)计算某个成员的分数 zscore key member
(4)计算成员的排名 zrank是从分数从低到高返回排名,zrevrank反之
zrank key member
zrevrank key member
(5)删除成员 zrem key member [member …]
(6)增加成员的分数 zincrby key increment member
(7)返回指定排名范围的成员 如果加上withscores选项,同时会返回成员的分数
zrange key start end [withscores]
zrevrange key start end [withscores]
(8)返回指定分数范围的成员
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
(9)返回指定分数范围成员个数
zcount key min max
(10)删除指定排名内的升序元素
zremrangebyrank key start end
(11)删除指定分数范围的成员
zremrangebyscore key min max
2.7.2 集合间的操作
(1)交集
zinterstore destination numkeys key [key …] [weights weight [weight …]]
[aggregate sum|min|max]
destination:交集计算结果保存到这个键。
·numkeys:需要做交集计算键的个数。
·key[key…]:需要做交集计算的键。
2.7.3 内部编码
有序集合类型的内部编码有两种:
-
·ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplistentries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配
置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist
可以有效减少内存的使用。当元素个数较少且每个元素较小时,内部编码为skiplist:
当元素个数超过128个,内部编码变为ziplist:
当某个元素大于64字节时,内部编码也会变为hashtable -
·skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作
为内部实现,因为此时ziplist的读写效率会下降
2.7.4 使用场景
(1)添加用户赞数 zadd user:ranking:2016_03_15 mike 3
(2)取消用户赞数 zrem user:ranking:2016_03_15 mike
(3)展示获取赞数最多的十个用户 zrevrangebyrank user:ranking:2016_03_15 0 9
(4)展示用户信息以及用户分数
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike