Redis笔记1(数据结构)

redis的特点

(1)优点

  • 数据结构丰富----方便操作,比如队列的先进先出,hash结构O(1)的快速查询,sorted-set有序集合方便获取排名
  • 数据在内存操作—快速
  • 单线程处理—避免锁
  • 非阻塞式IO多路复用—充分利用网络IO
  • 设计简单,效率高
  • 方便扩展,不像mysql一样分库分表,只要简单扩大内存,或增加redis个数
    (2)缺点
  • Rdb备份不具备实时性
  • Aof持久化比较消耗内存和cpu,甚至当aof文件过大的时候占用磁盘

基础数据结构

1 SDS

应用场景: list对象当列表比较长,而且存储的内容也比较长的时候,采用此种数据结构编码(类似于线性表)

struct sdshdr {
    int len; // buf 中已占用空间的长度
    int free;// buf 中剩余可用空间的长度
    char buf[]; // 数据空间,以’\0’结尾
};

相比字符串做出的优化

  • 常数复杂度获取字符串长度-----sds->len
  • 杜绝缓冲区溢出-----通过free的长度来判断是否有充足的空间
  • 减少修改字符串时带来的内存重分配次数----free够的时候,不需要重分配,只有free不足的时候需要扩展。如果对字符串收缩也不需要立刻回收空间,只需要修改len和free的属性即可。----空间预分配和惰性空间释放
  • 二进制安全
  • SDS相对C字符串虽然有些操作更快更便捷,但是这是以事先预分配超过需求的空间,以及记录len和free来完成的。这个过程有点以牺牲空间换时间的方法。而且这个len和free大小设置也是一门技术活!

2.链表

方便插入删除,方便重排,特别适合队列这种频繁的push和pop的操作

3.字典

用于保存键值对,Redis 的数据库就是使用字典来作为底层实现,哈希表也是
渐进式Rehash
随着操作的不断执行,哈希表保存的键值对会逐渐地增多或者减少,为了让hash表的负载因子(load factor)维持在一个合理的范围之内,当哈希表保存的键值对数量太多或者太少时,程序需要对hash表的大小进行相应的扩展活放缩。

hash表的负载因子 = hash节点个数/hash表的长度

为了避免rehash(hash节点个数可能成百上千万个)对服务器性能造成影响,服务器不是一次性将ht[0]里面的所有键值对全部rehash到ht[1], 而是分多次、渐进式地将ht[0]里面的键值对慢慢地rehash到ht[1].

渐进式rehash的基本步骤是:

(1)为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表

(2)在字典中维持一个索引计数器变量rehashidx,并将它的值设置为0,标识rehash开始。

(3)在rehash进行期间,每次对字典执行添加、删除、查找、删除或者更新操作时,程序除了执行指定的操作以外,还会顺带将ht[0]哈希表在rehashidx索引上的所有键值对rehash到ht[1], 当rehash工作完成之后,程序将rehashidx属性的值增一。

(4)随着字典操作的不断执行,最终在某个时间点上,ht[0]的所有键值对都会被rehash至ht[1],这时程序将rehashidx的属性的值设为-1,表示rehash操作已完成。

渐进式rehash的好处在于它采取分而治之的方式,将rehash键值对所需的计算工作均摊到字典的每个添加删除查找和更新操作上,从而避免了集中式rehash而带来的庞大计算量。

4. 跳跃表

跳跃表(skiplist)是一种有序数据结构,它通过在某个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。

redis中的应用:有序集合键,集群节点中用作内部数据结构

类似红黑树,但是实现较红黑树简单。排序或者有序查找可以达到二分查找的效率,该数据结构是以空间换时间。

5. 整数集合

整数集合是集合键的底层实现之一, 当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。

6. 压缩列表—内存编码的数据结构(节省内存)

压缩列表是列表键和hash键的底层实现之一。当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么redis就会使用压缩列表来做列表键的底层实现。

7. redis对象(顶层)

Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据库建立了一个对象系统,比如字符串对象,列表对象,集合对象,hash表对象,有序集合对等

使用对象的好处在于:

(1)我们可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率—对应redisObject中的encoding

(2)Redis的对象还实现了基于引用计数计数的内存回收机制—对应redisObject中的refCount

(3)Redis还通过引用计数实现了对象共享机制

(4)Redis对象带有访问时间记录信息,该信息可以计算数据库键的空转时长,从而确定在内存不足的情况下是否优先删除

因为C语言并不具备自动内存回收功能,所以redis对象系统构建了一个引用计数refcount技术来实现内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象进行内存回收。

对象的引用计数信息会随着对象的使用状态而不断变化:

在创建一个新对象时,引用计数的值会被初始化为1;
  当对象被一个新程序使用时,它的引用计数值会被增1
  当对象不再被一个程序使用时,它的引用计数会减1
  当对象的引用计数为0时,对象所占用的内存会被释放。

猜你喜欢

转载自blog.csdn.net/weixin_40632321/article/details/83617067