1.全局命令
keys * | 查看所有键 |
dbsize | 键总数 |
exists key | 检查键是否存在 |
del key [key ...] | 删除键 |
expire key seconds | .键过期 |
type key | 键的数据结构类型 |
dbsize命令在计算键总数时不会遍历所有键,而是直接获取Redis内置的 键总数变量,所以dbsize命令的时间复杂度是O(1)。而keys命令会遍历所 有键,所以它的时间复杂度是O(n),当Redis保存了大量键时,线上环境禁止使用。
Redis支持对键添加过期时间,当超过过期时间后,会自动删除键,例如为键hello设置了10秒过期时间:expire hello 10
- ttl命令会返回键的剩余过期时间,它有3种返回值:
- 大于等于0的整数:键剩余的过期时间。
- ·-1:键没设置过期时间。
- ·-2:键不存在
2.数据结构内部编码
过object encoding key | 查询内部编码 |
Redis这样设计有两个好处:第一,可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对外部用户来说基本感知不到。第二,多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为 linkedlist。
3.单线程架构
Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。
- 为什么Redis使用单线程模 型会达到每秒万级别的处理能力呢?
- 第一,纯内存访问。
- 第二,非阻塞I/O。
- 第三,单线程避免了线程切换和竞态产生的消耗。
4.字符串
字符串类型是Redis最基础的数据结构。首先键都是字符串类型,而且 其他几种数据结构都是在字符串类型基础上构建的。字符串类型的值实际可以 是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字 (整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能 超过512MB。
4.1 命令
4.1.1常用命令
设置值
set key value [ex seconds] [px milliseconds] [nx|xx] | 设置值 |
例如设置键为hello,值为world的键值对,返回结果为OK代表设置 成功:set hello world
- 选项
- ·ex seconds:为键设置秒级过期时间。
- ·px milliseconds:为键设置毫秒级过期时间。
- ·nx:键必须不存在,才可以设置成功,用于添加。
- ·xx:与nx相反,键必须存在,才可以设置成功,用于更新。
除了set选项,Redis还提供了setex和setnx两个命令:setex key seconds value
setnx key value
它们的作用和ex和nx选项是一样的。
指令使用例子:set hello world
setnx hello redis
set hello jedis xx
获取值
get key | 获取值 |
例如:127.0.0.1:6379> get hello
"world"
如果要获取的键不存在,则返回nil(空):
批量设置值
mset key value [key value ...] | 批量设置值 |
下面操作通过mset命令一次性设置4个键值对:mset a 1 b 2 c 3 d 4
批量获取值
mget key [key ...] | 批量获取值 |
下面操作批量获取了键a、b、c、d的值:mget a b c d
批量处理可以省时间,因为对于客户端来说,一次命令除了命令时间还是有网络时间,Redis的处理能力已经足够高,对于开发人员来说,网络可能会成为性能的瓶颈。要注意的是每次批量操作所发送的命令数不是无节制的,如果数量过多可能造成Redis阻塞或者网络拥塞。
计数
incr key | 计数 |
decr key | 自减 |
incrby key increment | 自增指定数字 |
decrby key decrement | 自减指定数字 |
incrbyfloat key increment | 自增浮点数 |
- incr命令用于对值做自增操作,返回结果分为三种情况:
- ·值不是整数,返回错误。
- 值是整数,返回自增后的结果。
- 键不存在,按照值为0自增,返回结果为1。
4.1.2不常用命令
追加值
append key value | 追加值 |
append可以向字符串尾部追加值,例如:append key world
字符串长度
strlen key | 字符串长度 |
设置并返回原值
getset key value | 设置并返回原值 |
设置指定位置的字符
setrange key offeset value | 设置指定位置的字符 |
offeste为要改变位置字符的位置
获取部分字符串
getrange key start end | 获取部分字符串 |
start和end分别是开始和结束的偏移量,偏移量从0开始计算,例如下面操作获取了值best的前两个字符:getrange redis 0 1
表2-2是字符串类型命令的时间复杂度,开发人员可以参考此表,结合 自身业务需求和数据大小选择适合的命令。
4.2内部编码
- 字符串类型的内部编码有3种:
- ·int:8个字节的长整型。
- ·embstr:小于等于39个字节的字符串。
- raw:大于39个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
5. 哈希
5.1命令
设置值
hset key field value | 设置值 |
下面为user:1添加一对field-value:hset user:1 name tom
如果设置成功会返回1,反之会返回0。此外Redis提供了hsetnx命令,它 们的关系就像set和setnx命令一样,只不过作用域由键变为field。
获取值
hget key field | 获取值 |
例如,下面操作获取user:1的name域(属性)对应的值:hget user:1 name
如果键或field不存在,会返回nil:
删除field
hdel key field [field ...] | 删除field |
hdel会删除一个或多个field,返回结果为成功删除field的个数,例如:hdel user:1 name
计算field个数
hlen key | 计算field个数 |
批量设置或获取field-value
hmget key field [field ...] | 批量获取field-value |
hmset key field value [field value ...] | 批量设置field-value |
判断field是否存在
hexists key field | 判断field是否存在 |
获取所有field
hkeys key | 获取所有field |
获取所有的field-value
hgetall key | 获取所有的field-value |
在使用hgetall时,如果哈希元素个数比较多,会存在阻塞Redis的可能。 如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部 field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型。
hincrby hincrbyfloat
hincrby key field | 自增指定数字 |
hincrbyfloat key field | 自增浮点数 |
计算value的字符串长度(需要Redis3.2以上)
hstrlen key field | 计算value的字符串长度 |
5.2内部编码
·ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries 配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64 字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的 结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。
·hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使 用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而 hashtable的读写时间复杂度为O(1)。
6. 列表
列表(list)类型是用来存储多个有序的字符串,列表中的每个字符串 称为元素(element),一个列表最多可以存储 -1个元素。
在Redis中,可 以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比 较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用 场景。
- 列表类型有两个特点:
- 第一、列表中的元素是有序的,这就意味着可以 通过索引下标获取某个元素或者某个范围内的元素列表
- 列表中的元素可以是重复的
6.1 命令
操作类型 | 操作 |
添加 | rpush lpush linsert |
查找 | lrange lindex llen |
删除 | lpop rpop lrem ltrim |
修改 | lset |
阻塞操作 | blpop brpop |
添加操作
从右边插入元素
rpush key value [value ...]
从左边插入元素
lpush key value [value ...]
向某个元素前或者后插入元素
linsert key before|after pivot value
linsert命令会从列表中找到等于pivot的元素,在其前(before)或者后 (after)插入一个新的元素value。
.查找
获取指定范围内的元素列表
lrange key start end
- lrange操作会获取列表指定索引范围所有的元素。索引下标有三个特点:
- 第一,索引下标从左到右分别是0到N-1,但是从右到左分别是-1到-N。
- 第二,lrange中的end选项包含了自身
- 第三,lrange 0 -1命令可以从左到右获取列表的所有元素:
获取列表指定索引下标的元素
lindex key index
获取列表长度
llen key
删除
从列表左侧弹出元素
lpop key
从列表右侧弹出
rpop key
删除指定元素
lrem key count value
- lrem命令会从列表中找到等于value的元素进行删除,根据count的不同 分为三种情况:
- count>0,从左到右,删除最多count个元素。
- count<0,从右到左,删除最多count绝对值个元素。
- count=0,删除所有
按照索引范围修剪列表
ltrim key start end
只保留列表第start个到第end个元素
修改
修改指定索引下标的元素:
lset key index newValue
阻塞操作
阻塞式弹出如下:
blpop key [key ...] timeout
brpop key [key ...] timeout
blpop和brpop是lpop和rpop的阻塞版本,它们除了弹出方向不同,使用方法基本相同,
- brpop命令包含两个参数:
- key[key...]:多个列表的键。
- ·timeout:阻塞时间(单位:秒)。
- 1)列表为空:如果timeout=3,那么客户端要等到3秒后返回,如果 timeout=0,那么客户端一直阻塞等下去:brpop list:test 3 brpop list:test 0
如果此期间添加了数据element1,客户端立即返回: - 列表不为空:客户端会立即返回。brpop list:test 0
- 两点需要注意
- 第一点,如果是多个键,那么brpop会从左至右遍历键,一旦有一个键能弹出元素,客户端立即返回:
- 第二点,如果多个客户端对同一个键执行brpop,那么最先执行brpop命 令的客户端可以获取到弹出的值。
6.2 内部编码
·ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时(默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用。
·linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用linkedlist作为列表的内部实现。
使用场景
- ·lpush+lpop=Stack(栈)
- ·lpush+rpop=Queue(队列)
- ·lpsh+ltrim=Capped Collection(有限集合)
- ·lpush+brpop=Message Queue(消息队列)
7.集合
集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一 样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。
7.1 命令
下面将按照集合内和集合间两个维度对集合的常用命令进行介绍。
7.1.1集合内命令
添加元素
sadd key element [element ...]
返回结果为添加成功的元素个数
删除元素
srem key element [element ...]
返回结果为成功删除元素个数
计算元素个数
scard key
scard的时间复杂度为O(1),它不会遍历集合所有元素,而是直接用 Redis内部的变量。
判断元素是否在集合中
sismember key element
如果给定元素element在集合内返回1,反之返回0
随机从集合返回指定个数元素
srandmember key [count]
[count]是可选参数,如果不写默认为1,例如:
从集合随机弹出元素
spop key
需要注意的是Redis从3.2版本开始,spop也支持[count]参数。
srandmember和spop都是随机从集合选出元素,两者不同的是spop命令 执行后,元素会从集合中删除,而srandmember不会。
获取所有元素
smembers key
smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻 塞Redis的可能性,这时候可以使用sscan来完成。
7.1.2 集合间操作
求多个集合的交集
sinter key [key ...]
求多个集合的并集
suinon key [key ...]
求多个集合的差集
sdiff key [key ...]
将交集、并集、差集的结果保存
sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...]
7.2 内部编码
intset(整数集合):当集合中的元素都是整数且元素个数小于set-maxintset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使 用hashtable作为集合的内部实现。
使用场景
- sadd=Tagging(标签)
- spop/srandmember=Random item(生成随机数,比如抽奖)
- sadd+sinter=Social Graph(社交需求)
8. 有序集合
它保留了集合不能有重复成员的特性, 但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下标作为排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依据。
有序集合中的元素不能重复,但是score可以重复。
8.1 命令
本节依旧按照集合内和集合外两个维度对有序集合的命令进行介绍。
8.1.1集合内
添加成员
zadd key score member [score member ...]
- 有关zadd命令有两点需要注意:
- Redis3.2为zadd命令添加了nx、xx、ch、incr四个选项:
- nx:member必须不存在,才可以设置成功,用于添加。
- xx:member必须存在,才可以设置成功,用于更新。
- ch:返回此次操作后,有序集合元素和分数发生变化的个数
- incr:对score做增加,相当于后面介绍的zincrby。
- ·有序集合相比集合提供了排序字段,但是也产生了代价,zadd的时间 复杂度为O(log(n)),sadd的时间复杂度为O(1)。
- Redis3.2为zadd命令添加了nx、xx、ch、incr四个选项:
计算成员个数
zcard key
计算某个成员的分数
zscore key member
计算成员的排名
zrank key member
zrevrank key member
zrank是从分数从低到高返回排名,zrevrank反之。
删除成员
zrem key member [member ...]
增加成员的分数
zincrby key increment member
返回指定排名范围的成员
zrange key start end [withscores]
zrevrange key start end [withscores]
如果加上withscores选项,同时会返回成员的分数:zrange user:ranking 0 2 withscores
返回指定分数范围的成员
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
[limit offset count]选项可以限制输出的起始位置和个数:同时min和max还支持开区间(小括号)和闭区间(中括号),-inf和 +inf分别代表无限小和无限大:
返回指定分数范围成员个数
zcount key min max
删除指定排名内的升序元素
zremrangebyrank key start end
删除指定分数范围的成员
zremrangebyscore key min max
8.1.2集合间的操作
交集
zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]
- 这个命令参数较多,下面分别进行说明:
- destination:交集计算结果保存到这个键。
- numkeys:需要做交集计算键的个数。
- key[key...]:需要做交集计算的键。
- weights weight[weight...]:每个键的权重,在做交集计算时,每个键中 的每个member会将自己分数乘以这个权重,每个键的权重默认是1。
- aggregate sum|min|max:计算成员交集后,分值可以按照sum(和)、 min(最小值)、max(最大值)做汇总,默认值是sum。
并集
zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]
该命令的所有参数和zinterstore是一致的,只不过是做并集计算,
8.2 内部编码
·ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplistentries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。
·skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作 为内部实现,因为此时ziplist的读写效率会下降。
9. 键管理
本节将按照单个键、遍历键、数据库管理三个维度对一些通用命令进行介绍。
9.1 单个键管理
键重命名
rename key newkey
为了防止被强行rename,Redis提供了renamenx命令,确保只有newKey 不存在时候才被覆盖,
- 在使用重命名命令时,有两点需要注意:
- 由于重命名键期间会执行del命令删除旧的键,如果键对应的值比较大,会存在阻塞Redis的可能性,这点不要忽视。
- 如果rename和renamenx中的key和newkey如果是相同的,在Redis3.2和之 前版本返回结果略有不同。Redis3.2中会返回OK:Redis3.2之前的版本会提示错误:
.随机返回一个键
randomkey
键过期
expire key seconds:键在seconds秒后过期
expireat key timestamp:键在秒级时间戳timestamp后过期。
pexpire key milliseconds:键在milliseconds毫秒后过期。
pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期。
ttl命令和pttl都可以查询键的剩余过期时间,但是pttl精度更高可以达到毫秒级别,
- 有3种返回值:
- 大于等于0的整数:键剩余的过期时间(ttl是秒,pttl是毫秒)。
- -1:键没有设置过期时间。
- -2:键不存在。
- 在使用Redis相关过期命令时,需要注意以下几点。
- 如果expire key的键不存在,返回结果为0:
- 如果过期时间为负值,键会立即被删除,犹如使用del命令一样:
- persist命令可以将键的过期时间清除:
- 对于字符串类型键,执行set命令会去掉过期时间:
- Redis不支持二级数据结构(例如哈希、列表)内部元素的过期功 能,例如不能对列表类型的一个元素做过期时间设置。
- setex命令作为set+expire的组合,不但是原子执行,同时减少了一次 网络通讯的时间。
迁移键
Redis发展历程中提 供了move、dump+restore、migrate三组迁移键的方法,它们的实现方式以及 使用的场景不太相同,下面分别介绍。
move
move key db
dump+restore
dump key
restore key ttl value
- dump+restore可以实现在不同的Redis实例之间进行数据迁移的功能,整 个迁移的过程分为两步:
- 在源Redis上,dump命令会将键值序列化,格式采用的是RDB格式。
- 在目标Redis上,restore命令将上面序列化的值进行复原,其中ttl参数代表过期时间,如果ttl=0代表没有过期时间。
- 有关dump+restore有两点需要注意:
- 第一,整个迁移过程并非原子性 的,而是通过客户端分步完成的。
- 第二,迁移过程是开启了两个客户端连 接,所以dump的结果不是在源Redis和目标Redis之间进行传输。
migrate
migrate host port key|"" destination-db timeout [copy] [replace] [keys key [key
migrate命令也是用于在Redis实例间进行数据迁移的,实际上migrate命令就是将dump、restore、del三个命令进行组合,从而简化了操作流程。 migrate命令具有原子性,而且从Redis3.0.6版本以后已经支持迁移多个键的 功能,有效地提高了迁移效率
- 下面对migrate的参数进行逐个说明:
- host:目标Redis的IP地址。
- port:目标Redis的端口。
- key|"":在Redis3.0.6版本之前,migrate只支持迁移一个键,所以此处是 要迁移的键,但Redis3.0.6版本之后支持迁移多个键,如果当前需要迁移多 个键,此处为空字符串""。
- destination-db:目标Redis的数据库索引。
- ·timeout:迁移的超时时间(单位为毫秒)。
- ·[copy]:如果添加此选项,迁移后并不删除源键。
- [replace]:如果添加此选项,migrate不管目标Redis是否存在该键都会正常迁移进行数据覆盖。
- ·[keys key[key...]]:迁移多个键,例如要迁移key1、key2、key3,此处填 写“keys key1 key2 key3”。
下面用示例演示migrate命令,为了方便演示源Redis使用6379端口,目 标Redis使用6380端口,现要将源Redis的键hello迁移到目标Redis中,会分为 如下几种情况:
源Redis有键hello,目标Redis没有:
migrate 127.0.0.1 6380 hello 0 1000
源Redis和目标Redis都有键hello:
如果migrate命令没有加replace选项会收到错误提示,如果加了replace会 返回OK表明迁移成功:
migrate 127.0.0.1 6379 hello 0 1000
migrate 127.0.0.1 6379 hello 0 1000 replace
源Redis没有键hello。如下所示,此种情况会收到nokey的提示:
migrate 127.0.0.1 6380 hello 0 1000
源Redis批量添加多个键:
mset key1 value1 key2 value2 key3 value3
源Redis执行如下命令完成多个键的迁移:
migrate 127.0.0.1 6380 "" 0 5000 keys key1 key2 key3
9.2 遍历键
全量遍历键
keys pattern
实际上keys命令是支持pattern匹配的,
- 通配符:
- *代表匹配任意字符
- ·代表匹配一个字符。
- ·[]代表匹配部分字符,例如[1,3]代表匹配1,3,[1-10]代表匹配1到10 的任意数字。
- \x用来做转义,例如要匹配星号、问号需要进行转义。
渐进式遍历
scan cursor [match pattern] [count number]
- cursor是必需参数,实际上cursor是一个游标,第一次遍历从0开始,每 次scan遍历完都会返回当前游标的值,直到游标值为0,表示遍历结束。
- match pattern是可选参数,它的作用的是做模式的匹配,这点和keys的 模式匹配很像。
- ·count number是可选参数,它的作用是表明每次要遍历的键个数,默认 值是10,此参数可以适当增大。
除了scan以外,Redis提供了面向哈希类型、集合类型、有序集合的扫 描遍历命令,解决诸如hgetall、smembers、zrange可能产生的阻塞问题,对 应的命令分别是hscan、sscan、zscan,它们的用法和scan基本类似,
9.3数据库管理
Redis提供了几个面向Redis数据库的操作,它们分别是dbsize、select、 flushdb/flushall命令,本节将通过具体的使用场景介绍这些命令。
切换数据库
select dbIndex
Redis只是用数 字作为多个数据库的实现。Redis默认配置中是有16个数据库:
清除数据库
.flushdb/flushall
两者的区别的是flushdb只清除当 前数据库,flushall会清除所有数据库。