《Redis官方文档》 redis 虚拟内存

原文链接 译文链接 译者: youxin2012
重点提示:
Redis 的虚拟内存(VM) 目前不被提倡使用,Redis 2.4将是有虚拟内存特性的最新版本(但它同样提示不鼓励使用虚拟内存)。我们发现使用虚拟内存会有一些不足和问题。对于Redis的未来,至少目前在不考虑支持比RAM更大的数据库时,我们希望能提供最好的内存数据库(持久化仍然在磁盘上)。我们随后的成果将关注提供脚本,集群以及更好的持久化方面。

虚拟内存

Redis 虚拟内存这一特性将首次出现在Redis 2.0的一个稳定发布版中。目前Git上Redis 不稳定分支的虚拟内存(从现在起称之为VM)已经可以使用,并且经试验证明足够稳定。

简介

Redis遵循 key-value模型。同时key和value通常都存储在内存中。然而有时这并不是一个最好的选择,所以在设计过程中我们要求key必须存储在内存中(为了保证快速查找),而value在很少使用时,可以从内存被交换出至磁盘上。

实际应用中,如果内存中有一个10万条记录的key值数据集,而只有10%被经常使用,那么开启虚拟内存的Redis将把与较少使用的key相对应的value转移至磁盘上。当客户端请求获取这些value时,他们被将从swap 文件中读回,并载入到内存中。

何时使用虚拟内存

在确定使用VM之前,请首先确认是否真的需要使用这一特性。Redis是一个磁盘备份,内存型数据库。使用Redis 的正确方法通常是使用足够大的RAM去装载所有数据。然而,有些场景下是无法做到这样的:

  • 数据访问不均匀。只有很少部分的key被大量访问,而每一个key又有大量的数据要放入内存。
  • 在不考虑数据读取方式以及value存储空间大小的前提下,仅由于没有足够的空间将所有数据放入内存。这种场景下,Redis可以被配置为在内存中存储key,在磁盘中存储value。此时key的查询操作较快,而value的读取则相对较慢。

谨记Redis的key是不做swap操作的,所以如果你的内存有大量的key和少量的value时,那么VM并不能解决你的问题。

然而当由于value占用空间较大(如占用空间较多的strings以及含有大量元素的lists, sets 或者 hashes)导致内存不足时,那么VM无疑是一个很好的选择。

有时你可以通过哈希表将相关的数据归组到一个key的相应字段,从而将“大量key与小存储的value”的问题转化为“少量key与大存储的value”的问题。例如你可以为每一个对象设置一个单独的key,并用哈希表的多个字段代表对象的不同属性,而非为对象的每一个属性设置一个单独的key。

VM 配置

VM的配置相对简单,可以根据需求设置最佳参数。通过编辑redis.conf来开启并配置VM。首先开启VM:

         vm-enabled yes

很多配置项可以改变VM的行为。事实上,为了获取最佳性能,你常常需要对配置做微调,而非使用默认参数。

vm-max-memory设置

vm-max-memory 指 Redis 在将value交换至磁盘(进行swap操作)之前有多大内存可使用。

通常,如果未达到内存上限,则不需要进行磁盘交换,Redis将所有对象放在内存中操作。然而一旦到达上限,将会有大量的对象被交换出内存至磁盘,以释放内存空间,直到低于限制。

交换过程(swap操作)中,首先被交换的对象是那些有着较大“年龄”(指未被访问的时长)的对象,同时一个对象的“交换能力”(”swappability”)与它在内存中大小的对数成正(swappability = age*log(size_in_memory))。当两个对象有着相同的“年龄”时,占用空间较大的对象将会首先被交换出去。

提醒:由于key不能被交换出内存,所以当仅由于key占用空间较多而达到内存上限时, Redis是不能通过改变 vm-max-memory 来解决问题的。

最好将该值设置到可以用RAM装载整个数据的工作集(working set)。实际中,当Redis有足够的内存时,交换操作(swap)也将进行的更加顺利。

配置swap文件

Redis利用swap文件将数据从内存转移到磁盘。swap文件并不对数据的存储时间做处理,当一个Redis应用结束时,swap文件可以被清除。然而,当Redis运行时不能以任何形式移动,删除或改变 swap文件。由于Redis的swap文件通常以随机读取的方式被使用,所以用ssd(固态硬盘)存储swap文件性能将更好。

swap文件按“页”(page)切分。一个值可以被交换(swap)到一个或多个页中,但是一个页最多只能存储一个值。

没有直接的方式可以获取Redis的swap文件将有多少字节被使用。然而,可以利用两个不同的配置参数,将其做乘积计算出使用的字节总数。这两个参数分别表示交换文件的页数和页大小,它们可以在redis.conf文件中配置:

  • vm-pages 用于配置swap文件中页的总数
  • vm-page-size 用于配置页的字节数

例:如果页大小被设置为32 byte,同时 页的总数被设置为1千万, 则交换文件总共可以装载320MB的数据。

由于单页最多只能装载一个value(但是一个value可以被存储在多个页上),因此应特别注意这些参数的设置。通常通过改变页大小来完成设置,这样可以用少量的页来完成大部分value的交换。

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

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

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

该参数用于设置Redis与swap文件进行I/O的最大线程数。通常令其等于系统的cpu核数。

当该参数设置为“0”时,将开启阻塞式虚拟内存。此时,它将以同步阻塞的方式进行I/0. 阻塞式虚拟内存有如下特性:

  • 当客户端从磁盘上读取被交换出去的key时,将阻塞其他客户端,所以该方式经历时延较长,尤其当磁盘较慢或者有大存储的数据发生交换时。
  • 总体说来,由于在进行同步、增加线程和恢复由于等待value而阻塞的客户端时没有时间损耗,阻塞式虚拟内存表现更好一些。所以如果你能接受偶尔较高的时延,阻塞式虚拟内存将是一个好的选择。尤其在发生交换较少,同时大部分你经常访问的数据恰好可以放入内存时。

相反,如果有大量的换入换出操作时,同时系统有多核可以使用,而你又不希望进行swap操作的客户端阻塞其他客户端时(通常几毫秒,当待交换数据占用空间较大时,时间会更长),用线程式虚拟内存效果将更好。我们鼓励你尝试用不同的配置做测试。

要知道的一些事情

swap文件的存放

在很多配置中swap文件可以很大,达到40GB或者更大。然而并不是所有的文件系统都可以很好的处理大文件,尤其是Mac OS X的文件系统,常常会显得异常蹩脚。

建议使用 linux ext3文件系统,或者其他可以很好支持稀疏文件的文件系统。

什么是稀疏文件?

稀疏文件指有大量内容为空的文件。高级一些的文件系统例如ext2, ext3, ext4,ReiserFS, Reiser4和其他一些文件 可以用一种更高效的方式编码这些文件,同时当文件有更多的块(block)需要被使用时,则为该文件分配更多的空间。

swap文件很稀疏的。当一次创建一个很大的文件时,不支持稀疏文件的文件系统可能会阻塞Redis进程。

参考wikepedia page  了解支持稀疏文件的文件系统。

虚拟内存的监控

一旦使用了开启虚拟内存的Redis,你可能很感兴趣它是怎样工作的:总共多少个对象被交换,每秒交换与载入的对象量等等。

下面是一个用于检查VM是如何工作的工具(见此处)。作为Redis 工具的一部分,redis-stat简单易用:

$ ./redis-stat vmstat
--------------- objects --------------- ------ pages ------ ----- memory -----
load-in  swap-out  swapped   delta      used     delta      used     delta
138837   1078936   800402    +800402    807620   +807620    209.50M  +209.50M
4277     38011     829802    +29400     837441   +29821     206.47M  -3.03M
3347     39508     862619    +32817     870340   +32899     202.96M  -3.51M
4445     36943     890646    +28027     897925   +27585     199.92M  -3.04M
10391    16902     886783    -3863      894104   -3821      200.22M  +309.56K
8888     19507     888371    +1588      895678   +1574      200.05M  -171.81K
8377     20082     891664    +3293      899850   +4172      200.10M  +53.55K
9671     20210     892586    +922       899917   +67        199.82M  -285.30K
10861    16723     887638    -4948      895003   -4914      200.13M  +312.35K
9541     21945     890618    +2980      898004   +3001      199.94M  -197.11K
9689     17257     888345    -2273      896405   -1599      200.27M  +337.77K
10087    18784     886771    -1574      894577   -1828      200.36M  +91.60K
9330     19350     887411    +640       894817   +240       200.17M  -189.72K

上面是一个redis-server 在虚拟内存开启,内部含有大约 1千万条key,同时利用redis-load 工具做大量仿真负载时的输出结果。从输出中你可以看到每秒有大量的“载入”和“交换”操作。请注意第一行显示从服务器开启时到现在的实际数值,下面几行不同于之前读取的数值。

如果你分配了足够的内存,可能会看到很多不太明显的交换,而redis-stat 是一个非常有用的工具,可以帮你判断是否需要更换RAM了。

开启虚拟内存的Redis :.rdb文件还是 AOF(Append Only File)文件更合适 ?

当虚拟内存开启时,保存和读取数据库操作都将变慢。当服务器被配置为用最少的内存时(即vm-max-memory 被设置为0),一个通常2s载入一次的DB操作,在开启虚拟内存时耗时将长达13s,所以你可能希望切换使用AOF的配置来实现持久化,以便可以进行BGREWRITEAOF操作。

请注意 当进程进行 BGSAVE 或者 BGREWRITEAOF 操作时,Redis不会在磁盘上交换新的value.

当有子进程访问虚拟内存时,虚拟内存将是只读的。所以,当有一个子进程有大量的写操作时,内存使用将增加。

减少使用内存

将 vm-max-memory设置为0,可以使Redis转为仅有key在内存中的磁盘数据库。当你希望使用尽可能少的内存存储大容量数值, 同时不介意时延或者相对糟糕的性能时,这是不错的选择。

该设置中你应该首先尝试着将虚拟内存设置为阻塞式(vm-max-threads 0)的。大量的交换入和交换出操作将带来巨大的开销,与单线程阻塞式虚拟内存相比,线程式虚拟内存将消耗大量的资源 。

虚拟内存的稳定性

虚拟内存仍处于试验阶段,但在过去的数周里,它已经以各种方式被应用到开发环境中,甚至一些产品中。目前,在测试阶段并没有发现bug,然而更多不确定的bug可能会在日后某些不可控的环境中发生,而这些环境常常由于一些原因而无法复现。

当前阶段,我们鼓励你在开发过程中尝试使用虚拟内存,甚至在产品中,如果你的db不是至关重要的话。

请报告任何你注意到的问题到the Redis Google Group,或者通过IRC加入 #redis IRC。

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 《Redis官方文档》 redis 虚拟内存

  • Trackback 关闭
  • 评论 (0)
  1. 暂无评论

return top