Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >万丈高楼平地起-redis基础数据结构string

万丈高楼平地起-redis基础数据结构string

作者头像
热心的大肚皮
发布于 2023-02-28 05:57:04
发布于 2023-02-28 05:57:04
21500
代码可运行
举报
运行总次数:0
代码可运行

大家好,我是热心的大肚皮,皮哥。我们又多了一个系列-redis。

redis是互联网技术架构在存储系统中使用最多的中间件,也是面试必问的技能之一。希望通过自己实战经验,能帮助更多后端开发者更深更快的掌握redis。不多说了,开整。

什么是redis?

redis是"Remote Dictionary Service"(远程字典服务)的首字母缩写。具有超高的性能、完美的文档、简洁易懂的源码和丰富的客户端在开源中间件领域中广受好评。

redis有几种数据结构呢?

redis有以下5种数据结构。

  • string(字符串)
  • list(列表)
  • hash(字典)
  • set(集合)
  • zset(有序集合)

今天我们先通关第一种string。

string

数据结构

redis中的字符串也叫做"SDS",也就是Simple Dynamic String。是一个带长度信息的字节数组。如下图。

直接上源码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 对象属性
struct SDS<T> {
  // 数组容量
  T capacity; 
  // 数组长度
  T len;     
  // 特殊标志位,暂时不用管
  byte flags; 
  //数组内容
  byte[] content; 
}

//追加 SDS 字符串
sds sdscatlen(sds s, const void *t, size_t len){
  // 原字符串的长度
  size_t curlen = sdslen(s);
  //按需调整空间,如果capacity不够容纳追加d的内容,就会从新分配
  //字节数据,并将原内容复制到新数组中
  s = sdsMakeRoomFor(s, len);
  //内存不足
  if(s == NULL) return NULL;
  //追加目标字符串内容到字节数组
  memcpy(s+curlen, t, len);
  //设置追加后的字符串长度
  sdssetlen(s, curlen + len);
  //让字符串以\0结尾,便于调试打印。
  s[curlen+len]='\0';
  return s;
}

/*空间调整,注意只是调整空间,后续自己组装字符串*/
sds sdsMakeRoomFor(sds s, size_t addlen) {
    void *sh, *newsh;
    // 当前剩下的空间
    size_t avail = sdsavail(s);
    size_t len, newlen;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;
    int hdrlen;
    /* 空间足够 */
    if (avail >= addlen) return s;
    // 长度
    len = sdslen(s);
    // 真正的数据体
    sh = (char*)s-sdsHdrSize(oldtype);
    // 新长度
    newlen = (len+addlen);
    // < 1M 2倍扩容
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;
    // > 1M 扩容1M
    else
        newlen += SDS_MAX_PREALLOC;
    // 获取sds 结构类型
    type = sdsReqType(newlen);
    // type5 默认转成 type8
    if (type == SDS_TYPE_5) type = SDS_TYPE_8;
    // 头长度
    hdrlen = sdsHdrSize(type);
    if (oldtype==type) { // 长度够用 并且 数据结构不变
        newsh = s_realloc(sh, hdrlen+newlen+1);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+hdrlen;
    } else {
        // 重新申请内存
        newsh = s_malloc(hdrlen+newlen+1);
        if (newsh == NULL) return NULL;
        memcpy((char*)newsh+hdrlen, s, len+1);
        s_free(sh);
        s = (char*)newsh+hdrlen;
        s[-1] = type;
        sdssetlen(s, len);
    }
    sdssetalloc(s, newlen);
    return s;
}

细心的小伙伴有没有发现,为什么capacity与len 不用int 而是 T呢?原因是当字符串比较短时,capacity与len可以用short 或者byte来表示,也是为了对内存极致的优化。

扩容规则

每次创建时capacity与len一样大,点那个字符串长度小于1MB时,每次扩容都是加倍现有的空间,如果长度大于1MB,则每次只会扩容1MB的空间,注意字符串在这里最大长度为512MB

存储方式

分为embstr与raw两种。当字符串超过44字节,则采用raw存储。那么为什么是44字节呢?首先我们要了解,在redis中,每一个对象都有一个对象头结构。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct RedisObject {
  //不同的对象都有不同的类型 4bits
  int4 type;
  //同一个类型会有不同的存储形式 4bits
  int4 encoding;
  //对象d的lru信息,使用24bits
  int24 lru;
  //引用计数,为0时则对象会被销毁 4bytes
  int32 refcount;
  //指向对象内容的具体存储位置,8bytes
  void *ptr;
}

一个字符串在内存的结构如下图。

我们可以看出来对象头RedisObject需要16个字节的空间。er内存分配器jemalloc、tcmalloc分配内存大小都是2/4/8/16/32/64 字节,而字符串不算内容最少需要19个字节,redis的作者考虑到性能,将64字节作为分界线,这样计算,也就是当字符串长度等于 64-19=45,但是字符串又是以null作为结尾,所以边界则是44字节。具体的存储方式为连续内存与,非连续内存,如下图。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿日常笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
透过Redis源码探究字符串的实现
最近在通过 Redis 学 C 语言,不得不说,Redis的代码写的真的工整。这篇文章会比较全面的深入的讲解了Redis数据结构字符串的源码实现,希望大家能够从中学到点东西。
luozhiyun
2022/06/19
2150
透过Redis源码探究字符串的实现
redis最核心的数据结构String之SDS
SDS名称叫做(simple dynamic string)翻译过来就叫简单的动态字串。顾名思义,它主要就是用来存字串数据的。类似于java的String对象。
小草飞上天
2025/01/14
1591
redis最核心的数据结构String之SDS
redis SDS设计与实现分析
本系列文章从源码角度分析redis的设计与实现,分析的源码为最新版本7.2.4。下载地址(https://github.com/redis/redis/tree/7.2.4)。
数据小冰
2024/03/22
3920
redis SDS设计与实现分析
Redis源码分析SDS
Redis 中字符串都用自定义的结构**简单动态字符串(Simple Dynamic Strings,SDS),而不是C语言的字符串。 Redis 中使用到的字符串都是用 SDS,例如 key、string 类型的值、sorted set 的 member、hash 的 field 等等等等
克虏伯
2023/11/05
2800
Redis源码分析SDS
【redis源码学习】simple dynamic strings(简单动态字符串 sds)
Q1:如何实现一个扩容方便且二进制安全(不会被\0打断)的字符串呢? Q2:SDS如何兼容C语言函数呢? Q3:SDS为了节约内存都秀了什么操作呢? Q4:SDS是如何扩容的? Q5:SDS是如何减少拷贝次数的?
看、未来
2021/12/21
3400
【redis源码学习】simple dynamic strings(简单动态字符串 sds)
Redis【2】- SDS源码分析
Redis 中用得最多的就是字符串,在 C 语言中其实可以直接使用 char* 字符数组来实现字符串,也有很多可以直接使用得函数。但是 Redis 并没有使用 C 语言原生的字符串,而是自己实现了一个 SDS(简单动态字符串,Simple Dynamic String) 。
秦怀杂货店
2024/12/07
980
Redis【2】- SDS源码分析
探索Redis设计与实现3:Redis内部数据结构详解——sds
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
Java技术江湖
2019/12/02
3740
String底层实现——动态字符串SDS
上篇我们已经了解了Redis是什么,在Linux上如何安装,常见的数据类型和API使用,如果有不明白的,可以移步到主页。
陈琛
2020/06/18
6060
Redis源码剖析之SDS(Simple Dynamic String)
SDS(simple dynamic string)是Redis提供的字符串的封装,在redis中也是存在最广泛的数据结构,它也是很多其他数据结构的基础,所以才选择先介绍SDS。 SDS也兼容部分C字符串API(strcmp,strlen),它如何兼容C字符串我觉得也是有个很sao的操作,等看完我这篇博客你就明白了。在开始正式内容前,我先抛几个问题(有些也是面试高频题),带着问题去学习也是一种非常好的学习方法。
xindoo
2021/01/22
5170
Redis源码剖析之SDS(Simple Dynamic String)
Redis 数据结构-字符串源码分析
平时在使用 Redis 的时候,只会使用简单的 set,get,并不明白其中的道理,为了探个究竟,搞个明白,就看了下其底层的实现 ^ ^。
Java技术编程
2020/05/21
4920
面试杀手锏:Redis源码之SDS
Hello,欢迎大家来到《 Redis 数据结构源码解析系列》,在《Redis为什么这么快?》一文中我说过 Redis 速度快的一个原因就是其简单且高效的数据结构。
敖丙
2022/03/24
7940
面试杀手锏:Redis源码之SDS
Simple Dynamic Strings(SDS)源码解析和使用说明二
     在《Simple Dynamic Strings(SDS)源码解析和使用说明一》文中,我们分析了SDS库中数据的基本结构和创建、释放等方法。本文将介绍其一些其他方法及实现。(转载请指明出于breaksoftware的csdn博客)
方亮
2019/01/16
9690
Redis剖析——Redis字符串的设计与实现
Redis是一个键值对数据库(key-value DB),下面是一个简单的Redis的命令:
binecy
2021/12/08
8450
Redis剖析——Redis字符串的设计与实现
redis学习 - sds字符串
Redis 设计与实现:如果想要知道redis底层,这本书可以给予不少的帮助,非常推荐每一位学习redis的同学去翻一翻。
阿东
2021/08/16
3280
redis学习 - sds字符串
redis数据结构-SDS
本文最后更新于 2022年12月30日,已超过 32 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
仙士可
2023/02/01
3230
redis数据结构-SDS
从源码上聊聊Redis-String、List的结构实现
本文的数据类型只讲底层结构和部分机制,不讲具体的使用,使用的话自行bing,但是会提一些应用场景
Karos
2023/07/20
9760
从源码上聊聊Redis-String、List的结构实现
sds数据结构分析-redis源码阅读笔记(1)
sds 定义 typedef char *sds; 数据结构: struct sdshdr {   // buf 中已占用空间的长度   int len;   // buf 中剩余可用
evenleo
2020/11/15
4770
Redis 基本特性
  1. 非关系型的键值对数据库,可以根据键以O(1) 的时间复杂度取出或插入关联值   2. Redis 的数据是存在内存中的   3. 键值对中键的类型可以是字符串,整型,浮点型等,且键是唯一的   4. 键值对中的值类型可以是string,hash,list,set,sorted set 等   5. Redis 内置了复制,磁盘持久化,LUA脚本,事务,SSL, ACLs,客户端缓存,客户端代理等功能   6. 通过Redis哨兵和Redis Cluster 模式提供高可用性
忧愁的chafry
2022/10/30
1.1K0
Redis 基本特性
深入理解Redis 数据结构—简单动态字符串sds
Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库、缓存和消息中间件。其中 Redis 键值对中的键都是 string 类型,而键值对中的值也是有 string 类型,在 Redis 中 string 类型运用还是很广泛的。本文主要介绍 string 的数据结构—— 简单动态字符串(Simple Dynamic String) 简称sds。
用户10384376
2023/02/25
3290
深入理解Redis 数据结构—简单动态字符串sds
Redis | 源码阅读 —— 字符串
使用过 Redis 的都知道 Redis 用的最多的可能是它的 Key/Value 的缓存,在 Redis 用作 Key/Value 的缓存时,Value 有若干种数据类型,分别是 String、List、Set、Sorted Set 和 Hash。不同的 Value 类型对应了不同的数据结构,我们分别来了解一下 Redis 各种 Value 类型的数据结构。
码农UP2U
2020/09/11
6320
Redis | 源码阅读 —— 字符串
相关推荐
透过Redis源码探究字符串的实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验