SDS

Redis面试热点之底层实现篇

空扰寡人 提交于 2020-02-26 05:27:52
Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久化的高性能键值对数据库。Redis的之父是来自意大利的西西里岛的Salvatore Sanfilippo,Github网名antirez,笔者找了作者的一些简要信息并翻译了一下,如图: 从2009年第一个版本起Redis已经走过了10个年头,目前Redis仍然是最流行的key-value型内存数据库的之一。 优秀的开源项目离不开大公司的支持,在2013年5月之前,其开发由 VMware 赞助,而2013年5月至2015年6月期间,其开发由 毕威拓 赞助,从2015年6月开始,Redis的开发由 Redis Labs 赞助。 笔者也使用过一些其他的NoSQL,有的支持的value类型非常单一,因此很多操作都必须在客户端实现,比如value是一个结构化的数据,需要修改其中某个字段就需要整体读出来修改再整体写入,显得很笨重,但是Redis的value支持多种类型,实现了很多操作在服务端就可以完成了,这个对客户端而言非常方便。 当然Redis由于是内存型的数据库,数据量存储量有限而且分布式集群成本也会非常高,因此有很多公司开发了基于SSD的类Redis系统,比如360开发的SSDB、Pika等数据库,但是笔者认为从0到1的难度是大于从1到2的难度的,毋庸置疑Redis是NoSQL中浓墨重彩的一笔

简单动态字符串

邮差的信 提交于 2020-02-13 23:48:47
  Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组,以下简称C字符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。   当Redis需要的不仅仅是一个字符串面量,而是一个可以被修改的字符串值时,Redis就会使用SDS来表示字符串值,比如在Redis的数据库里,包含字符串值得键值对在底层都是由SDS来实现得。   客户端执行命令     set msg "hello world"   那么Redis将在数据库中创建一个新得键值对,其中     键值对得键是一个字符串对象,对象得底层实现是一个保存着字符串“msg”的SDS     键值对的值也是一个字符串对象,对象的底层实现是一个保存着字符串“hello world”的SDS   又比如,客户端执行命令     rpush fruits “apple” “banana” “cherry”   那么Redis将在数据库中创建一个新的键值对,其中      键值对的键是一个字符串对象,对象底层实现是一个保存了字符串“fruits”的SDS      键值对的值是一个列表对象,列表对象包含了三个字符串对象,这三个字符串对象分别由三个SDS实现:第一个SDS保存着字符串“apple”,第二个SDS保存着字符串

Redis-----第2章 简单动态字符串

邮差的信 提交于 2020-02-07 23:31:35
第2章 简单动态字符串 文章目录 第2章 简单动态字符串 @[toc] 1. SDS的定义 2. SDS和C字符串的区别 (1). 获取字符串长度 (2). 杜绝缓冲区溢出 (3). 减少修改字符串时带来的内存充分配次数 1). 空间预分配 2). 惰性空间释放 (4). 二进制安全 (5). 兼容部分C字符串函数 ​ Redis自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将其作为Redis的默认字符串表示.在Redis中,包含字符串值的键值对在底层都是SDS实现的.C字符串只会作为字面量使用. 1. SDS的定义 struct sdshdr { // 记录出发数组中已经使用了的字符数量 // 也就是sds所保存的字符串的长度 int len ; // 记录空闲空间的数量 int free ; // 字节数组,存储字符数据 char buf [ ] ; } ​ SDS遵循C字符串以空字符(’\0’)结尾的惯例,目的是为了直接重用一部分C字符串库函数.但是这个空字符是不计入len属性中的. 2. SDS和C字符串的区别 ​ C字符串并不能满足Redis在安全性,效率以及功能方面的要求. (1). 获取字符串长度 ​ SDS可以常数复杂度的获取字符串的长度,因为数据结构中已经存储了字符串的长度,不需要遍历数组去求累计和. (2). 杜绝缓冲区溢出 ​

Redis学习-简单动态字符串SDS

梦想与她 提交于 2020-02-06 20:24:47
SDS(simple dynamic string)简单动态字符串 SDS与C语言字符串在redis用法上的区别: C语言字符串用于字符串不被修改的地方,如日志输出 SDS是一个可以被修改的字符串,如键,值 结构体保存在sds.h/sdsdr文件中 struct sdhdr { //记录buf数组中已经使用的字节的数量 int len ; //记录buf数组中未使用的数量 int free ; //字节数组用于保存字符串 char buf [ ] ; } ; 注意C语言字符串的最后一个空字符‘\0’不属于len 打印字符串时用 printf ( "%s" , s - > buf ) ; SDS与C语言字符串的区别 1.常数复杂度获取自妇产长度 C语言求长度是需要遍历的 2.杜绝缓冲区溢出 C语言有一个函数 char * strcat ( char * dest , const char * src ) ; 用于把src字符串拼接到dest上面,但是如果dest空间不足就会产生溢出。 Redis有自己的SDS拼接函数 sdscat 用于拼接,会先检查是否有足够大的内存空间,不够就进行内存拓展,然后再进行拼接。 3.减少修改字符串带来的内存分配次数 C语言不用说,每次都是重新分配,但是SDS不一样,实现了: 空间预分配 若对SDS修改之后,长度小于1MB,则分配 len+free

Redis设计与实现——第一部分 数据结构与对象

笑着哭i 提交于 2020-02-03 22:46:28
第一部分 数据结构与对象 第2章 简单动态字符串 Redis自己创建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。在Redis里面,C字符串只会作为字符串字面量用在一些无须对字符串值进行修改的地方,比如打印日志什么。但是如果用在一个字符串变量,Redis就会使用SDS来表示字符串值,比如在Redis的数据库里面,包含字符串值的键值对在底层都是由SDS来实现的。 127.0.0.1:6379> set k1 hello OK 127.0.0.1:6379> get k1 "hello" 那么Redis将在数据库中创建一个新的键值对,其中键值对的键是一个字符串对象,对象的底层实现是一个保存着字符串"k1"的SDS。键值对的值也是一个字符串对象,对象的底层实现是一个保持着字符串"hello"的SDS。 如果客户端执行命令 127.0.0.1:6379> RPUSH fruits apple banana cherry (integer) 3 那么Redis将在数据库中创建一个新的键值对,其中键值对的键是一个字符串对象,对象底层实现是一个保存了字符串"fruits"的SDS。键值对的值是一个列表对象,列表对象包含三个字符串对象,这三个字符串对象分别由三个SDS实现。 除了用来保存数据库中的字符串值外

Redis数据结构:SDS

余生长醉 提交于 2020-01-27 07:44:41
1. 简单动态字符串(simple dynamic string,SDS)是Redis的默认字符串表示结构,底层的string都是基于SDS实现。Redis基于C语言,并引用了部分C函数。 使用场景:SET key "hello" 或RPUSH list "a" "b" "c" ,其中引号中的字符串就是SDS类型的 数据结构:struct sdshdr { //buf中保存的字符串长度 int len; //buf中空闲空间长度 int free; //字符串数组,注意:buf会在结尾处额外分配一个字符'\0',不参与计算 char buf[]; }; 2. 动态扩容策略: 在拼接一个字符串时,Redis会先检查是否有多余的空间,若不够会先扩容到符合【已有长度+新长度】,然后再拼接,并额外再分配相同大小的空间。 2.1 预分配: 1)如果对SDS进行修改之后,len如果小于1MB,那么程序也会分配和len相同大小的为使用空间,这时len=free。比如:SDS的len=5,free=0,当添加一个长度为3的字符串后,len=8,free=8,此时buf的长度为8+8+1(额外的一字节为'\0');当下次再添加3个字符串时,free的长度符合要求,就不会触发扩容了。 2)如果len大于等于1MB,那么程序会额外分配1MB的空间。 2.2 懒释放 当减少一些字符串时

redis数据结构-sds

跟風遠走 提交于 2020-01-26 14:58:34
sds-simple dynamic string简单的动态数组 1、sds定义 2、与c字符串比较 3、sds特性 1)获取长度时间复杂度为O(1) sds中有len长度字段 2)缓冲器不会溢出 首先sds有预留空闲free存储空间 其次如果空间不够,会动态申请 3)修改字符串最多需要执行N次内存重分配 重分配策略 a)空间预分配 策略是当sds长度小于1m时,预分配空间=sds长度,当大于1m时,预分配1m b) 惰性空间释放 当sds缩短时,程序不立即释放多出来的字节空间,而是使用free属性将这些字节的数量记录起来,以备将来用,可通过API释放这部分空间 4)可以保存文本或者二进制数据 c字符串除了末尾之外不能有空字符,否则空字符会被误认为字符串结尾,这就导致了c字符串不能报错图片、音频、视频以及二进制数据;而sds是根据len来判读字符串结尾的 来源: https://www.cnblogs.com/yanwei-wang/p/8072863.html

关于redis中SDS简单动态字符串

旧时模样 提交于 2020-01-25 04:55:00
1、SDS 定义 在C语言中,字符串是以’\0’字符结尾(NULL结束符)的字符数组来存储的,通常表达为字符指针的形式(char *)。它不允许字节0出现在字符串中间,因此,它不能用来存储任意的二进制数据。 sds的类型定义 typedef char *sds; 肯定有人感到困惑了,竟然sds就等同于char *? sds和传统的C语言字符串保持类型兼容,因此它们的类型定义是一样的,都是char *,在有些情况下,需要传入一个C语言字符串的地方,也确实可以传入一个sds。 但是sds和char *并不等同,sds是Binary Safe的,它可以存储任意二进制数据,不能像C语言字符串那样以字符’\0’来标识字符串的结束,因此它必然有个长度字段,这个字段在header中 sds的header结构 /* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */ struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string

redis.1--SDS结构

时光总嘲笑我的痴心妄想 提交于 2020-01-25 04:53:31
1. Redis 没有直接使用c语言的字符串(以空字符结尾的字符数组),而是自己构建了一 种名为简单动态字符串(Simple Dynamic String , SDS),并将SDS做为  redis的默认字符串。 2.在redis数据库里面,包含字符串的键值对,底层都是由SDS实现的。 3.举例说明:   (1)在redis客户端执行:set msg "HelloWorld" ,那么,redis在数据库中将会创建一个新的键值对。键值对的键对象的底层实现,是由一个保存着字符串msg的SDS实现的。     键值对的值是一个保存着HelloWorld的SDS.   (2) 执行:set fruit "apple" "banana" "orange" ,那么,键值对的键是一个保存着fruit字符串的SDS。     键值对的值是一个列表对象,列表对象,包含三个字符串对象,三个字符串对象底层分别由三个SDS实现。 4.SDS的实义   如图:    (1)free 属性为0,表示这个SDS没有分配任何未使用空间。 (2)len 属性为5,表示这个SDS保存着一个5字节长的字符串 (3)buf 属性是一个char类型的数组,数组的前五个字节分别保存了,'R' 'e' 'd' 'i' 's' ,而最后一个字节保存了空字符 '\0' (以空字符结尾),最后一个空字节不计算在len属性里面。

redis源码分析(3)sds

丶灬走出姿态 提交于 2020-01-25 04:52:19
sds是redis中用来处理字符串的数据结构。sds的定义在sds.h中: 1 typedef char *sds; 简洁明了!简明扼要!(X,玩我呢是吧!这特么不就是c中的字符串么?!)。像redis这种高端大气上档次的服务器显然不会这么的幼稚。在sds的定义之后,还有一个结构体: 1 struct sdshdr { 2 int len; 3 int free; 4 char buf[]; 5 } 有len,有free,这就有点意思了。很明显,根据这个结构体的定义,这是sds的header,用来存储sds的信息。注意最后的buf定义,这个buf数组没有设置长度。这是为神马呢?在gcc中,这种方式可以使得buf成为一个可变的数组,也就是说,可以扩展buf同时又保证在使用的时候,感觉buf始终在struct sdshdr中。有点啰嗦,其实可以用下图展示: sdshdr sds | | V V ---------------------------- |len | free | buf … | ---------------------------- 这个就是sds的内存分布图。struct sdshdr这个结构体放在了真正的数据之前,且是紧挨着的。这样,通过buf引用的数组其实就是后面的数据。这个是利用了c中数组访问的特点。 下面我们来看看如何创建一个sds: 1 /* Create