Redis的数据保存在内存中,可能出现物理内存不足的情况。物理内存不足时,Redis使用“虚拟内存”解决
Redis的VM与操作系统的VM相似,把很少访问的value保存到磁盘中。同时,Redis把value对应的key都放在内存中,为了能够让Redis快速定位到被换出的value所在磁盘位置,从而将其导入到内存中
相比操作系统的VM,redis的VM的优势:
1.操作系统的VM是基于页的概念,比如Linux系统中每个页是4KB,而Redis大多数对象远小于4KB,一页上可能有多个Redis对象。另外Redis的集合对象类型如List、set可能存在于多个页上。故Redis自己实现可达到控制换入的粒度
2.Redis将交换到磁盘的对象压缩,保存到磁盘的对象可以去除指针和对象元数据信息。一般压缩后的对象比内存中的对象小10倍,这样Redis的VM比操作系统的VM少做很多I/O操作
配置文件信息
#开启VM功能 vm -enabled yes #交换出来的value保存的文件路径/tmp/redis.swap vm -swap -file /tmp/redis.swap #Redis使用的最大内存上限,超过上限后Redis开始交换value到磁盘文件中 vm -max -memory 268435456 #设置每个页面的大小为32个字节 vm -page -size 32 #最多在文件中使用多少页面,SWAP文件的大小等于vm -page -size * vm -pages vm -pages 134217728 #用于执行value对象换入换出的工作线程数量。0表示不使用工作线程 vm -max -threads 4
Redis的VM只把value交换到磁盘中,而key依然存储在内存中,目的是让开启VM的Redis和完全使用内存的Redis性能基本保持一致。如果由于太多key而造成内存不足问题,Redis的VM并不能解决
Redis也按照页来交换对象,一页只能保存一个对象,但是一个对象可以保存在多页中。当Redis使用的内存没有超过设置的vm-max-memory之前,不把任何value交换到磁盘中;当超过最大内存限制后,Redis根据以下算法寻找一个对象交换到磁盘中:
swappability = age * log(size_in_memory)
age代表这个对象距离上一次被访问的时间,size_in_memory是这个对象在内存中占用的空间大小。Redis采取的策略是把那些很少访问,而且占用内存又比较大的对象交换到磁盘中,但是第二个因素所占的权重更低,所以在公式中取log值。因为交换大对象时,需要占用更多的I/O和CPU资源
对象在SWAP文件中如何存储-->
SWAP文件中采用rdb文件的存储格式。SWAP文件被分割成固定数量的页,每页占用指定数量的字节空间。在redis.conf中根据自己业务需求配置以下两个参数:
vm-page-size:设置每页的大小,默认值为32
vm-pages:设置能够使用的页数,默认值为134217728
Redis在内存中保存一个bitmap以映射这些页是否被占用,每bit代表对应磁盘空间的页是否被使用。内存中保存这样一份映射表极大增强了Redis性能,同时,对内存的使用又非常少
开启VM的后台操作-->
Redis默认持久化方式是开启一个子进程创建rdb文件。Redis调用系统的fork函数创建一个子进程,这样得到当前在内存中数据库的一个完全一致的拷贝,因为fork函数复制了当前进程的整个编程内存空间(Copy On Write)
当VM开启时,value可能被交换出内存,并不是在内存中保存所有数据。子进程在执行保存时,与父进程共享同一个SWAP文件,因为:
有命令需要请求交换出内存的数据时,父进程需要把这些对象换回到内存中;子进程需要访问SWAP文件获得完整数据集
为了避免两个进程访问同一个SWAP文件,当有后台子进程在做快照保存时,父进程不允许把内存中的对象交换到SWAP文件
Redis正在进行后台内存快照或者后台重写aof时,不能VM交换
交换过程
1.交换对象至SWAP文件
计算保存这个对象需要占用SWAP文件中的多少页
在SWAP文件中寻找一段连续页空间保存这个对象
把对象写入SWAP文件
2.从SWAP文件中加载对象