redis-1

作者: 甜甜起司猫_ | 来源:发表于2021-06-09 20:29 被阅读0次

redis-1

redis的IO模型

4大核心组建

  1. 多路复用
  2. 套接字队列
  3. 事件分派器
  4. 事件处理器 (请求处理器、连接处理器、回复处理器)

运行过程:
主线程监听套接字事件,把套接字丢给套接字队列,事件分派器从队列中获取套接字,丢给事件处理器处理。

(此处应有图)

6.0引入多线程模型

redis原IO模型的瓶颈在于从套接字中读取数据,因此在6.0版本中引入异步IO去解决这个问题。在新的多线程模型下,主线程在监听套接字事件后,找到一个IO线程去读取套接字数据,主线程根据事件找到对应的事件处理器,执行命令。在将响应写入套接字这个过程,也是交给IO线程去处理。总的来看,相当于有一个异步IO线程池,专门处理IO的读写,而主线程负责监听套接字和执行命令。

(此处应有图)

与memcache的IO模型对比

memcache的IO模型,本质上也是多路复用。与redis的IO模型不同的是,memcache的主线程只负责监听套接字,而读写IO和执行命令的工作,都交给worker线程来完成。

(此处应有图)

类似netty worker group

(此处应有图)

过期处理

  1. 定期删除
  2. 惰性删除

定期删除

redis定期遍历数据库,检查过期的key并删除。特点是随机检查,不会一次全部删除所有过期的key,而是在规定的事件内能删多少删多少,目的是为了平衡CPU的开销和内存的消耗。

关联G1的部分region回收,是为了停顿时间可控

惰性删除

在访问key的时候,检查key的过期时间,如果已经过期,则删除该key键值对。

过期处理时,RDB、AOF和主从复制下的表现

当redis开启RDB、AOF和主从复制时,redis的过期处理:

  1. 加载RDB时会忽略已过期的key-RBD不读
  2. 重写AOF时会忽略已过期的key-AOF不写
  3. 主从同步时,从服务器等待主服务器的删除命令-从服务器不处理

不同版本的过期处理策略

针对主从同步场景,在进行过期删除时,从服务器等待主服务器的删除指令;但在读过期数据时:

  1. 版本3.2之前,从服务器会返回过期key的值,仿佛key没过期
  2. 版本3.2之后,从服务器会返回NULL,和主服务器行为一致

版本3.2之前,从服务器读取过期key的处理,可以使用TTL命令来判断key有没有过期


redis在执行删除指令时,不会同步删除key,而是将key从keyspace中移除,然后将删除任务放入一个异步队列,最后由其他后台线程删除。但如果key键值对不是很大,删除时不需要很大的开销,此时就没必要使用异步队列去删除了,所以,redis会先计算删除key的开销,达到一定的阈值才会启用异步删除。

redis value的数据结构

SDS

特点:

  1. 存储了字符串长度,可以常量时耗获取字符串长度
  2. SDS采用了预分配和懒回收策略来分配内存,减少分配和回收内存的次数

hashtable

特点:

  1. 使用拉链法解决冲突
  2. 渐进式rehash
  3. murmurhash2算法

拉链法

redis的hashtable使用拉链法解决hash冲突,当发生冲突时,将元素插入链表头。

渐进式rehash

当扩容或缩容时需要进行rehash,为了避免集中式rehash会对服务器带来庞大的计算量从而导致响应延迟等,需要将rehash分为多次,渐进式的完成。

渐进式rehash是将rehash的计算工作平摊到每次的增删改查的执行中,是一种分而治之的思想,渐进式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 操作已完成。

murmurhash2

该算法效率高,随机性较好,减少发生冲突的几率。

ziplist

ziplist是Redis为了节省内存而自定义的一种特殊编码的顺序性数据结构。ziplist内存结构类似数组,是连续的内存空间,但存储的元素类型和大小不一定一致。ziplist通常用于有序并且大小较小数量较少的数据集合。

对ziplist进行增删查操作时,会涉及两个关键点:

  1. 元素移动
  2. 连锁更新

元素移动

因为ziplist是类似数组那样使用连续内存空间去存储,所以在增删元素时和数组有相似的表现:增删某一元素时,首先要从头开始遍历直到找到目标位置,在对目标位置元素进行改变后,其前后的元素也要相应的进行位移(增:往后位移,删:往前位移)。所以ziplist增删的时间复杂度是O(n)。

连锁更新

ziplist有个特点,每个元素会存储前一个元素的大小,这样可以实现反向遍历。但如果前一个节点发生长度变化时,当前元素就要改变这个值。所以最坏的情况是,一个元素的改动影响所有元素的改动,时间复杂度是O(n^2)。

ziplist特点

  1. 整个ziplist存在一个连续内存中
  2. 通过固定内存偏移量获取头节点,保留与尾节点的偏移量zltail,而不像双端链表存储头尾节点
  3. 每个节点保留前置节点的长度,从而实现反向遍历,而不像双端链表存储前置节点指针
  4. 每个节点采用变长的编码方式,存储字符串或整数值
  5. 在特定条件下,ziplist会发生连锁更新,导致增删操作时间复杂度由O(n)变为O(n^2)

intset

intset是一个数组结构,用于存储整数类型,里面的元素是唯一的。它可以存放16、32、64位的整数。如果元素位数变大,那么就会触发升级过程。例如原本存储的元素都是16位整数,现在插入一个32位的整数,那么 Redis 需要按照32位重新计算内存大小,并且分配内存,迁移原本的数据,而后将新数据插入。有一点需要注意的是,Redis并不支持降级。这是intset升级不降级的特性。

相关文章

  • Redis-1

    一、Redis基础 概述Redis是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的Web应...

  • redis-1

    redis-1 redis的IO模型 4大核心组建 多路复用 套接字队列 事件分派器 事件处理器 (请求处理器、连...

  • Redis-1 入门

    官网: https://redis.io/参考: http://redisdoc.com/ Redis 介绍 Re...

  • Java-分布式框架-redis-1

    Redis核心原理 Redis的单线程和高性能 Redis 单线程为什么还能这么快? 因为它所有的数据都在内存中,...

  • 从零开始写一个Redis-1

    嵌牛导读:为了学习Redis和更好地理解Redis,决定自己写一个C++版本的Redis 嵌牛鼻子:Redis 嵌...

  • Redis-1 redis介绍以及安装单机版

    1、介绍 redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value数据库...

网友评论

      本文标题:redis-1

      本文链接:https://www.haomeiwen.com/subject/vhuqeltx.html