ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Redis学习(一)-- Redis及SDS初识

2021-01-26 22:58:49  阅读:204  来源: 互联网

标签:__ 字节 SDS -- Redis 字符串 buf


Redis及SDS初识

Redis简介

Redis(REmote DIctionary Server)是使用C语言编写的、开源的、支持网络的、基于内存的、可选持久化的键值对数据库。

2009年第一版,2018年redis 5.0.0,2019年redis 6,目前最新。

Redis优点

  1. 内存型数据库,读写速度快
  2. 单线程(一个线程处理网络请求,IO多路复用),避免了线程之间的切换,不存在加锁、解锁等同步操作
  3. 支持复杂的数据类型,key value的value可以是多种类型:string list set zset hash
  4. 支持数据持久化:RDB AOF RDB&AOF 三种方案,重启后数据可回复
  5. 支持主从结构,集群模式

与Memcached对比

  1. 内存型数据库
  2. 多线程
  3. 只支持string、二进制类型
  4. 不支持数据持久化,重启后数据丢失
  5. 不支持集群模式,需要依赖客户端实现在集群中分片写入数据

简单动态字符串-SDS

SDS简介

简单动态字符串(Simple Dynamic Strings,SDS)是Redis的基本数据结构之一,也是Redis高效工作的武器之一。SDS用于存储字符串和整形数据,并且保证了二进制安全(后续会说明)。

SDS数据结构

struct sds {
    int len;   //buf中已占用字节数,即当前长度
    int free;  //buf中剩余可用字节数
    char buf[];//柔性数组,可伸缩(可扩容)
}

SDS相对于char*的优点

快速获取长度和剩余空间

根据统计变量len,free可以更快的得到字符串的长度和可用字节数,O(1)

二进制安全

C语言中,"\0"表示字符串的结束,如果字符串中本身就有"\0",字符串会被截断,该问题称为非二进制安全。SDS中可以根据len可知字符串是否终止,不必依赖于"\0"。

防止越界

当对SDS进行修改、合并、追加等操作时,可以根据len free等进行边界检查(还有自动扩容及类型转换),防止操作越界。

空间预分配和惰性释放

空间预分配

用于SDS字符串的增长:当对SDS进行拼接修改时,会进行边界检查,如有需要,会自动进行空间扩展,为其分期所必须的空间以及额外的未使用空间(sdsMakeRoomFor)。

惰性空间释放

用于SDS字符串的缩短(释放):并非使用内存重分配释放多出来的内存,而是通过重置len free记录,

新的数据可以覆盖写,不用重新申请内存。

当然,SDS也提供了相应的API,使其在需要时真正地释放未使用空间,避免惰性空间释放导致的空间浪费。

兼容C语言处理字符串的函数

SDS对上层暴露的指针不是SDS结构体的指针,而是指向柔性数组buf的指针。可直接对其使用C语言的字符串处理函数。

SDS优化

SDS多容量类型优化(头部优化)

上述SDS结构的问题

对于短字符串来说,内容可能只有1字节,但头部却占了4个字节,浪费空间

对于很长的字符串来说,len和free都是4个字节,能存储的字符数量最多也只能为2[^32]

5种类型

分为5种类型(头部长度小于1字节、1字节、2字节、4字节、8字节),使用1字节的标志字段flags来标识类型(sdshdr5种flags也用于记录buf长度)。sdshdr5 sdshdr8 sdshdr16 sdshdr32 sdshdr64

sdshdr5
struct __atribute__((__packed)) sdshdr5{
    unsigned char flags; //低3位表示类型,高5位表示长度
    char buf[];
}

sdshdr5种flags的低3位表示类型(2[3]=8),高5位表示长度(2[5]=32 ,即可用于表示长度小于32的短字符串)

sdshdr16

sdshdr8(最长2[^8]) sdshdr16(最长2[^16]) sdshdr32(最长2[^32]=4GB) sdshdr64(最长2[64]=2[24]T) 结构相同。

struct __atribute__((__packed)) sdshdr8{
    unit8_t len;        //已使用长度
    unit8_t alloc;      //总长度,1字节
    unsigned char flags; //低3位表示类型,高5位预留
    char buf[];
}
struct __atribute__((__packed)) sdshdr16{
    unit16_t len;        //已使用长度
    unit16_t alloc;      //总长度,2字节
    unsigned char flags; //低3位表示类型,高5位预留
    char buf[];
}
...

这里以sdshdr16为例:
在这里插入图片描述

结构体对齐

__atribute__((__packed__))修饰,使结构体由按照变量大小的最小公倍数(sdshdr16是2,sdshdr32是24)字节对齐变为按1字节对齐,一下以sdshdr32为例:

在这里插入图片描述

改为1字节对齐后:

  • ​ 节省了3字节
  • ​ 能使用buf[-1]找到flags。否则还要对不能的结构进行处理buf[-4] buf[-8]…等,更复杂。

SDS扩容

改为1字节对齐后:

  • ​ 节省了3字节
  • ​ 能使用buf[-1]找到flags。否则还要对不能的结构进行处理buf[-4] buf[-8]…等,更复杂。

SDS扩容

本文参考《Redis5 设计与源码分析》

标签:__,字节,SDS,--,Redis,字符串,buf
来源: https://blog.csdn.net/qq_34963409/article/details/113201635

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有