32. 你知道Redis的字符串是怎么实现的吗?

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 32. 你知道Redis的字符串是怎么实现的吗?

32. 你知道Redis的字符串是怎么实现的吗?


之前有人在找工作面试时在Redis相关问题上可栽了跟头。在面试前按常规套路准备了一下,比如 Redis 的常用5种数据结构,Redis持久化策略,Redis实现分布式锁,简单发布订阅等等都准备了,当时不知天高地厚以为十拿九稳了,可是万万没想到我终究还是在Redis的被问的第一个问题上翻船了~~

面试官 :看你简历上写了熟悉常用数据结构,都有哪些说说

本人 :常用有5种,string,list,set,zset,hash(内心很得意)

面试官 :那你说说都用过哪些数据结构

本人 :用的最多的是string,通常会把json字符串存进去

面试官 :那你知道Redis内部是怎么实现它的string的么?

本人 :呃~,我了解Redis是用C语言写的,至于具体实现就不清楚了~

到此一面卒~~~

有相同经历的朋友么?

回去后恶补了一下Redis有关原理性的知识点,恰好最近在最总结面试经历于是有了今天这篇文章。

Redis字符串的实现

Redis虽然是用C语言写的,但却没有直接用C语言的字符串,而是自己实现了一套字符串。目的就是为了提升速度,提升性能,可以看出Redis为了高性能也是煞费苦心。

Redis构建了一个叫做简单动态字符串(Simple Dynamic String),简称SDS

1.SDS 代码结构

struct sdshdr{
    //  记录已使用长度
    int len;
    // 记录空闲未使用的长度
    int free;
    // 字符数组
    char[] buf;
};

SDS ?什么鬼?可能对此陌生的朋友对这个名称有疑惑。只是个名词而已不必在意,我们要重点欣赏借鉴Redis的设计思路。下面画个图来说明,一目了然。

Redis的字符串也会遵守C语言的字符串的实现规则,即最后一个字符为空字符。然而这个空字符不会被计算在len里头。

2.SDS 动态扩展特点

SDS的最厉害最奇妙之处在于它的Dynamic。动态变化长度。举个例子

如上图所示刚开始s1 只有5个空闲位子,后面需要追加’ world’ 6个字符,很明显是不够的。那咋办?Redis会做以下三个操作:

计算出大小是否足够

开辟空间至满足所需大小

开辟与已使用大小len相同长度的空闲free空间(如果len < 1M)开辟1M长度的空闲free空间(如果len >= 1M)

看到这儿为止有没有朋友觉得这个实现跟Java的列表List实现有点类似呢?看完后面的会觉得更像了。

Redis字符串的性能优势

快速获取字符串长度

避免缓冲区溢出

降低空间分配次数提升内存使用效率

1.快速获取字符串长度

再看下上面的SDS结构体:

struct sdshdr{
    //  记录已使用长度
    int len;
    // 记录空闲未使用的长度
    int free;
    // 字符数组
    char[] buf;
};

由于在SDS里存了已使用字符长度len,所以当想获取字符串长度时直接返回len即可,时间复杂度为O(1)。如果使用C语言的字符串的话它的字符串长度获取函数时间复杂度为O(n),n为字符个数,因为他是从头到尾(到空字符’\0’)遍历相加。

2.避免缓冲区溢出

对一个C语言字符串进行strcat追加字符串的时候需要提前开辟需要的空间,如果不开辟空间的话可能会造成缓冲区溢出,而影响程序其他代码。如下图,有一个字符串s1=“hello” 和 字符串s2=“baby”,现在要执行strcat(s1,“world”),并且执行前未给s1开辟空间,所以造成了缓冲区溢出。

而对于Redis而言由于每次追加字符串时都会检查空间是否够用,所以不会存在缓冲区溢出问题。每次追加操作前都会做如下操作:

计算出大小是否足够

开辟空间至满足所需大小

3.降低空间分配次数提升内存使用效率

字符串的追加操作会涉及到内存分配问题,然而内存分配问题会牵扯内存划分算法以及系统调用所以如果频繁发生的话影响性能,所以对于性能至上的Redis来说这是万万不能忍受的。所以采取了以下两种优化措施

空间与分配

惰性空间回收

空间预分配

对于追加操作来说,Redis不仅会开辟空间至够用而且还会预分配未使用的空间(free)来用于下一次操作。至于未使用的空间(free)的大小则由修改后的字符串长度决定。

当修改后的字符串长度len < 1M,则会分配与len相同长度的未使用的空间(free)

当修改后的字符串长度len >= 1M,则会分配1M长度的未使用的空间(free)

有了这个预分配策略之后会减少内存分配次数,因为分配之前会检查已有的free空间是否够,如果够则不开辟了~

惰性空间回收

与上面情况相反,惰性空间回收适用于字符串缩减操作。比如有个字符串s1=“hello world”,对s1进行sdstrim(s1," world")操作,执行完该操作之后Redis不会立即回收减少的部分,而是会分配给下一个需要内存的程序。当然,Redis也提供了回收内存的api,可以自己手动调用来回收缩减部分的内存。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
8月前
|
存储 NoSQL 5G
redis优化编码之字符串
Redis数据结构之字符串
98 2
redis优化编码之字符串
|
8月前
|
XML JSON NoSQL
Redis的常用数据结构之字符串类型
Redis的常用数据结构之字符串类型
63 0
|
8月前
|
NoSQL 安全 Linux
Redis 字符串:SDS
Redis 字符串:SDS
85 0
|
5月前
|
存储 缓存 NoSQL
redis数据结构-字符串
redis数据结构-字符串
48 1
|
7月前
|
存储 NoSQL Redis
Redis系列学习文章分享---第十六篇(Redis原理1篇--Redis数据结构-动态字符串,insert,Dict,ZipList,QuickList,SkipList,RedisObject)
Redis系列学习文章分享---第十六篇(Redis原理1篇--Redis数据结构-动态字符串,insert,Dict,ZipList,QuickList,SkipList,RedisObject)
93 1
|
3月前
|
NoSQL Redis
Redis 字符串(String)
10月更文挑战第16天
57 4
|
4月前
|
存储 缓存 NoSQL
3)深度解密 Redis 的字符串
3)深度解密 Redis 的字符串
52 1
|
5月前
|
NoSQL 安全 Java
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
这篇文章深入探讨了Redis中的String数据类型,包括键操作的命令、String类型的命令使用,以及String在Redis中的内部数据结构实现。
Redis6入门到实战------ 三、常用五大数据类型(字符串 String)
|
5月前
|
C# 开发者 UED
WPF开发者必备秘籍:深度解析文件对话框使用技巧,打开与保存文件原来如此简单!
【8月更文挑战第31天】在WPF应用开发中,文件操作是常见需求。本文详细介绍了如何利用`Microsoft.Win32`命名空间下的`OpenFileDialog`和`SaveFileDialog`类来正确实现文件打开与保存功能。通过示例代码展示了如何设置文件过滤器、初始目录等属性,并使用对话框进行文件读写操作。正确使用文件对话框能显著提升用户体验,使应用更友好易用。
132 0
|
5月前
|
存储 NoSQL Redis
【Redis 探秘】SDS 简单动态字符串:揭秘 Redis 高效字符串处理的秘密武器!
【8月更文挑战第24天】Redis采用的简单动态字符串(SDS)是一种专为优化内存存储和字符串操作而设计的数据结构。相较于C语言的标准字符串,SDS改进了字符串长度计算、内存重分配及字符串比较等问题。其特性包括预分配冗余空间减少未来的内存重分配、显式存储长度以加快获取速度等。这些改进使Redis能更高效地管理字符串数据。例如,在Redis中,SDS被广泛应用于键值对的存储,显著提升了字符串操作的性能。了解SDS不仅对于深入理解Redis的工作原理至关重要,也是开发者技能树中的重要一环。
79 0