*log(size_in_memory)。对于vm-page-size的设置应该根据自己的应用将页面的大小设置为可以容纳大多数对象的大小。太大了会浪 费磁盘空间,太小了会造成交换文件出现碎片。对于交换文件中的每个页面,redis会在内存中对应一个1bit值来记录页面的空闲状态。所以像上面配置中页 面数量(vm-pages 134217728 )会占用16M内存用来记录页面空闲状态。vm-max-threads表示用做交换任务的线程数量。如果大于0推荐设为服务器的cpu core的数量。如果是0则交换过程在主线程进行;
参数配置讨论完后,在来简单介绍下vm是如何工作的:
当vm-max-threads设为0时(Blocking VM)
换出:
主线程定期检查发现内存超出最大上限后,会直接已阻塞的方式,将选中的对象保存到swap文件中,并释放对象占用的内存,此过程会一直重复直到下面 条件满足:
1.内存使用降到最大限制以下
2.swap文件满了
3.几乎全部的对象都被交换到磁盘了
换入:
当有client请求value被换出的key时。主线程会以阻塞的方式从文件中加载对应的value对象,加载时此时会阻塞所有client。然后处理client的请求
当vm-max-threads大于0(Threaded VM)
换出:
当主线程检测到使用内存超过最大上限,会将选中的要交换的对象信息放到一个队列中交由工作线程后台处理,主线程会继续处理client请求。
换入:
如果有client请求的key被换出了,主线程先阻塞发出命令的client,然后将加载对象的信息放到一个队列中,让工作线程去加载。加载完毕后工作线程通知主 线程。主线程再执行client的命令。这种方式只阻塞请求value被换出key的client;
总的来说blocking vm的方式总的性能会好一些,因为不需要线程同步,创建线程和恢复被阻塞的client等开销。但是也相应的牺牲了响应性。threaded vm的 方式主线程不会阻塞在磁盘io上,所以响应性更好。如果我们的应用不太经常发生换入换出,而且也不太在意有点延迟的话则推荐使用blocking vm的方式。
关于redis vm的更详细介绍可以参考下面链接:
http://antirez.com/post/redis-virtual-memory-story.html
http://redis.io/topics/internals-vm
3>diskstore方式
diskstore方式是作者放弃了虚拟内存方式后选择的一种新的实现方式,也就是传统的B-tree的方式。具体细节是:
1) 读操作,使用read through以及LRU方式。内存中不存在的数据从磁盘拉取并放入内存,内存中放不下的数据采用LRU淘汰。
2) 写操作,采用另外spawn一个线程单独处理,写线程通常是异步的,当然也可以 把cache-flush-delay配置设成0,Redis尽量保证即时写入。但是在 很多场合延迟写会有更好的性能,比如一些计数器用Redis存储, 在短时间如果某个计数反复被修改,Redis只需要将最终的结果写入磁盘。这种 做法作者叫per key persistence。由于写入会按key合并,因此和snapshot还是有差异,disk store并不能保证时间一致性。
由于写操作是单线程,即使cache-flush-delay设成0,多个client同时写则需要排队等待,如果队列容量超过cache-max-memory Redis设计会进入等 待状态,造成调用方卡住;
Google Group上有热心网友迅速完成了压力测试,当内存用完之后,set每秒处理速度从25k下降到10k再到后来几乎卡住。 虽然通过增加cache- flush-delay可以提高相同key重复写入性能;通过增加ca