redis

1.概述

    Redis 是一个基于键值对(key-value)的分布式存储系统,与Memcached类似,却优于Memcached的一个高性能的key-value数据库。

    Redis 数据库里面的每个键值对(key-value) 都是由对象(object)组成的:

  数据库总是一个字符串对象(string object);

  数据库的则可以是字符串对象、列表对象(list)、哈希对象(hash)、集合对象(set)、有序集合(sort set)对象这五种对象中的其中一种。

    我们为什么会说Redis 优于Memcached 呢,因为Redis 的出现,丰富了memcached 中key-value的存储不足,在部分场合可以对关系数据库起到很好的补充作用,而且这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。

2.redis底层数据结构

2.1 简单动态字符串(simple dynamic string)SDS 

 定义:

Redis 中定义动态字符串的结构:

/*  
 * 保存字符串对象的结构  
 */  
struct sdshdr {  
      
    // buf 中已占用空间的长度  
    int len;  
  
    // buf 中剩余可用空间的长度  
    int free;  
  
    // 数据空间  
    char buf[];  
};

 

 

   1、len 变量,用于记录buf 中已经使用的空间长度(这里指出Redis 的长度为5)

   2、free 变量,用于记录buf 中还空余的空间(初次分配空间,一般没有空余,在对字符串修改的时候,会有剩余空间出现)

     3、buf 字符数组,用于记录我们的字符串(记录Redis)

2.3 与C字符串得区别

 

2.3.1 获取字符串长度(SDS O(1)/C 字符串 O(n))

     传统的C 字符串 使用长度为N+1 的字符串数组来表示长度为N 的字符串,所以为了获取一个长度为C字符串的长度,必须遍历整个字符串。

     和C 字符串不同,SDS 的数据结构中,有专门用于保存字符串长度的变量,我们可以通过获取len 属性的值,直接知道字符串长度。

    

 

2.3.2 杜绝缓冲区溢出

    C 字符串 不记录字符串长度,除了获取的时候复杂度高以外,还容易导致缓冲区溢出。

     假设程序中有两个在内存中紧邻着的 字符串 s1 和 s2,其中s1 保存了字符串“redis”,二s2 则保存了字符串“MongoDb”:

      

     如果我们现在将s1 的内容修改为redis cluster,但是又忘了重新为s1 分配足够的空间,这时候就会出现以下问题:

      

      我们可以看到,原本s2 中的内容已经被S1的内容给占领了,s2 现在为 cluster,而不是“Mongodb”。

 

     Redis 中SDS 的空间分配策略完全杜绝了发生缓冲区溢出的可能性:

     当我们需要对一个SDS 进行修改的时候,redis 会在执行拼接操作之前,预先检查给定SDS 空间是否足够,如果不够,会先拓展SDS 的空间,然后再执行拼接操作

 

 

2.3.3 减少修改字符串时带来的内存重分配次数   

  C语言字符串在进行字符串的扩充和收缩的时候,都会面临着内存空间的重新分配问题。

   1. 字符串拼接会产生字符串的内存空间的扩充,在拼接的过程中,原来的字符串的大小很可能小于拼接后的字符串的大小,那么这样的话,就会导致一旦忘记申请分配空间,就会导致内存的溢出。

   2. 字符串在进行收缩的时候,内存空间会相应的收缩,而如果在进行字符串的切割的时候,没有对内存的空间进行一个重新分配,那么这部分多出来的空间就成为了内存泄露。

  举个例子:我们需要对下面的SDS进行拓展,则需要进行空间的拓展,这时候redis 会将SDS的长度修改为13字节,并且将未使用空间同样修改为1字节 

  

   因为在上一次修改字符串的时候已经拓展了空间,再次进行修改字符串的时候会发现空间足够使用,因此无须进行空间拓展

  

 

  通过这种预分配策略,SDS将连续增长N次字符串所需的内存重分配次数从必定N次降低为最多N次

 

2.3.4 惰性空间释放

    我们在观察SDS 的结构的时候可以看到里面的free 属性,是用于记录空余空间的。我们除了在拓展字符串的时候会使用到free 来进行记录空余空间以外,在对字符串进行收缩的时候,我们也可以使用free 属性来进行记录剩余空间,这样做的好处就是避免下次对字符串进行再次修改的时候,需要对字符串的空间进行拓展。

    然而,我们并不是说不能释放SDS 中空余的空间,SDS 提供了相应的API,让我们可以在有需要的时候,自行释放SDS 的空余空间。

    通过惰性空间释放,SDS 避免了缩短字符串时所需的内存重分配操作,并未将来可能有的增长操作提供了优化

 

 

2.3.5 二进制安全

    C 字符串中的字符必须符合某种编码,并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存想图片,音频,视频,压缩文件这样的二进制数据。

    但是在Redis中,不是靠空字符来判断字符串的结束的,而是通过len这个属性。那么,即便是中间出现了空字符对于SDS来说,读取该字符仍然是可以的。

    例如:

   

 

 

2.3.6 兼容部分C字符串函数

     虽然SDS 的API 都是二进制安全的,但他们一样遵循C字符串以空字符串结尾的惯例。

 

2.3.7 总结

 

C 字符串SDS
获取字符串长度的复杂度为O(N)获取字符串长度的复杂度为O(1)
API 是不安全的,可能会造成缓冲区溢出API 是安全的,不会造成缓冲区溢出
修改字符串长度N次必然需要执行N次内存重分配修改字符串长度N次最多执行N次内存重分配
只能保存文本数据可以保存二进制数据和文本文数据
可以使用所有<String.h>库中的函数可以使用一部分<string.h>库中的函数

转载于:https://my.oschina.net/u/3900969/blog/3006653

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值