redis-API的理解和使用

本文深入解析Redis的五种核心数据结构:字符串、哈希、列表、集合和有序集合,涵盖每种数据结构的命令、内部编码及典型应用场景,同时讲解Redis的单线程架构与键管理命令,为开发者和运维人员提供全面指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

 

一.前言

二.预备

2.1全局命令

 

2.2 数据结构和编码

2.3单线程架构

三.字符串

3.1 命令

3.2 内部编码

3.3典型使用场景

四.哈希

4.1命令

4.2内部编码

五.列表

5.1命令

5.2内部编码

5.3使用场景

六. 集合

6.1命令

6.2内部编码

6.3使用场景

七.有序集合

7.1命令

7.2内部编码

7.3使用场景

八.键管理


一.前言

Redis提供了5种数据结构,理解每种数据结构的特点对于Redis开发运维非常重要,同时掌握Redis的单线程命令处理机制,会使数据结构和命令的选择事半功倍。

二.预备

在正式介绍5种数据结构之前,了解一下Redis的一些全局命令、数据结构和内部编码、单线程命令处理机制是十分有必要的,它们能为后面内容的学习打下一个好的基础,主要体现在两个方面:第一、Redis的命令有上百个,如果纯靠死记硬背比较困难,但是如果理解Redis的一些机制,会发现这些命令有很强的通用性。第二、Redis不是万金油,有些数据结构和命令必须在特定场景下使用,一旦使用不当可能对Redis本身或者应用本身造成致命伤害。

2.1全局命令

Redis有5种数据结构,它们是键值对中的值,对于键来说有一些通用的命令。

命令描述备注
keys *查看所有键keys命令会遍历所有键,所以它的时间复杂度是O(n),当Redis保存了大量键时,线上环境禁止使用。
dbsizedbsize命令会返回当前数据库中键的总数dbsize命令在计算键总数时不会遍历所有键,而是直接获取Redis内置的
键总数变量,所以dbsize命令的时间复杂度是O(1)。
exists key如果键存在则返回1,不存在则返回0 
del key [key ...]删除键del是一个通用命令,无论值是什么数据结构类型,del命令都可以将其删除,返回结果为成功删除键的个数,假设删除一个不存在的键,就会返回0
expire key secondsRedis支持对键添加过期时间,当超过过期时间后,会自动删除键, 
ttl返回键的剩余过期时间

有3种返回值:
·大于等于0的整数:键剩余的过期时间。

·-1:键没设置过期时间。

-2:键不存在

type key键的数据结构类型键不存在,则返回none:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)

 

2.2 数据结构和编码

实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码,如图2-2所示。可以看到每种数据结构都有两种以上的内部编码实现,例如list数据结构包含了linkedlist和ziplist两种内部编码。同时有些内部编码,例如ziplist,可以作为多种外部数据结构的内部实现,可以通过object encoding命令查询内部编码。

Redis这样设计有两个好处:第一,可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令,例如Redis3.2提供了quicklist,结合了ziplist和linkedlist两者的优势,为列表类型提供了一种更为优秀的内部编码实现,而对外部用户来说基本感知不到。第二,多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist。

 

2.3单线程架构

Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。因为Redis是单线程来处理命令的,所以一
条命令从客户端达到服务端不会立刻被执行,所有命令都会进入一个队列中,然后逐个被执行。

为什么Redis使用单线程模型会达到每秒万级别的处理能力呢?可以将其归结为三点:
第一,纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
第二,非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间,如图2-6所示。

第三,单线程避免了线程切换和竞态产生的消耗。

 

为单线程能带来几个好处

第一,单线程可以简化数据结构和算法的实现。如果对高级编程语言熟悉的读者应该了解并发数据结构实现不但困难而且开发测试比较麻烦。

第二,单线程避免了线程切换和竞态产生的消耗,对于服务端开发来说,锁和线程切换通常是性能杀手。

但是单线程会有一个问题

对于每个命令的执行时间是有要求的。如果某个命令执行过长,会造成其他命令的阻塞,对于Redis这种高性能的服务来说是致命的,所以Redis是面向快速执行场景的数据库。
 

三.字符串

3.1 命令

常用命令
命令描述备注时间复杂度
set key value [ex seconds] [px milliseconds] [nx|xx]设置值

set命令有几个选项:

·ex seconds:为键设置秒级过期时间。

·px milliseconds:为键设置毫秒级过期时间。

·nx:键必须不存在,才可以设置成功,用于添加

·xx:与nx相反,键必须存在,才可以设置成功,用于更新

 

O(1)
setex

和xx选项是一样的

 O(1)
setnx和nx选项是一样的由于Redis的单线程命令处理机制,如果有多个客户端同时执行setnx key value,根据setnx的特性只有一个客户端能设置成功,setnx可以作为分布式锁的一种实现方案,Redis官方给出了使用setnx实现分布式锁的方法:http://redis.io/topics/distlockO(1)
get key获取值如果要获取的键不存在,则返回nil(空)O(1)
mset key value [key value ...]批量设置值 O(k)
mget key [key ...]批量获取值如果有些键不存在,那么它的值为nil(空),结果是按照传入键的顺序返回O(k)
incr key用于对值做自增操作

·值不是整数,返回错误。
·值是整数,返回自增后的结果。
·键不存在,按照值为0自增,返回结果为1。

除了incr命令,Redis提供了decr(自减)、incrby(自增指定数字)、decrby(自减指定数字)、incrbyfloat(自增浮点数)
 

O(1)
不常用命令
命令描述备注时间复杂度
append key value追加值append可以向字符串尾部追加值O(1)
strlen key字符串长度 O(1)
getset key value设置并返回原值getset和set一样会设置值,但是不同的是,它同时会返回键原来的值O(1)
setrange key offeset value设置指定位置的字符 O(1)
getrange key start end获取部分字符串start和end分别是开始和结束的偏移量,偏移量从0开始计算O(n)
n是字符串长度

3.2 内部编码

字符串类型的内部编码有3种:
·int:8个字节的长整型。
·embstr:小于等于39个字节的字符串。
·raw:大于39个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。

3.3典型使用场景

1.缓存功能

2.计数

3.共享Session

4.限速

四.哈希

4.1命令

命令描述备注时间复杂度
hset key field value设置值设置成功会返回1,反之会返回0。
此外Redis提供了hsetnx命令
O(1)
hget key field获取值如果键或field不存在,会返回nilO(1)
hdel key field [field ...]删除fieldhdel会删除一个或多个field,返回结果为成功删除field的个数O(k)
hlen key计算field个数 O(1)
hmget key field [field ...]
hmset key field value [field value ...]
 
批量设置或获取field-value O(k)
hexists key field判断field是否存在不包含时返回0,反之返回结果为1O(1)
hkeys key获取所有field O(n)
hvals key获取所有value O(n)
hgetall key获取所有的field-value在使用hgetall时,如果哈希元素个数比较多,会存在阻塞Redis的可能。如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型。O(n)
hincrby
hincrbyfloat
hincrby和hincrbyfloat,就像incrby和incrbyfloat命令一样,但是它们的作用域是filed O(1)
hstrlen key field计算value的字符串长度(需要edis3.2以上) O(1)

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)。

五.列表

列表类型有两个特点:

第一、列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。

第二、列表中的元素可以是重复的

5.1命令

 命令描述备注时间复杂度
增加rpush key value [value ...]从右边插入元素 O(k)
lpush key value [value ...]从左边插入元素 O(k)
linsert key before|after pivot value向某个元素前或者后插入元素 O(n)
查询lrange key start end获取指定范围内的元素列表

索引下标有两个特点:
第一,索引下标从左到右分别是0到N-1,但是从右到左分别是-1到-N。

第二,lrange中的end选项包含了自身,这个和很多编程语言不包含end不太相同

O(s+n)

s是start的偏移量,n是start到end范围

lindex key index获取列表指定索引下标的元素 O(n)
llen key获取列表长度 O(1)
删除lpop key从列表左侧弹出元素 O(1)
rpop key从列表右侧弹出 O(1)
lrem key count value删除指定元素lrem命令会从列表中找到等于value的元素进行删除,根据count的不同分为三种情况:
·count>0,从左到右,删除最多count个元素。
·count<0,从右到左,删除最多count绝对值个元素。
·count=0,删除所有。
O(n)
ltrim key start end按照索引范围修剪列表如 ltrim listkey 1 3 会只保留列表listkey第2个到第4个元素:
 
O(n)
修改lset key index newValue修改指定索引下标的元素 O(n)
堵塞操作

blpop key [key ...] timeout

 

brpop key [key ...] timeout

·key[key...]:多个列表的键。
·timeout:阻塞时间(单位:秒)

1)列表为空:如果timeout=3,那么客户端要等到3秒后返回,如果timeout=0,那么客户端一直阻塞等下去

2)列表不为空:客户端会立即返回。

O(1)

5.2内部编码

列表类型的内部编码有两种:

·ziplist(压缩列表):当列表的元素个数小于list-max-ziplist-entries配置(默认512个),同时列表中每个元素的值都小于list-max-ziplist-value配置时(默认64字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用。

·linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用linkedlist作为列表的内部实现。(quicklist是3.2版本新增加的,旧版本的linkedlist基本上是被淘汰掉了,而是使用的为quicklist来代替)

5.3使用场景

1.消息队列

2.文章列表

六. 集合

集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素并且集合中的元素是无序的,不能通过索引下标获取元素。

6.1命令

集合内操作
命令描述备注时间复杂度
sadd key element [element ...]添加元素返回结果为添加成功的元素个数,O(k)
srem key element [element ..删除元素返回结果为成功删除元素个数,O(k)
scard key计算元素个数 O(1)
sismember key element判断元素是否在集合中在集合内返回1,反之返回0O(1)
srandmember key [count]随机从集合返回指定个数元素 O(count)
spop key从集合随机弹出元素Redis从3.2版本开始,spop也支持[count]参数。O(1)
smembers key获取所有元素smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,这时候可以使用sscan来完成,O(n)

6.2内部编码

集合类型的内部编码有两种:

intset(整数集合):当集合中的元素都是整数且元素个数小于set-maxintset-entries配置(默认512个)时,Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
·hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合的内部实现。

6.3使用场景

集合类型比较典型的使用场景是标签(tag)。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。

七.有序集合

有序集合相对于哈希、列表、集合来说会有一点点陌生,但既然叫有序集合,那么它和集合必然有着联系,它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下标作为排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依据。

7.1命令

集合内操作
命令描述备注时间复杂度
zadd  [NX|XX] [CH] [INCR]
key score member [score member ...]
添加成员Redis3.2为zadd命令添加了nx、xx、ch、incr四个选项:
·nx:member必须不存在,才可以设置成功,用于添加。
·xx:member必须存在,才可以设置成功,用于更新。
·ch:返回此次操作后,有序集合元素和分数发生变化的个数
·incr:对score做增加,相当于后面介绍的zincrby。

O(k*log(n))

k是添加成员的个数,n是当前有的个数

zcard key计算成员个数 O(1)
zscore key member计算某个成员的分数 O(1)
zrank key member
zrevrank key member
计算成员的排名zrank是从分数从低到高返回排名,zrevrank反之。O(log(n))
zrem key member [member ...]删除成员返回结果为成功删除的个数。

O(k*log(n))

k是添加成员的个数,n是当前有的个数

zincrby key increment member增加成员的分数 

O(log(n))

zrange key start end [withscores]
zrevrange key start end [withscores]
返回指定排名范围的成员有序集合是按照分值排名的,zrange是从低到高返回,zrevrange反之。O(log(n))
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
返回指定分数范围的成员

其中zrangebyscore按照分数从低到高返回,zrevrangebyscore反之。

同时min和max还支持开区间(小括号)和闭区间(中括号),-inf和+inf分别代表无限小和无限大

O(log(n))
zcount key min max返回指定分数范围成员个数 O(log(n))
zremrangebyrank key start end删除指定排名内的升序元素 O(log(n))
zremrangebyscore key min max删除指定分数范围的成员 O(log(n))
集合间的操作
命令描述备注时间复杂度
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是一致的,只不过是做并集计算, 

7.2内部编码

有序集合类型的内部编码有两种:
·ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplistentries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用。
·skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist的读写效率会下降。

7.3使用场景

有序集合比较典型的使用场景就是排行榜系统。

八.键管理

命令描述备注
rename key newkey键重命名

为了防止被强行rename,Redis提供了renamenx命令确保只有newKey不存在时候才被覆盖

由于重命名键期间会执行del命令删除旧的键,如果键对应的值比较大,会存在阻塞Redis的可能性,这点不要忽视

randomkey随机返回一个键 
expireat、pexpire、pexpireat、pttl、persist键过期

·expireat key timestamp:键在秒级时间戳timestamp后过期。

expire key seconds:键在seconds秒后过期。


ttl命令和pttl都可以查询键的剩余过期时间,但是pttl精度更高可以达到
毫秒级别,有3种返回值:
·大于等于0的整数:键剩余的过期时间(ttl是秒,pttl是毫秒)。
·-1:键没有设置过期时间。
·-2:键不存在

 

·pexpire key milliseconds:键在milliseconds毫秒后过期。

·pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期。

 迁移键迁移键功能非常重要,因为有时候我们只想把部分数据由一个Redis迁移到另一个Redis(例如从生产环境迁移到测试环境),Redis发展历程中提供了move、dump+restore、migrate三组迁移键的方法,它们的实现方式以及使用的场景不太相同,下面分别介绍。
......  
.......  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值