Redis 是一个高性能的键值存储系统,支持多种数据类型。每种数据类型都有其特定的使用场景和底层实现原理。以下是 Redis 支持的几种主要数据类型及其深入讲解:
数据结构 | 用途 | 原理 | 常用命令示例 |
---|---|---|---|
字符串(String) | 存储简单键值对,如用户信息、配置项、计数器等。 | 动态字符串(SDS),支持动态调整长度。 | SET key value 、GET key 、INCR key |
哈希(Hash) | 存储对象或结构化数据,如用户信息、商品信息等。 | 使用 ziplist 或 hashtable 存储键值对。 | HSET key field value 、HGET key field 、HGETALL key |
列表(List) | 实现队列、栈等数据结构,适合存储有序数据。 | 使用 ziplist 或 linkedlist 存储双向链表。 | LPUSH key value 、RPUSH key value 、LPOP key 、RPOP key |
集合(Set) | 存储不重复元素,适合去重、交集、并集等操作。 | 使用 intset 或 hashtable 存储唯一元素。 | SADD key member 、SREM key member 、SINTER key1 key2 |
有序集合(Sorted Set) | 存储有序且不重复的元素,适合排行榜、优先级队列等场景。 | 使用跳跃表和哈希表实现,支持快速范围查询和排序。 | ZADD key score member 、ZRANGE key start stop 、ZREM key member |
位图(Bitmap) | 存储二进制位,适合实现布隆过滤器、用户签到等功能。 | 基于字符串实现,每个位只能是 0 或 1。 | SETBIT key offset value 、GETBIT key offset 、BITCOUNT key |
地理空间索引(Geospatial Index) | 存储地理位置信息,支持范围查询、距离计算等操作。 | 使用有序集合存储,地理位置信息映射到分数。 | GEOADD key longitude latitude member 、GEODIST key member1 member2 |
HyperLogLog | 用于基数统计(去重计数),适合统计独立访客数(UV)等场景。 | 使用概率算法估算基数,误差率约为 0.81%。 | PFADD key element 、PFCOUNT key 、PFMERGE destkey sourcekey1 sourcekey2 |
1. 字符串(String)
(1)定义
- 字符串是 Redis 最基本的数据类型,可以存储文本、数字或二进制数据。
- 最大长度:512 MB。
(2)使用场景
- 缓存数据(如 HTML 片段、JSON 数据)。
- 计数器(如用户访问量)。
- 分布式锁。
(3)底层实现
- SDS(Simple Dynamic String):
- Redis 使用 SDS 作为字符串的底层实现。
- SDS 的结构如下:
struct sdshdr { int len; // 字符串长度 int free; // 未使用的空间 char buf[]; // 字符串内容 };
- 优点:
- O(1) 时间复杂度获取字符串长度。
- 自动扩容,减少内存分配次数。
- 二进制安全,可以存储任意数据。
(4)常用命令
SET key value
:设置键值对。GET key
:获取键对应的值。INCR key
:将键的值增加 1。
2. 列表(List)
(1)定义
- 列表是一个有序的字符串集合,支持在头部或尾部插入和删除元素。
- 最大长度:2^32 - 1 个元素。
(2)使用场景
- 消息队列。
- 最新消息列表(如微博时间线)。
(3)底层实现
- 双向链表(LinkedList):
- 当列表元素较少时,Redis 使用双向链表存储。
- 每个节点包含前驱指针、后继指针和值。
- 压缩列表(Ziplist):
- 当列表元素较少且每个元素较小时,Redis 使用压缩列表存储。
- 压缩列表是一块连续的内存,存储多个元素,节省内存。
(4)常用命令
LPUSH key value
:在列表头部插入元素。RPUSH key value
:在列表尾部插入元素。LPOP key
:从列表头部删除元素。RPOP key
:从列表尾部删除元素。
3. 集合(Set)
(1)定义
- 集合是一个无序的字符串集合,元素唯一。
- 最大长度:2^32 - 1 个元素。
(2)使用场景
- 去重(如用户标签)。
- 交集、并集、差集运算(如共同好友)。
(3)底层实现
- 哈希表(Hashtable):
- 当集合元素较多时,Redis 使用哈希表存储。
- 哈希表的键是集合元素,值为 NULL。
- 整数集合(Intset):
- 当集合元素较少且均为整数时,Redis 使用整数集合存储。
- 整数集合是一块连续的内存,存储多个整数,节省内存。
(4)常用命令
SADD key member
:向集合添加元素。SREM key member
:从集合删除元素。SINTER key1 key2
:计算两个集合的交集。
4. 有序集合(Sorted Set)
(1)定义
- 有序集合是一个有序的字符串集合,每个元素关联一个分数(Score),按分数排序。
- 最大长度:2^32 - 1 个元素。
(2)使用场景
- 排行榜(如游戏积分榜)。
- 范围查询(如按时间范围查询日志)。
(3)底层实现
- 跳跃表(Skip List):
- 当有序集合元素较多时,Redis 使用跳跃表存储。
- 跳跃表是一种多层链表,支持快速查找、插入和删除。
- 压缩列表(Ziplist):
- 当有序集合元素较少且每个元素较小时,Redis 使用压缩列表存储。
(4)常用命令
ZADD key score member
:向有序集合添加元素。ZREM key member
:从有序集合删除元素。ZRANGE key start stop
:按分数范围查询元素。
5. 哈希(Hash)
(1)定义
- 哈希是一个键值对集合,适合存储对象。
- 最大长度:2^32 - 1 个键值对。
(2)使用场景
- 存储对象(如用户信息)。
- 缓存结构化数据。
(3)底层实现
- 哈希表(Hashtable):
- 当哈希元素较多时,Redis 使用哈希表存储。
- 压缩列表(Ziplist):
- 当哈希元素较少且每个键值对较小时,Redis 使用压缩列表存储。
(4)常用命令
HSET key field value
:设置哈希字段的值。HGET key field
:获取哈希字段的值。HGETALL key
:获取哈希的所有字段和值。
6. 位图(Bitmap)
(1)定义
- 位图是一种特殊的字符串,支持位级操作。
- 最大长度:512 MB。
(2)使用场景
- 用户签到记录。
- 布隆过滤器。
(3)底层实现
- 字符串:位图实际上是字符串的二进制表示。
(4)常用命令
SETBIT key offset value
:设置位的值。GETBIT key offset
:获取位的值。BITCOUNT key
:统计位图中 1 的数量。
7. HyperLogLog
(1)定义
- HyperLogLog 是一种概率数据结构,用于统计唯一元素的数量。
- 最大长度:12 KB。
(2)使用场景
- 统计独立用户数(如 UV)。
(3)底层实现
- 概率算法:HyperLogLog 使用概率算法估算基数,误差率约为 0.81%。
(4)常用命令
PFADD key element
:向 HyperLogLog 添加元素。PFCOUNT key
:统计 HyperLogLog 的基数。
8. 地理空间(Geospatial)
(1)定义
- 地理空间用于存储地理位置信息(如经纬度)。
- 最大长度:2^32 - 1 个元素。
(2)使用场景
- 附近的人。
- 地理位置查询。
(3)底层实现
- 有序集合:地理空间数据实际上是有序集合的一种特殊形式。
(4)常用命令
GEOADD key longitude latitude member
:添加地理位置。GEODIST key member1 member2
:计算两个位置的距离。GEORADIUS key longitude latitude radius
:查询指定半径内的位置。
9. 总结
- Redis 数据类型:字符串、列表、集合、有序集合、哈希、位图、HyperLogLog、地理空间。
- 底层实现:SDS、双向链表、压缩列表、哈希表、跳跃表等。
- 适用场景:缓存、计数器、消息队列、排行榜、去重、地理位置等。