讲透系列-Redis-你真的了解String吗?

100 阅读4分钟

1、使用Docker下载镜像,并且运行起来 docker run -d -p 6379:6379 redis:latest

Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
1392a3a0fd93: Pull complete
59e22667830b: Pull complete
243804704905: Pull complete
4f4fb700ef54: Pull complete
06a6d6eb795d: Pull complete
3f8c6beabb1f: Pull complete
0d70579159bb: Pull complete
Digest: sha256:b0efb06f6b4d8c1e2fd1b7c1e89e178d787b432b7b09286b4e7ea3dcdbac777a
Status: Downloaded newer image for redis:latest
f8e7949735efee0751193c7d4595652ba0f7a2b7d0925e5aeef7f49041124dd2

2、在容器列表中,可以看得到 image.png

3、进入容器列表 docker exec -it myredis redis-cli

string 字符串

1、介绍Redis的String的定义,数据结构是什么,并且分析为什么不用C语言的字符串,而是要自己造一个SDS?

因为C语言里面,字符串的标准格式,是以Null结尾,(0x\0)作为结束符,而且函数 strlen()的时间复杂度是O(n),所以就不合适。

数组容量 alloc,数组所分配的长度 数组长度len,实际用的多少 数组内容Buf

image.png

“长度分段策略”是 Redis SDS(Simple Dynamic String)库在处理字符串时,为了内存优化而采用的一种精巧的设计。它的核心思想是:根据字符串的实际长度,选择不同大小的头部结构体来存储元数据,从而尽可能地节省内存空间。

2、 为什么需要长度分段?

在 Redis 这样的内存数据库中,数据存储的效率至关重要。如果所有字符串都使用一个固定大小的头部来存储元数据,就会产生以下问题:

  • 内存浪费:如果一个固定头部为 17 字节(sdshdr64)的字符串对象只存储了“Hello”这 5 个字符,那么就会有大量的空间被浪费。
  • 不灵活:如果一个头部太小(例如只能存储 255 个字符),那么就无法存储更长的字符串。

为了解决这个问题,SDS 库设计了五种不同的头部结构体,每一种都对应一个长度区间,这就是所谓的“长度分段”。

image.png

3、字符串的扩容策略,惰性删除(不处理) (1) 字符串长度少于1M,加倍扩容。 (2)字符串长度大于1M,扩容时,每次就会新增1M,直到512M为止。

sdscatlen是扩容函数 image.png

sdsMakeRoomFor 在进行扩容的时候,字符串长度大于1M,扩容时,每次就会新增1M,直到512M为止。 image.png

这里定义了一个常量值,也就是1M空间 image.png

4、存储方式(embstr和raw) embstr:字符串长度小于44字节 raw:字符串长度大于44字节

docker run -d --name my-redis -p 6379:6379 -v /c/Redis/redis.conf:/usr/local/etc/redis/redis.conf redis:latest redis-server /usr/local/etc/redis/redis.conf
127.0.0.1:6379> set key1 1234
127.0.0.1:6379> debug object key1
Value at:0x7aaff8149058 refcount:1 encoding:int serializedlength:3 lru:10096795 lru_seconds_idle:5

127.0.0.1:6379> set key2 12345555555555555555555555555555555555555555555555555555 
127.0.0.1:6379> debug object key2
Value at:0x7aaff8149040 refcount:1 encoding:raw serializedlength:19 lru:10096829 lru_seconds_idle:13

127.0.0.1:6379> set key3 1234sbc-9-=
127.0.0.1:6379> debug object key3
Value at:0x7aaff801bc30 refcount:1 encoding:embstr serializedlength:12 lru:10096869 lru_seconds_idle:5

我们可以看到,长度不一样,类型,不一样。对应的encoding也不一样:

image.png

embstrraw 是 Redis 优化内存和性能的两种策略。

  • embstr 是一种内存优化的编码,通过一次性分配连续内存来存储小字符串,减少了内存碎片,提高了访问速度。但它的缺点是不可修改,一旦修改就需要转换为 raw
  • raw 是一种通用的编码,用于存储大字符串。它的内存分配和释放开销更大,但可以灵活地进行修改操作。