这里先列举一下 Redis 的数据结构,以及对应的底层实现。
Redis 提供了多种数据结构,每种结构都有其独特的应用场景和底层实现。以下是 Redis 的主要数据结构及其底层实现:
- 字符串(String)
- 底层实现:简单动态字符串(SDS)
- 特点:适用于存储单个值,如用户 session、缓存对象。
- 场景:大部分简单数据的缓存都是使用这个数据结构的
- 列表(List)
- 底层实现:有两种实现,ziplist,quicklist(链表)。这在面试中会是一个难点,但是大部分面试官如果没有更新自己的八股文知识的话,应该也不太知道,也不太会问。
- 特点:适用于存储有序元素,如消息队列、文章列表。
- 场景:例如说收藏夹中的收藏列表,好友列表等,有些公司还会用作消息队列。List 还有一个使用场景,就是可以用来实现滑动窗口算法,达成限流的效果。
- 集合(Set)
- 底层实现:hashtable 和 intset
- 特点:适用于存储无序且唯一元素,如标签、用户关注列表。
- 场景:很多都是利用集合求差集、并集或者交集。比如说共同好友、共同关注的人这种社交的应用。
- 有序集合(Sorted Set)
- 底层实现:skiplist(跳表) 和 ziplist
- 特点:适用于存储有序且唯一元素,如排行榜、时间线。
- 场景:最典型的就是各种榜单了,比如说游戏里面的分数排行,或者社交平台的各种榜单,电商平台的各种榜单。
- 哈希(Hash)
- 底层实现: ziplist 或 hashtable (取决于元素数量和大小)
- 特点:适用于存储对象属性,如用户信息、配置项。
- 场景:适合存储有很多属性的对象,比如说在用户系统中,使用 Redis 哈希存储用户信息,键为 user:userid,字段为 name、email 等,HSET 设置属性,HGET 获取属性,读写都可以只操作部分数据,减少数据冗余。
- 地理空间(Geospatial)
- 底层实现:有序集合(Sorted Set)的扩展
- 特点:适用于存储地理空间数据,如附近的人、位置服务。
- 场景:计算附近的人
- 位图(Bitmap)
- 底层实现:字符串(String)的位操作
- 特点:适用于存储布尔值,如用户签到、活跃用户统计。
- 场景:在社交平台中,使用 Redis 位图记录用户每日签到情况,键为 signin:userid,SETBIT 设置签到,GETBIT 查询签到,节省存储空间。
- HyperLogLog
- 底层实现:HyperLogLog 算法
- 特点:适用于统计大量数据的基数,如 UV 统计。
- 场景:UV 统计,在网站分析系统中,使用 Redis HyperLogLog 统计每日 UV,键为 uv:date,PFADD 添加访问记录,PFCOUNT 获取 UV 数,高效处理大数据统计。
- 流(Stream)
- 底层实现:Rax 树和链表
- 特点:适用于消息队列和日志收集,支持持久化。
- 场景:在监控系统 中,使用 Redis 流收集日志信息,键为 log_stream,XADD 添加日志,XREAD 读取日志,支持持久化和高吞吐量。
我加粗的五种字符串,列表,集合,有序集合和哈希是一定要记住的,剩下的几种你要是在项目里面用过,就要记住,并且在回答的时候引导到你用的案例上。
而后可以考虑在面试中进一步回答选择 Redis 数据结构的基本原则:
- 功能性:也就是你选择的 Redis 数据结构至少能支持你所需要的业务场景,能够解决你的业务问题
- 性能:内存要少,读写操作要快
- 底层实现的潜在问题:要进一步评估在你的业务数据特性下,你使用的数据结构对应的底层结构究竟是什么,防止出现 intset 那种升级问题,或者 ziplist 连锁更新的问题
- 扩展性:典型的就是在考虑存储一个大 JSON 串还是使用 Hash 结构,如果考虑到未来存在单字段的读写情况,那么使用扩展性的问题