Redis 数据结构详解(基于 6.0.10 版本)
Redis 作为高性能键值数据库,支持多种丰富的数据结构,每种结构都有独特的底层实现和适用场景。本文从底层编码、核心命令到应用场景,全面解析 Redis 的 8 种核心数据结构:String、List、Set、Hash、Zset、Bitmaps、HyperLogLogs 和 GEO。
Redis 对象模型(redisObject)
Redis 中所有值都会被包装为 redisObject 结构体,通过 type 标识数据类型,encoding 指定底层存储方式,实现灵活的内存优化:
1 2 3 4 5 6 7
| typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; int refcount; void *ptr; } robj;
|
核心数据结构详解
1. String(字符串)
特点:单键单值,可变字节数组,支持字符串、整数、二进制数据(最大 512MB)。
底层编码:
int:存储 64 位整数(如 set num 123)。
embstr:存储短字符串(≤44 字节),连续内存分配(redisObject + SDS 同块内存)。
raw:存储长字符串(>44 字节),独立内存分配(redisObject 和 SDS 分开)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 127.0.0.1:6379> set test_int 1 OK 127.0.0.1:6379> object encoding test_int "int" 127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz OK 127.0.0.1:6379> strlen test_raw (integer) 44 127.0.0.1:6379> object encoding test_raw "embstr" 127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz OK 127.0.0.1:6379> object encoding test_raw "raw" 127.0.0.1:6379> strlen test_raw (integer) 45
# 查看key的内部结构和编码等信息 >debug object k4 Value at:0x7ffc97c044f0 refcount:1 encoding:embstr serializedlength:3 lru:11351195 lru_seconds_idle:5363
|
embstr和raw两种编码的区别
embstr编码用于保存短字符串,与raw编码一样,都是使用redisObject结构和sdshdr结构来表示字符串对象,但是raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,两个对象在内存地址上是不连续的;而embstr编码则通过调用一次内存分配函数来分配一块连续的内存空间,空间中依次包含redisObject和sdshdr两个结构
底层实现:基于 SDS(简单动态字符串),记录长度(len)和容量(alloc),避免 C 字符串的缺陷(如 O (n) 长度计算):
1 2 3 4 5 6
| struct sdshdr8 { uint8_t len; uint8_t alloc; unsigned char flags; char buf[]; };
|
扩容:当字符串长度小于1M时,扩容是现有空间进行加倍;当字符串长度超过1M,扩容只会多扩1M的空间。且字符串最长为512M
核心命令:
- 设值:
set key value、setex key 3600 val(过期时间)、setnx key val(不存在时设值)。
- 取值:
get key、mget key1 key2(批量获取)。
- 修改:
append key suffix(追加)、setrange key 0 "new"(替换部分字符)。
- 计数:
incr key(自增)、decrby key 5(减 5)。