⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 codenong.com/cs106843764 「码农家园」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

Redis 源码中有很多优秀的实践,值得我们学习。它作为开源作品之一,汇聚了众多开源智慧,深受广大程序员喜爱。它的优秀还导致了不少人都喜欢研究它,面试官也喜欢提问面试者,也使整个行业进入了更深的内卷。

我相信多数人还是拒绝选择躺平的,今天我们一起来了解一下,Redis 的 VM 机制。

Redis 之 VM 机制

Redis 的 VM (虚拟内存)机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过 VM 功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。Redis 提高数据库容量的办法有两种:一种是可以将数据分割到多个 Redis Server上;另一种是使用虚拟内存把那些不经常访问的数据交换到磁盘上。「需要特别注意的是 Redis 并没有使用 OS 提供的 Swap,而是自己实现。」

Redis 为了保证查找的速度,只会将 value 交换出去,而在内存中保留所有的 Key。所以它非常适合 Key 很小,Value 很大的存储结构。如果 Key 很大,value 很小,那么vm可能还是无法满足需求。

VM 相关配置

通过在 redis 的 redis.conf 文件里,设置 VM 的相关参数来实现数据在内存和磁盘之间 换入和 换出操作。相关配置如下:

#开启vm功能
vm-enabled yes
#交换出来的value保存的文件路径
vm-swap-file /tmp/redis.swap
#设置当内存消耗达到上限时开始将value交换出来
vm-max-memory 1000000
#设置单个页面的大小,单位是字节
vm-page-size 32
#设置最多能交换保存多少个页到磁盘
vm-pages 13417728
#设置完成交换动作的工作线程数,设置为0表示不使用工作线程而使用主线程,这会以阻塞的方式来运行。建议设置成CPU核个数
vm-max-threads 4

redis 规定同一个数据页面只能保存一个对象,但一个对象可以保存在多个数据页面中。在 redis 使用的内存没超过 vm-max-memory 时,是不会交换任何 value 到磁盘上的。当超过最大内存限制后,redis 会选择较老的对象(如果两个对象一样老会优先交换比较大的对象)将它从内存中移除,这样会更加节约内存。

对于 Redis 来说,一个数据页面只会保存一个对象,也就是一个 Value 值,所以应该将 vm-page-size 设置成大多数 value 可以保存进去。如果设置太小,一个 value 对象就会占用几个数据页面,如果设置太大,就会造成页面空闲空间浪费。

VM 的工作机制

redis 的 VM 的工作机制分为两种:一种是 vm-max-threads=0,一种是 vm-max-threads > 0。

「第一种:vm-max-threads = 0」

  • 数据换出:

主线程定期检查使用的内存大小,如果发现内存超出最大上限,会直接以阻塞的方式,将选中的对象 换出 到磁盘上(保存到文件中),并释放对象占用的内存,此过程会一直重复直到下面条件满足任意一条才结束:

1、内存使用降到最大限制以下。 2、设置的交换文件数量达到上限。 3、几乎全部的对象都被交换到磁盘了。

  • 数据换入:

当有 client 请求 key 对应的 value 已被换出到磁盘中时,主线程会以阻塞的方式从换出文件中加载对应的 value 对象,加载时此时会阻塞所有 client,然后再处理 client 的请求。「这种方式会阻塞所有的 client。」

「第二种:vm-max-threads > 0」

  • 数据换出:

当主线程检测到使用内存超过最大上限,会将选中的要交换的数据放到一个队列中交由工作线程后台处理,主线程会继续处理 client 请求。

  • 数据换入:

当有 client 请求 key 的对应的 value 已被换出到磁盘中时,主线程先阻塞当前 client,然后将加载对象的信息放到一个队列中,让工作线程去加载,此时进主线程继续处理其他 client 请求。加载完毕后工作线程通知主线程,主线程再执行被阻塞的 client 的命令。「这种方式只阻塞单个 client。」

总结

Redis 直接自己构建了 VM 机制 ,不会像一般的系统会调用系统函数处理,会浪费一定的时间去 移动 和 请求,而 Redis 不存在。这也是 Redis 能够那么快的一个原因之一了。

文章目录
  1. 1. Redis 之 VM 机制
  2. 2. VM 相关配置
  3. 3. VM 的工作机制
    1. 3.1. 「第一种:vm-max-threads = 0」
    2. 3.2. 「第二种:vm-max-threads > 0」
  4. 4. 总结