Redis中数据类型详解
String 字符串
特性:
- Redis最基础数据类型,二进制安全(可存储文本、图片、视频等二进制数据)。
- 支持多种操作:设置/获取值(SET/Get)、自增自减、追加内容、范围读取等。
- 单个String最大容量512MB。
底层实现:
底层并非单一结构,而是根据值类型和长度 动态选择高校存储方式。核心依赖:SDS(Simple Dynamic String,简单动态字符串)结构:
- SDS结构:替代C语言原生的字符串(Char*),优化后 解决了C字符串”长度O(n),缓冲区溢出。无法存储空字符(\0因为字符串以\0结束) 等问题。SDS结构:
- len:已使用字节数(获取长度O(1));
- free:未使用字节数(减少内存分配次数);
- buf[]:实际存储数据的字节数组(二进制安全,允许包含\0)
- 存储优化:
- 当值为 **整数且范围在[0,264-1]**时,Redis会将其转为long类型存储(避免SDS额外开销)。
- 当值为短字符串(如长度<44字节)时,SDS会与Redis对象头(redisObject)紧凑存储(减少内存碎片);
- 当值为长字符串(>44字节),会单独为其分配内存存储SDS,避免对象头过大。
Hash(哈希)
核心特性:
- 类似Java中的hashMap,存储键值对集合,适合表示“对象”。
- 支持单独操作某个 元素field(HSET/HGET)、批量操作(HMSET/HMGET)、删除field(HDEL)、判断field是否存在(Hexists)等。
- 单个Hash最多可存储232-1个键值对。
底层实现:
Hash底层根据Field数量和value大小,动态选择不同结构存储(两种结构)。
- zipList(压缩列表):
- 场景:field数量少(默认<512个),且每个field/value长度短(默认<64字节)。
- 特点:连续内存存储的双向量表,将多个field-value紧凑排序(减少内存碎片,查询效率)。通过“压缩”冗余元数据(如指针)降低内存占用。
- hashtable(哈希表):
- 场景:当field数量多或field/value长度长(超过上述阈值)。
- 特点:与hashMap类似,基于“数组+链表”实现(Redis6.0后引入“渐进式hash优化)。
- 数组 ht_table:存储哈希桶,每个桶对应一个链表(解决哈希冲突);
- 渐进式rehash:当哈希扩容/缩容时,不一次性将所有数据“搬迁”,而是分批迁移(避免但线程阻塞,保证服务可用)。
List(列表)
核心特性:
- 有序、可重复的元素集合,支持双向访问(头/尾 插入/删除 效率极高)。
- 核心操作:头部/尾部 插入(L/R PUSH)、头部/尾部 删除(L/R POP)、范围获取(LRANGE)等。
- 单个List最多存储232-1个元素。
底层实现:
List的底层在Redis.3.2前后由重大更新:当前默认:
- quick list(快速列表):
- 目的:结合ziplist(压缩列表)的“内存紧凑”和linkedList(双向链表)的高效查询插入删除优势。
- 特点:
- 外层是一个双向链表(每个节点是一个zipList);
- 内层每个ziplist存储多个元素(默认最大长度8192字节);
- 优势:即减少内存碎片(zipList紧凑存储),又比米娜长列表下ziplist遍历低效的问题(双向链表的高效查询)。
- 旧版本:
- 元素少且短 - ziplist
- 元素多且长 - linkedList(纯双向链表,每个节点单独分配内存,内存碎片多,已被quicklist替代)
Set集合
核心特性:
- 无序,不可重复的元素集合,支持并集、交集和差集等集合运算。
- 核心操作:添加元素(SADD),删除元素(SREM),判断元素存在(sismember),交集(Sinter),并集(SUNION),差集(SDIFF)等。
- 单个Set最多可存储232-1个元素。
底层实现:
Set的底层根据 元素类型动态选择。
- intset(整数集合):
- 场景:元素均为整数(int16、int32/int64等类型) 且数量少(默认512个)。
- 特点:连续内存存储的有序数组(按从小到大),支持二分查找(判断元素是否存在O(n)),且会自动升级存储类型(INT 16 - INT32)以容纳更大整数。
- hashTable(哈希表):
- 场景:元素包含非整数(如字符串),或整数数量超过阈值。
- 特点:与hash类型的hashtable底层一致,将Set元素作为key,value设置为NULL(利用了Hash表的key不能为空特性,实现Set去重)
Sorted Set(有序集合,简称ZSet)
特性:
- 兼具Set的(不可重复)和List(有序)的优点,每个元素关联一个分数(score),按score从小到大排序。
- 核心操作:添加元素(ZADD)、按分数范围获取(ZRANGEBYSCORE)、按排名获取(ZRANGE)、计算排名(ZRANK)、增加分数(ZINCRBY)等、
- 单个ZSet最多可存232-1个元素。
底层实现:
ZSet底层是"zipList + skipList(跳表)"的组合(两种结构协同工作)
- zipList(压缩列表):
- 场景:元素数量少(默认<128个),且每个元素member和分数score长度短(默认<64字节)。
- 特点:元素按照score排序,每个元素存储score+member,通过遍历实习啊ziplist范围查询(效率O(n))。
- skiplist + hashTable(跳表+哈希表)(元素过多或长时)、
- skip(跳表):负责按score排序和范围查找
- 特点:多层有序链表,底层是完整的有序链表。上层是“索引层”(每层索引跳过部分元素),通过索引快速定位(查询效率O(logn),类似平衡树 但实现更简单)
- hashtable(哈希表):负责“快速获取元素的score”。
- 特点:将member 作为key,score作为value,支持O(1)时间获取分数(避免跳表遍历查询score)。
- 协同逻辑:跳表保证 有序和范围查询,哈希表保证快速查分,两者共享元素数据(避免数据冗余)。
- skip(跳表):负责按score排序和范围查找
BitMap(位图)
核心特征:
- 本质是String类型的扩展,将String的每个字节拆分为8个二进制位(bit),通过微操作(如置位、清位、统计)实现高效存储。
- 核心操作:置位(SETBIT)、清位(GETBIT)、统计置位数量(BITCOUNT)、位运算(BITOP,如与/或/异或)。
- 优势:节省空间。
底层实现:
完全依赖String类型的SDS结构
- 每个bit对应SDS中buf[]数组的一个二进制位,bit位置(offset)对应“字节索引”+“位索引”(如offset=9 - 第1个字节的第一位,从0开始计数)
- 当offset查过当前SDS长度时,会自动扩容SDS(按字节对齐,避免部分位 无法操作)。
HyperLogLog(基数统计)
核心特性:
- 用于统计集合的基数(即不重复元素的个数),特点是内存占用极低且固定(无论集合大小,仅需要~12KB)。但存在0.81左右的误差(可接受的概率性统计)。
- 核心操作:添加元素(PFADD)、统计基数(PFCOUNT)、合并多个HyLogLog(PFMERGE)
- 优势:解决“大数据量技术统计”的内存问题(如统计1亿用户的UV,用Set需GB级内存,HyLogLog仅需12KB)。
底层实现:
基于HyperLogLog算法(LogLog优化后),核心是通过哈希值的前导 零个数 估算基数。
- 数据结构:包含一个稀疏矩阵(Sparse)和dense矩阵(密集),动态切换:
- 稀疏矩阵:元素少的时候,用“索引+前导零个数”的紧凑格式存储(节省内存);
- dense矩阵:元素多的时候,用固定大小的数组(默认16384个桶,每个桶6bit)存储,每个桶记录该桶对应的哈希值前导零最大个数。
- 算法逻辑:
- 对每个元素做哈希(得到64位哈希值)
- 取哈希值的 前14位置作为“桶索引”(对应16384个桶),后50位作为“数值”;
- 计算 数值 的前导零个数(+1),更新对应桶的最大值。
- 最终通过所有桶的最大值,代入公式 估算基数(修公正误差)。
GEO(地理信息)
核心特性
- 用于 存储和操作地理坐标数据(如经纬度),支持 “距离计算、范围查询” 等地理相关操作。
- 核心操作:添加地理坐标(GEOADD)、计算两点距离(GEODIST)、根据坐标范围查询(GEORADIUS)、根据元素查询坐标(GEOPOS)、删除元素(GEOREM)。
底层实现
基于 ZSet(有序集合) 实现,核心是 “将二维经纬度转为一维的 geohash 值”:
- 坐标编码:
- 将地球表面按经纬度划分为网格,每个网格对应一个 geohash 字符串(如 “wx4g0e”);
- 将 geohash 字符串转为 64 位整数(作为 ZSet 的 score),地理元素名称作为 ZSet 的 member;
- 由于 geohash 具有 “相邻网格的 hash 值相近” 的特性,ZSet 按 score 排序后,相邻的元素就是地理上相近的点。
- 操作映射:
- GEOADD → 编码经纬度为 score,执行 ZADD;
- GEODIST → 解码两个元素的 score 为经纬度,用 Haversine 公式计算球面距离;
- GEORADIUS → 计算目标坐标的 geohash 范围,执行 ZRANGEBYSCORE 筛选,再过滤真实距离。