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

    xiaoxiao2024-04-20  6

    重点提示: 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 相关资源:敏捷开发V1.0.pptx
    最新回复(0)