Redis的设计与实现 | 数据结构、多线程和缓存

前言

本系列[Redis的设计与实现]为网络课程的笔记整理, 如有疏漏和错误的地方, 欢迎留言更正!

Redis的数据结构

redis的通用格式是redisobject, 其中包含5中字段:

  • type字段:标志该对象是什么对象
  • encoding字段: 内部编码类型,每种redis类型都可以用不用的具体实现
  • lru字段:24bit, 记录对象最后被访问的时间, 辅助LRU删除的算法
  • refcount字段: 记录当前用户被引用的次数, 辅助引用计数法的垃圾回收算法.
  • *ptr字段: 数据指针, 如果是整数则直接放到数据指针中.
    redis的通用数据结构

Redis中的线程和IO模型

redis开发了文件事件处理器(file event handler),从用I/O多路复用同时监听多个socket, 其中包括下列组成:

  • socket:socket操作的抽象
  • IO多路复用器:监听多个sockt
  • 文件事件分派器:接收多个socket传来的socket
  • 文件事件处理器:服务器会为执⾏不同任务的套接字关联不同的事件处理器, 这些处理器是⼀个个函数, 它们定义了某个事件发⽣时, 服务器应该执⾏的动作。
    文件事件处理器

Redis中的多线程

Redis4.0开始的版本并非纯粹的“单线程”, 只有执行命令的主线程执行, 还有一些用于后台任务的线程.

Redis6之前之所以不用多线程, 因为redis并不会受到cpu的限制, 而是受限于内存和网络. 另外开启多线程会带来并发读写的系列问题.

Redis6.0之后引入了多线程, 但也仅是Redis6.0引入了多线程的特性,这个多线程是在哪里呢?——「是对处理网络请求过程采用了多线程」。 这样可以满足2个原因:

  1. 充分利用服务器的CPU资源
  2. 多线程任务可以分摊Redis同步IO读写负荷.

Redis 6.0采用多个IO线程来处理网络请求,网络请求的解析可以由其他线程完成,然后把解析后的请求交由主线程进行实际的内存读写。提升网络请求处理的并行度,进而提升整体性能。

Redis中的缓存淘汰算法

当Redis中的key数量超过max memory值后, 会使用相应的内存淘汰策略. Redis中常用的2中内存淘汰方法, LRU和LFU, 具体可以再细分为:

  1. Noeviction:这是默认的淘汰策略, 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进⾏.
  2. volatile-lru:volatile-lru 尝试淘汰设置了过期时间的 key,最少使⽤的 key 优先被淘汰
  3. volatile-ttl: volatile-ttl 跟上⾯⼀样,除了淘汰的策略不是 LRU,⽽是 key 的剩余寿命 ttl 的值,ttl 越⼩越优先被淘汰。
  4. volatile-random: volatile-random 跟上⾯⼀样,不过淘汰的 key 是过期 key 集合中随机的 key。
  5. allkeys-lru: 按照访问时间在全体的key淘汰最老被访问的.
  6. allkeys-random: 随机淘汰key
Redis中的近似LRU算法

Redis 使⽤的是⼀种近似 LRU 算法,它跟 LRU 算法还不太⼀样。之所以不使⽤ LRU 算法,是因为需要消耗⼤量的额外的内存.

Redis 为实现近似 LRU 算法,它给每个 key 增加了⼀个额外的⼩字段,这个字段的⻓度是 24 个 bit,也就是最后⼀次被访问的时间戳。

每次都是随机采样(分别是all-keys和lru-keys)出5个key, 然后淘汰最早被访问(利用LRU字段中的24bit字段)的key, 这个算法在大数定理下会近似严格的LRU算法.

Redis中的LFU算法

Redis4中新增中的淘汰策略, 核心思想是表示一个key被访问的热度, 在lru字段中后的8位中表示访问次数的已8为底数的对数结果.

Redis中的过期策略和惰性删除

设置过TTL的key都会被放入一个独立的字典中, 然后根据采用以下2种策略来进行删除:

  1. 定时扫描策略:

Redis 默认会每秒进⾏⼗次过期扫描,过期扫描不会遍历过期字典中所有的 key,⽽是采⽤了⼀种简单的贪⼼策略。
1、从过期字典中随机 20 个 key;
2、删除这 20 个 key 中已经过期的 key;
3、如果过期的 key ⽐率超过 1/4,那就重复步骤 1;

  1. 惰性删除: 访问时检查是否过期, 过期则删除.

总结:定期删除是集中处理,惰性删除是零散处理。

LazyFree

使用DEL命令删除大key或者大量key时, 会阻塞.
为了解决以上问题, redis 4.0 引⼊了lazyfree的机制,它可以将删除键或数据库的操作放在后台线程⾥执⾏, 从⽽尽可能地避免服务器阻塞。

lazyfree的原理不难想象,就是在删除对象时只是进⾏逻辑删除,然后把对象丢给后台,让后台线程去执⾏真正的destruct,避免由于对象体积过⼤⽽造成阻塞。

参考文章:
知乎 | Redis单线程模型,redis6的多线程模型
Redis6.0为何引入多线程?单线程不香吗?

思维导图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值