一、string
Redis字符串是可修改字符串,在内存中以字节数组形式存在。
下面是string在源码中的定义,SDS(Simple Dynamic String)
struct SDS<T> {
T capacity; // 数组容量
T len; // 数组长度
byte flags; // 特殊标识位,不理睬它
byte[] content; // 数组内容
}
Redis规定字符串的长度不超过512M。
Redis字符串的两种存储方式:
- 长度特别短,使用emb形式存储
- 长度超过44,使用raw形式存储
扩容策略
字符串长度小于1M之前,扩容采用加倍策略,保留100%的冗余空间。(从源码中可以看到是现有的数组长度len+设定的容量大小capacity)
字符串长度超过1M后,每次扩容只多分配1M大小的冗余空间。
sds sdscatlen(sds s, const void *t, size_t len) {
size_t curlen = sdslen(s); // 原字符串长度
// 按需调整空间,如果 capacity 不够容纳追加的内容,就会重新分配字节数组并复制原字符串的内容到新数组中
s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL; // 内存不足
memcpy(s+curlen, t, len); // 追加目标字符串的内容到字节数组中
sdssetlen(s, curlen+len); // 设置追加后的长度值
s[curlen+len] = '\0'; // 让字符串以\0 结尾,便于调试打印,还可以直接使用 glibc 的字符串函数进行操作
return s;
}
二、 list
Redis的列表常用来做异步队列使用。
右边进,左边出是队列。
rpush books python java golang
lpop books
右边进,右边出是栈。
rpush books python java golang
rpop books
三、hash
Redis 的字典相当于 Java 语言里面的 HashMap,它是无序字典。
hset books java "think in java"
hgetall books
Redis相比于Java的HashMap不同的是,采取了渐进式rehash,为的是不堵塞服务。
什么是渐进式rehash?
创建新的hashtable,同时保留旧的hashtable,并且通过定时任务将旧的hashtable中的key-value转移到新的hashtable,查询时,会同时查询新旧hashtable,等到完全转移完成,再将旧的删除掉。
这里思考一个问题?Java中的rehash,要怎么处理?不是渐进式的,那如何保证在rehash时进行查询,获取到正确的值?
四、set
Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。
set 结构可以用来存储活动中奖的用户 ID,因为有去重功能,可以保证同一个用户不会中奖两次
五、zset
底层实现?
zset类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。它的内部实现用的是一种叫做「跳跃列表」的数据结构。
参考文档
[1]: 天下无难试之Redis面试刁难大全
[2]: Redis 深度历险:核心原理与应用实践
[3]: 十二张图带你了解 Redis 的数据结构和对象系统