关注互联网应用及运维技术的个人博客

REDIS-String存储原理

数据模型

因为 Redis 是 KV 的数据库,它是通过 hashtable 实现的,所以每个键值对都会有一个 dictEntry,指向了 key 和 value 的指针,next 指向下一个 dictEntry。

typedef struct dictEntry {
void *key; /* key 关键字定义 */
union {
void *val; uint64_t u64; /* value 定义 */
int64_t s64; double d;
} v;
struct dictEntry *next; /* 指向下一个键值对节点 */
} dictEntry;

key 是字符串,但是 Redis 没有直接使用 C 的字符数组,而是存储在自定义的 SDS 中 value 既不是直接作为字符串存储,也不是直接存储在 SDS 中,而是存储在 redisObject 中

实际上五种常用的数据类型的任何一种,都是通过 redisObject 来存储的。

redisObject

typedef struct redisObject {
unsigned type:4; /* 对象的类型,包括:OBJ_STRING、OBJ_LIST、OBJ_HASH、OBJ_SET、OBJ_ZSET */
unsigned encoding:4; /* 具体的数据结构 */
unsigned lru:LRU_BITS; /* 24 位,对象最后一次被命令程序访问的时间,与内存回收有关 */
int refcount; /* 引用计数。当 refcount 为 0 的时候,表示该对象已经不被任何对象引用,则可以进行垃圾回收了
*/
void *ptr; /* 指向对象实际的数据结构 */
} robj;

可以使用 type 命令来查看对外的类型 127.0.0.1:6379> type nosum string

字符串类型的内部编码有三种:

int,存储 8 个字节的长整型(long,2^63-1) embstr, 代表 embstr 格式的 SDS(Simple Dynamic String 简单动态字符串),存储小于 44 个字节的字符串 raw,存储大于 44 个字节的字符串(3.2 版本之前是 39 字节)

为什么 Redis 要用 SDS 实现字符串

1、C语言本身没有字符串。只能用字符数组char[]实现
2、使用字符数组必须先给目标变量分配足够的空间,否则可能会溢出
3、如果要获取字符长度,必须遍历字符数组,时间复杂度是 O(n)
4、C 字符串长度的变更会对字符数组做内存重分配
5、通过从字符串开始到结尾碰到的第一个'\0'来标记字符串的结束,因此不能保存图片、音频、视频、压缩文件等二进制(bytes)保存的内容,二进制不安全

SDS的特点

1、不用担心内存溢出问题,如果需要会对 SDS 进行扩容
2、获取字符串长度时间复杂度为 O(1),因为定义了 len 属性
3、通过“空间预分配”( sdsMakeRoomFor)和“惰性空间释放”,防止多次重分配内存

int 和 embstr 转化为 raw

1、当 int 数据不再是整数或大小超过了 long 的范围,自动转化为 embstr
2、对于 embstr,由于其实现是只读的,因此在对 embstr 对象进行修改时,都会先转化为 raw 再进行修改
3、只要是修改 embstr 对象,修改后的对象一定是 raw 的,无论是否达到了 44 个
赞(0)
未经允许不得转载:飞天狒狒 » REDIS-String存储原理

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址