美团面试原题:深入理解Redis五种基本数据结构及其在实际开发中的应用,助你轻松应对面试挑战
Redis的五种基本数据结构(String、List、Hash、Set、Sorted Set)在面试中是经常被询问的话题。本文将帮助你回顾这些结构,并加深对它们的理解。
此外,还有几种特殊的数据结构(HyperLogLogs、Bitmap、Geospatial、Stream)也非常重要,我们将留待下次讨论。
对于Redis的详细数据结构介绍,可以参考Redis官方网站:
随着Redis新版本的发布,未来可能会有新数据结构的推出,查阅Redis官网的相关介绍是获取最新信息的最佳途径。
String(字符串)
概述
String是Redis中最基本且最常用的数据结构。它是一个二进制安全的数据结构,能够存储任何数据类型,如字符串、整数、浮点数、图片(例如图片的base64编码或路径)以及序列化后的对象。
尽管Redis是用C语言编写的,但它采用了一种名为简单动态字符串(Simple Dynamic String,SDS)的字符串表示方式。与C语言的原生字符串相比,Redis的SDS不仅可以存储文本数据,还能处理二进制数据,并且获取字符串长度的复杂度为O(1)(C字符串为O(N))。此外,Redis的SDS API设计确保了安全性,避免了缓冲区溢出的问题。
常用命令
命令 | 描述 |
---|---|
SET key value | 设置指定key的值 |
SETNX key value | 仅当key不存在时设置key的值 |
GET key | 获取指定key的值 |
MSET key1 value1 key2 value2 … | 同时设置多个指定key的值 |
MGET key1 key2 ... | 获取多个指定key的值 |
STRLEN key | 返回key所储存字符串值的长度 |
INCR key | 将key中存储的数字值加一 |
DECR key | 将key中存储的数字值减一 |
EXISTS key | 检查指定key是否存在 |
DEL key(通用) | 删除指定的key |
EXPIRE key seconds(通用) | 设置key的过期时间 |
更多Redis String命令和详细使用指南,请查看Redis官网。
基本操作示例
> SET key value
OK
> GET key
"value"
> EXISTS key
(integer) 1
> STRLEN key
(integer) 5
> DEL key
(integer) 1
> GET key
(nil)
应用场景
存储常规数据的场合
- 示例:缓存session、token、图片地址、序列化后的对象(相对Hash存储更节省内存)。
- 相关命令:
SET
、GET
。
计数功能
- 示例:用户单位时间的请求数(简单限流)、页面单位时间的访问数。
- 相关命令:
SET
、GET
、INCR
、DECR
。
分布式锁
利用SETNX key value
命令可以实现一个简单的分布式锁(不过存在一些缺陷,因此通常不建议这样实现)。
List(列表)
概述
Redis的List是链表数据结构的实现。虽然许多高级编程语言内置了链表的实现,如Java中的LinkedList
,但C语言并没有,因此Redis实现了自己的链表结构。Redis的List采用双向链表的方式,使得反向查找和遍历更加便利,但也带来了额外的内存开销。
常用命令
命令 | 描述 |
---|---|
RPUSH key value1 value2 ... | 在指定列表的尾部添加一个或多个元素 |
LPUSH key value1 value2 ... | 在指定列表的头部添加一个或多个元素 |
LSET key index value | 设置指定列表索引的位置的值 |
LPOP key | 移除并获取指定列表的第一个元素 |
RPOP key | 移除并获取指定列表的最后一个元素 |
LLEN key | 获取列表元素的数量 |
LRANGE key start end | 获取列表中指定范围的元素 |
更多Redis List命令及详细使用指南,请查看Redis官网。
基本操作示例
通过RPUSH/LPOP
或LPUSH/RPOP
实现队列:
> RPUSH myList value1
(integer) 1
> RPUSH myList value2 value3
(integer) 3
> LPOP myList
"value1"
> LRANGE myList 0 1
1) "value2"
2) "value3"
应用场景
信息流展示
- 示例:最新文章、动态更新。
- 相关命令:
LPUSH
、LRANGE
。
消息队列
尽管Redis List可用于实现消息队列,但功能较为简单且存在缺陷,不建议使用。相较之下,Redis 5.0新加入的Stream
结构更适合用于这种场景。
Hash(哈希)
概述
Redis中的Hash是一个String类型的field-value(键值对)映射表,尤其适用于存储对象,在后续操作中可以直接修改对象某些字段的值。Hash类似于JDK1.8之前的HashMap
,但Redis的Hash经过了多次优化,性能表现更好。
常用命令
命令 | 描述 |
---|---|
HSET key field value | 设置指定哈希表中指定字段的值 |
HSETNX key field value | 仅在字段不存在时设置其值 |
HMSET key field1 value1 field2 value2 ... | 同时设置多个field-value对 |
HGET key field | 获取指定哈希表中指定字段的值 |
HMGET key field1 field2 ... | 获取指定字段的值 |
HGETALL key | 获取指定哈希表中所有键值对 |
HEXISTS key field | 检查指定字段是否存在 |
HDEL key field1 field2 ... | 删除一个或多个字段 |
HLEN key | 获取字段数量 |
更多Redis Hash命令和详细使用指南,请查看Redis官网。
基本操作示例
> HMSET userInfoKey name "guide" description "dev" age "24"
OK
> HEXISTS userInfoKey name
(integer) 1
> HGET userInfoKey name
"guide"
> HGET userInfoKey age
"24"
> HGETALL userInfoKey
1) "name"
2) "guide"
3) "description"
4) "dev"
5) "age"
6) "24"
> HSET userInfoKey name "GuideGeGe"
> HGET userInfoKey name
"GuideGeGe"
应用场景
对象数据存储
- 示例:用户信息、商品信息、文章信息、购物车信息。
- 相关命令:
HSET
、HMSET
、HGET
、HMGET
。
Set(集合)
概述
Redis中的Set是一种无序集合,集合中的元素是唯一的,类似Java中的HashSet
。当需要存储列表数据且不希望有重复数据时,Set是一个理想选择。Set提供了判断元素是否存在的接口,这是List无法提供的特性。
通过Set可以轻松实现交集、并集和差集等操作。例如,可以将用户的所有关注者和粉丝存储在不同集合中,轻松获取共同关注和共同粉丝。
常用命令
命令 | 描述 |
---|---|
SADD key member1 member2 ... | 向指定集合添加一个或多个元素 |
SMEMBERS key | 获取集合中的所有元素 |
SCARD key | 获取集合的元素数量 |
SISMEMBER key member | 判断元素是否在集合中 |
SINTER key1 key2 ... | 获取集合的交集 |
SUNION key1 key2 ... | 获取集合的并集 |
SDIFF key1 key2 ... | 获取集合的差集 |
SPOP key count | 随机移除并获取集合中的元素 |
SRANDMEMBER key count | 随机获取集合中指定数量的元素 |
更多Redis Set命令和详细使用指南,请查看Redis官网。
基本操作示例
> SADD mySet value1 value2
(integer) 2
> SADD mySet value1
(integer) 0
> SMEMBERS mySet
1) "value1"
2) "value2"
> SCARD mySet
(integer) 2
> SISMEMBER mySet value1
(integer) 1
应用场景
非重复数据存放
- 示例:网站UV统计、文章点赞、动态点赞等场景。
- 相关命令:
SCARD
。
集合之间的交集、并集和差集
- 示例:共同好友、共同关注、好友推荐。
- 相关命令:
SINTER
、SUNION
、SDIFF
。
Sorted Set(有序集合)
概述
有序集合与Set类似,但增加了一个权重参数score
,使得集合中的元素能够根据score
进行排序,并可以通过score
的范围获取元素列表。它类似于Java中的HashMap
和TreeSet
的结合体。
常用命令
命令 | 描述 |
---|---|
ZADD key score1 member1 score2 member2 ... | 向指定有序集合添加元素 |
ZCARD key | 获取有序集合的元素数量 |
ZSCORE key member | 获取指定元素的score值 |
ZINTERSTORE destination numkeys key1 key2 ... | 求交集并存储 |
ZUNIONSTORE destination numkeys key1 key2 ... | 求并集并存储 |
ZDIFF destination numkeys key1 key2 ... | 求差集并存储 |
ZRANGE key start end | 获取指定范围的元素 |
ZREVRANGE key start end | 获取指定范围的元素(逆序) |
更多Redis Sorted Set命令和详细使用指南,请查看Redis官网。
基本操作示例
> ZADD myZset 2.0 value1 1.0 value2
(integer) 2
> ZCARD myZset
2
> ZSCORE myZset value1
2.0
> ZRANGE myZset 0 1
1) "value2"
2) "value1"
应用场景
根据权重排序的随机获取场合
- 示例:排行榜功能,如直播间礼物排行榜、游戏段位排行榜等。
- 相关命令:
ZRANGE
、ZREVRANGE
、ZREVRANK
。
需要存储优先级或重要程度的场景
- 示例:优先级任务队列。
- 相关命令:
ZRANGE
、ZREVRANGE
、ZREVRANK
。
参考资料
[1] Redis Data Structures: https://redis.com/redis-enterprise/data-structures/
[2] Redis Data Types Tutorial: https://redis.io/docs/manual/data-types/data-types-tutorial/