Redis SDS 详解

本文介绍了Redis中的SimpleDynamicString(SDS)数据结构,其具有O(1)获取长度、动态扩容、二进制安全等特性,通过内存预分配和惰性空间释放提升性能,以及优化技巧如合理分配空间和避免频繁修改大字符串。
摘要由CSDN通过智能技术生成

我们都知道Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。

不过Redis没有直接使用C语言中的字符串,因为C语言字符串存在很多问题:

  • 获取字符串长度的需要通过运算
  • 非二进制安全
  • 不可修改
    Redis构建了一种新的字符串结构,称为简单动态字符串(Simple Dynamic String),简称SDS

SDS 的结构:

SDS 是 Redis 用于表示字符串的底层数据结构。它的结构由以下部分组成:

  1. buf:存储字符串内容的区域,是一个字节数组,用于保存实际的字符串数据。
  2. alloc: 已经申请的区域的长度
  3. len:记录字符串的长度,即 buf 中实际存储的字符数,不包括末尾的空字符 \0。
struct __attribute__((__packed__)) sdshdr8 {
 uint8_t len; /*buf 中已经报错的字符串字节数,不含结束标识*/
 uint8_t alloc;/*buf 中申请的总字节数,不含结束标识*/
 unsigned char flags;/*SDS的头类型,用来控制头部大小*/
 char buf [];
}

/*头类型*/
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

image.png

SDS的特性和优势:

  1. 获取字符串长度的时间复杂度为O(1)
  2. 动态扩容:SDS 允许字符串长度的动态增长,并且能够动态地调整内存空间,以避免频繁的内存分配和复制操作,提高了性能。
  3. 二进制安全:SDS 可以存储任意二进制数据,不受空字符 \0 的限制,因此可以存储图片、压缩数据等任意类型的数据。
  4. 预分配和惰性空间释放:SDS 采用预分配的策略,提前分配一定的空间以减少频繁的内存分配操作。同时,它使用惰性空间释放策略,在缩短字符串长度时并不立即释放多余的空间,而是保留一定的额外空间,以备后续可能的扩展使用。
  5. 修改时复制(Copy on Write):SDS 在进行修改操作时,会先进行复制,以确保修改操作不会影响到其他引用该字符串的地方,保证数据的安全性。

动态扩容过程

假如我们要给"test"追加一个"ordersheet"

  1. 首先,需要计算追加的字符串长度,即 “ordersheet” 的长度为 10。
  2. SDS 检查当前剩余的空间是否能容纳新的字符串,发现空间不够以容纳所有字符。
  3. 触发扩容操作,按照一定规则申请新的内存空间
  4. 将原始的字符串 “test” 复制到新的更大空间,并在末尾追加 “ordersheet\0”。
  5. 更新字符串的长度为 14(“test” 的长度 4 + “ordersheet” 的长度 10)。
  6. 调整空闲空间,确保在将来的操作中有足够的预留空间

申请新内存空间规则:

  • 如果新字符串小于1M,则新空间为扩展后字符串长度的两倍+1;
  • 如果新字符串大于1M,则新空间为扩展后字符串长度+1M+1。称为内存预分配。

SDS 的优势与应用:

  1. 高效性能:SDS 通过动态扩容和预分配机制,更高效地处理内存空间,减少了频繁的内存操作,提升了性能。
  2. 安全性和灵活性:SDS 的二进制安全性保证了可以存储和处理任意类型的数据,而不受到传统 C 字符串的限制。其丰富的操作函数提供了对字符串进行各种操作的灵活性

SDS 的优化技巧

  1. 合理使用空间预分配: 在创建 SDS 字符串时,根据实际需求预先分配足够的空间。不要过度分配,但也不要频繁进行小额的扩容操作,这可以减少不必要的内存操作。
  2. 避免频繁修改大型字符串: 大型 SDS 字符串的修改可能触发大量的内存重新分配和数据复制,这会影响性能。尽量减少对大型 SDS 字符串的频繁修改操作,考虑在实际需要时一次性完成操作。
  3. 利用惰性空间释放: SDS 采用惰性空间释放策略,在缩短字符串长度时,并不立即释放多余的空间,而是保留一定的额外空间。这个额外空间在之后可能的扩展使用中能够提供更好的性能。
  4. 选择合适的 API 函数: 在 Redis 的 API 函数中,有许多针对 SDS 字符串的操作函数。选择合适的函数可以减少不必要的复制或内存分配操作,提高效率。
  5. 避免频繁的字符串连接操作: 避免使用频繁的字符串连接操作,特别是对大量数据进行连接操作,这可能导致大量的内存重新分配和数据复制。
  6. 利用合并命令和 Pipeline: 如果需要进行大量的字符串操作,可以利用 Redis 的 Pipeline 特性或合并多个操作命令,以减少网络开销和提高性能。
  7. 内存管理: 在需要释放 SDS 字符串时,确保调用合适的释放函数以释放 SDS 所占用的内存,以免造成内存泄漏。
  8. 监控和优化: 使用 Redis 提供的监控工具或命令,监视 SDS 字符串的使用情况,并针对性地进行优化调整,比如合理设置过期时间,控制字符串的长度等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值