分享

Redis官方主题 – Virtual Memory虚拟内存

 昵称597197 2011-06-15

尽管Redis的虚拟内存是首次出现在Redis 2.0稳定发布版的特性之一。但是通过对Git上发布的Redis分支所做的大量测试证明,虚拟内存技术目前已经是稳定可靠的。

虚拟内存简述

Redis遵循一种Key-Value键值模型。你可以将键与一些值关联起来。通常情况下,Redis把键和相关联的值都存储在内存中,但有时候这未必是最佳选择。为了确保能够快速查找,键必须存储在内存中,但是可以把一些很少使用的值交换至磁盘中。

在实践过程中,如果你的内存中存有10w个键的数据集,但是只有10%的键是经常使用的,那么开启了虚拟内存机制的Redis就会把这些利用率不高的键所对应的值数据交换至磁盘中。

当客户端发起一条命令,请求访问这些冷门数据并作为结果返回的时候,这些值又会从交换文件中重新加载至内存中。

使用虚拟内存的时机

在你决定使用虚拟内存之前,你应该问自己是否真的需要这个特性。Redis只是一种用磁盘做备份的内存数据库。Redis的使用之道应该是尽可能的使用足够的内存以保证数据全部存放在内存中。但是下列场景中不是必须如此:

  1. 数据访问总是集中在某些数据上。只需要一小部分键就可以获得大部分的访问数据(例如你网站的活跃用户数据)。与此同时,每个键有太多数据存放在内存中。
  2. 可能因为没有过多考虑数据存储模式,或者数据值太大,使得我们没有足够的内存将所有的数据都存放在内存中。在这种环境下,Redis可以转化成只把键存放于内存中的磁盘数据库使用,这样键查询速度依然很快,但是在访问值的时候需要去读取低速的磁盘。

有一点非常值得注意,Redis无法将键交换至磁盘中,因此如果你的内存问题是因太多值很小的键引起,虚拟内存机制是帮不了你的。

但是,如果大部分内存开销都用于大容量的值存储时(例如很大的字符串,列表,集合或者很多元素的哈希),那么选用虚拟内存机制是一个好主意。

有时候,你可以通过采用Hash结构将相关数据分组存入到一个单键所对应的字段,把“大量值很小的键”情况所引发的问题,转化成“键很少但是值很大”的情况。举个例子,通过把一个对象的不同属性映射至一个单键的Hash字段上,来取代为对象的每个属性都使用一个键的方案。(思门注:Hash数据结构同样从Redis2.x版本开始出现)

虚拟内存配置

配置Redis的虚拟内存并不难,但是应该根据需求细心的设置最佳的参数。

虚拟内存的开启和配置都是通过编辑redis.conf文件实现,首先将它启用:

vm-enabled yes

有大量的选项可以改变虚拟内存的性能。如果不希望使用默认配置运行每个数据集,那么你需要做一些细微的调整以获取最大的性能。

vm-max-memory选项

vm-max-memory选项用于指定当Redis占用多大内存空间后,才将数据交换至磁盘。

基本上如果(内存使用)没有达到这个内存限制,是不会有任何对象被交换至磁盘的,Redis将像往常一样在内存中使用所有对象。如果一旦达到该限制,那么Redis将会尽可能的把数据交换出去,以保证内存使用回到限制范围之内。

被交换出去的对象主要是”老龄化“(也就是,那些已经有很长时间没有被使用过的)的这些数据,并且一个对象的”被交换能力“与它在内存中所占用的空间大小是成对数比例的。所以,旧对象是优先考虑的,当生存期差不多的时候,值内容更大的对象将被优先交换出去。

警告:由于在Redis中键是无法被交换出去的,因此如果键占用的空间超过了内存限制,Redis的vm-max-memory选项是无法生效的。

这个选项最大的价值就是将“工作集”中的数据存储于足够的内存中。在实践过程中,尽可能给Redis分配更多的内存,交换工作将会做的更好。

配置交换文件

为了把数据从内存上转移至磁盘中,Redis使用了交换文件。交换文件对数据持久化没有太大的作用,并且可以在Redis进程终止后删除。但是,在Redis运行过程中,不应对交换文件进行移动,删除或者修改操作。

因为Redis的交换文件大多使用随机访问方式,所以把交换文件存放于固态磁盘中会得到更好的性能。

交换文件被分成多个“页”。一个值可以被交换至一个或更多页中,但是一个单页内不能保存多于一个的值。

目前还没有直接的方法,告诉Redis的交换文件应该使用多少字节大小。而是通过配置两个不同的参数,将它们的乘积用于计算可用的字节总数。这两个参数分别是交换文件中的页数,和单页的大小。可以在redis.conf配置文件中配置这两个参数。

  • vm-pages选项管理交换文件中的总页数。
  • vm-page-size选项则用于设置每页的字节数。

因此,如果每页大小设置为32字节,并且总页数设置为1000w页,那么交换文件总共可以存储320MB的数据。

因为每页都不能保存超过限制大小的内容(但是一个值可以被存储于多个页中),因此在设置这些参数的时候得格外小心。通常而言最好的方式是调节页大小,让大多数值被交换至尽可能少的页中。

线程化虚拟内存 vs 阻塞式虚拟内存

另一个非常重要的配置参数就是vm-max-threads:

# The default vm-max-threads configuration
vm-max-threads 4

这是交换文件执行I/O操作时所能用到的最大线程数。合适的参数值是与你的系统内核数保持一致。

然而特殊值“0”将会启用阻塞式虚拟内存。当虚拟内存配置为阻塞式后,它将以同步阻塞方式执行I/O操作。这些就是你可以从阻塞式虚拟内存中预期得到的:

  • 客户端在访问被交换出的键时会阻塞其他客户端读取数据,因此对客户端会产生的较大延迟,尤其是当你正使用低速磁盘、磁盘正忙,或者是有许多内容很大的值被交换至磁盘的时候。
  • 总体而言,阻塞式虚拟内存的性能会更好一些,因为在同步、产生线程,以及恢复因等待数据而被阻塞的客户端过程中没有时间消耗。因此如果你愿意接受更高的延迟,尤其是极少发生数据交换,并且大部分时间所访问的数据都在内存中时,阻塞式虚拟内存机制会是一个好的选择。

相反,如果你有大量的数据交换出入的操作,想充分利用多核特性,并且不希望客户端在处理数据交换的时候被其他客户端中断几毫秒(或者更多需要交换的数据都比较大)时,最好还是使用线程虚拟内存。

热情期望您使用不同的配置和数据进行体验。

交换文件的合适存放位置

在许多配置中,交换文件尺寸可以设置成相当大,40GB甚至更多。并不是所有的文件系统都可以很好的处理这么大的文件,尤其是在蹩脚的Mac OS X文件系统中。官方推荐使用的是Linux系统下的Ext3文件系统,或者是其他能够良好支持稀疏文件的文件系统。什么是稀疏文件?

稀疏文件就是留有很多空余空间的文件。高级的文件系统,像ext2, ext3, ext4, RaiserFS, Raiser4,还有一些其他的,都能够以一种更有效的方式将文件编码,并且在需要时分配更多的可用空间,也就是说,在文件中使用更多实际的块。

很显然,交换文件相当稀疏,尤其是服务器刚运行了一小段时间,或者文件自身大小相比交换出去的数据量而言很大的情形。当立即创建一个很大的文件时,一个不支持稀疏文件的文件系统在某种程度上可能会导致Redis进程阻塞。

至于支持稀疏文件的文件系统列表,可以将参见维基百科对不同文件系统的对比(via)。

虚拟内存监控

一旦你选择了开启Redis系统的虚拟内存机制并运行,你一定会很感兴趣它是如何工作的:总共有多少对象被交换,每秒交换和载入的对象数量,等等。

有一个用于检测虚拟内存工作状态非常顺手的工具,它是Redis Tools的其中一部分。这个工具叫redis-stat,而且用起来相当清晰。

以上输出的是数据是关于一台开启了虚拟内存机制,大约有100w键在内,并且通过redis-load工具模拟载入的Redis服务器。

正如你所见,每秒都会产生大量的load-in和swap-out操作。需要注意的是,第一行结果记录的是自服务器启动后的实际值,后面显示的都是和第一行对比的差异数据。

如果你为保持数据赋予了足够多的内存,很有可能你看到的只有一小部分数据交换发生,因此redis-stat是一个相当有价值的工具,以便让你知道是否需要去购买新的内存条了:)

在开启虚拟内存的时候选择.rdb文件还是增量文件会更好?

当虚拟内存开启时,保存和加载数据库的时候会比较慢。如果在服务器尽可能使用最小内存的情况下(举个例子,vm-max-memory设置为0),通常情况下只需要2秒就能载入的数据,在开启虚拟内存的时候需要13秒才能完成。

因此你可能希望为了持久化把配置文件切换至增量文件模式,这样你可以时不时的使用BGREWRITEAOF命令。

很重要的一点,当BGSAVE或者BGREWRITEAOF命令在执行过程中的时候,Redis是不会把新产生的数据交换到磁盘上的。当另外一个子进程访问的时候,虚拟内存将变为只读状态。因此当子进程工作时如果产生大量的数据写入操作,内存占用量可能会攀升。

尽可能少的使用内存

一种有意思的Redis安装方式:通过将vm-max-memory设置为0,仅把键存在内存中来实现一个基于磁盘的数据库。如果你不介意延迟高一些,性能损失一些,只是希望为内容很大的值少花费一些内存开销,这也是一个不错的安装方法。

在这种安装模式下,数据交换会产生的巨大流量,线程开销也会消耗大量的资源,你应该尝试开启阻塞式虚拟内存(vm-max-threads设置为0)。

虚拟内存的稳定性

虚拟内存仍然是实验性代码,但是最近几周在测试环境中已经经历了多种测试,甚至在一些生产环境中也使用了。在这些测试期间,没有发现任何Bug。不过在那些我们因为某些原因无法复制的环境中,仍然可能存在某些隐藏的问题。

现阶段,我们鼓励你在开发环境以及处理非核心业务的生产环境中尝试VM机制,比如只是一个大的数据持久化缓存消失时,不会有太多的问题的情况下。

请把你遇到的任何问题,通过Redis谷歌小组或者加入Redis的IRC频道,报告给我们。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多