Rides 自整理命令

时间:2022-03-20 20:32:36
Redis学习笔记 ---来自Redis实战  建议和Redis设计与实现一起看
1.redis.conf 文件  配置参数解释

daemonize:
默认情况下,redis 不是在后台运行的,如果需要在后台运行,把该项的值更改为 yes

pidfile
当 Redis 在后台运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid,你可以配
置到其他地址。当运行多个 redis 服务时,需要指定不同的 pid 文件和端口

bind
指定 Redis 只接收来自于该 IP 地址的请求,如果不进行设置,那么将处理所有请求,在
生产环境中最好设置该项

port
监听端口,默认为 6379

timeout
设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,
那么关闭该连接

loglevel
log 等级分为 4 级,debug, verbose, notice, 和 warning。生产环境下一般开启 notice

logfile
配置 log 文件地址,默认使用标准输出,即打印在命令行终端的窗口上
databases
设置数据库的个数,可以使用 SELECT <dbid>命令来切换数据库。默认使用的数据库是 0

save
设置 Redis 进行数据库镜像的频率。

if(在 60 秒之内有 10000 个 keys 发生变化时){
进行镜像备份
}else if(在 300 秒之内有 10 个 keys 发生了变化){
进行镜像备份
}else if(在 900 秒之内有 1 个 keys 发生了变化){
进行镜像备份
}

rdbcompression
在进行镜像备份时,是否进行压缩

dbfilename
镜像备份文件的文件名

dir
数据库镜像备份的文件放置的路径。这里的路径跟文件名要分开配置是因为 Redis 在进
行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,再把该
临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放
在这个指定的路径当中

slaveof
设置该数据库为其他数据库的从数据库

masterauth
当主数据库连接需要密码验证时,在这里指定

requirepass
设置客户端连接后进行任何其他指定前需要使用的密码。警告:因为 redis 速度相当快,
所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行 150K 次的密码尝试,
这意味着你需要指定非常非常强大的密码来防止暴力破解。

maxclients
限制同时连接的客户数量。当连接数超过这个值时,redis 将不再接收其他连接请求,
客户端尝试连接时将收到 error 信息。

maxmemory
设置 redis 能够使用的最大内存。当内存满了的时候,如果还接收到 set 命令,redis 将
先尝试剔除设置过 expire 信息的 key,而不管该 key 的过期时间还没有到达。在删除时,
将按照过期时间进行删除,最早将要被过期的 key 将最先被删除。如果带有 expire 信息
的 key 都删光了,那么将返回错误。这样,redis 将不再接收写请求,只接收 get 请求。
maxmemory 的设置比较适合于把 redis 当作于类似 memcached 的缓存来使用。

appendonly
默认情况下,redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时
的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较
大范围的数据丢失。所以 redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。
开启 append only 模式之后,redis 会把所接收到的每一次写操作请求都追加到
appendonly.aof 文件中,当 redis 重新启动时,会从该文件恢复出之前的状态。但是这样
会造成 appendonly.aof 文件过大,所以 redis 还支持了 BGREWRITEAOF 指令,对
appendonly.aof 进行重新整理。所以我认为推荐生产环境下的做法为关闭镜像,开启
appendonly.aof,同时可以选择在访问较少的时间每天对 appendonly.aof 进行重写一次。

appendfsync
设置对 appendonly.aof 文件进行同步的频率。always 表示每次有写操作都进行同步,

everysec 
表示对写操作进行累积,每秒同步一次。这个需要根据实际业务场景进行配置

vm-enabled
是否开启虚拟内存支持。因为 redis 是一个内存数据库,而且当内存满的时候,无法接
收新的写请求,所以在 redis 2.0 中,提供了虚拟内存的支持。但是需要注意的是,redis
中,所有的 key 都会放在内存中,在内存不够时,只会把 value 值放入交换区。这样保
证了虽然使用虚拟内存,但性能基本不受影响,同时,你需要注意的是你要把vm-max-memory 设置到足够来放下你的所有的 key

vm-swap-file
设置虚拟内存的交换文件路径

vm-max-memory
这里设置开启虚拟内存之后,redis 将使用的最大物理内存的大小。默认为 0,redis 将
把他所有的能放到交换文件的都放到交换文件中,以尽量少的使用物理内存。在生产环
境下,需要根据实际情况设置该值,最好不要使用默认的 0

vm-page-size
设置虚拟内存的页大小,如果你的 value 值比较大,比如说你要在 value 中放置博客、
新闻之类的所有文章内容,就设大一点,如果要放置的都是很小的内容,那就设小一点。

vm-pages
设置交换文件的总的 page 数量,需要注意的是,page table 信息会放在物理内存中,每
8 个 page 就会占据 RAM 中的 1 个 byte。总的虚拟内存大小 = vm-page-size * vm-pages

vm-max-threads
设置 VM IO 同时使用的线程数量。因为在进行内存交换时,对数据有编码和解码的过
程,所以尽管 IO 设备在硬件上本上不能支持很多的并发读写,但是还是如果你所保存
的 vlaue 值比较大,将该值设大一些,还是能够提升性能的

glueoutputbuf
把小的输出缓存放在一起,以便能够在一个 TCP packet 中为客户端发送多个响应,具体
原理和真实效果我不是很清楚。所以根据注释,你不是很确定的时候就设置成 yes

hash-max-zipmap-entries
在 redis 2.0 中引入了 hash 数据结构。当 hash 中包含超过指定元素个数并且最大的元素
没有超过临界时,hash 将以一种特殊的编码方式(大大减少内存使用)来存储,这里
可以设置这两个临界值

activerehashing
开启之后,redis 将在每 100 毫秒时使用 1 毫秒的 CPU 时间来对 redis 的 hash 表进行重
新 hash,可以降低内存的使用。当你的使用场景中,有非常严格的实时性需要,不能
够接受 Redis 时不时的对请求有 2 毫秒的延迟的话,把这项配置为 no。如果没有这么严
格的实时性要求,可以设置为 yes,以便能够尽可能快的释放内存

String
set key value  添加一个key value
get key 获取一个key对应的value值
setnx key value 如果添加的key已经存在则不改变对应的值并返回0,如果key不存在则添加一个并返回1
setex key seconds value 添加一个有存在时间的key-value seconds单位为秒(s);
setrange key offset value 替换字符 key代表被替换的值的key 
offset代表从哪里开始替换(下标从0开始)如果从第6个开始 那么包含第6个
value 要替换的值
mset 设置多个key的值 mset key vlaue key value ...
get 获取keu对应的string值,如果key不存在那么返回nil
getset 设置key的值并返回旧值。
getrange key start end 获取指定key的value的子字符串 例如 getrange name 0 6   就是获取name的值并截取 0-6 前包后也包 小标从0开始,如果下表超出字符串长度,将默认为同方向的最大下标
mget key key1 key 2 ... 一次获取多个key,如果key不存在则返回对应的nil
incr 对key的值做加加操作,并返回新的值,如果incr一个不是int的value会返回错误,incr一个不存在的key则设置key为1
incrby key int 同incr类似,加指定值,可以不存在时候会设置key,并任务原来的value是0
decr 对key的值做减减操作,decr一个不存在的key,则设置key为-1
decrby key int 减去指定的值
append 给制定的key的字符串追加value,返回新字符串的长度
strlen 取指定key的value的长度
----------------------------------------hashes类型及操作------------------------------------
说明:类似java中hashMap 数组加链表的格式 详情请看redis设计与实现哈希表章节
hset key field value 设置hash 指定值  如果key不存在则先创建
hsetnx hashkey field value 设置hash制定值,如果key不存在则创建,如果field 已经存在,返回0 nx是 not exist的意思
hmset hashkey field1 value field2 value ...同时设置hash的多个field 返回ok
hget hashkey field 获取hashkey 指定fidld的值
hmget hashkey field field1 field2 获取指定的field的值 如果没有返回nil
hincrby hashkey field int 指定的hash field加上给定的值
hexists hashkey field 测试制定field是否存在 返回1代表存在  0代表不存在
hlen hashkey 返回指定hash的field数量
hkeys hashkey 返回所有hash的所有field
hvals hashkey 返回所有hash的value
hgetall hashkey 返回hash中全部的filed value
--------------------------list类型及操作----------------
说明:list是一个双端链表的结构 最常用的数据结构的一种 适用于增加和删除  详情请看redis设计与实现双端链表的实现原理
Redis 的 list 类型其实就是一个每个子元素都是 string 类型的双向链表。链表的最大长度是(2 的 32 次方)。
我们可以通过 push,pop 操作从链表的头部或者尾部添加删除元素。这使得 list 既可以用作栈,也可以用作队列.
有意思的是 list 的 pop 操作还有阻塞版本的,当我们[lr]pop 一个 list 对象时,
如果 list 是空, 或者不存在,会立即返回 nil。但是阻塞版本的 b[lr]pop 可以则可以阻塞,
当然可以加超时时 间,超时后也会返回 nil。为什么要阻塞版本的 pop 呢,主要是为了避免轮询。
举个简单的 例子如果我们用 list 来实现一个工作队列。
执行任务的 thread 可以调用阻塞版本的 pop 去获 取任务这样就可以避免轮询去检查是否有任务存在。
当任务来时候工作线程可以立即返回, 也可以避免轮询带来的延迟

lpush listkey value value1 ... 在list 头部添加字符串元素
rpush listkey value value1 ... 在key对应的list的尾部添加字符串元素
linsert listkey BEFORE|AFTER pivot value  在list的制定位置插入一个值 before从开始位置数 after从末尾开始数
lset listkey pivot 设置list中指定下表的元素值 ps:下标从0开始
lrem listkey count value 删除list中count个value相同的元素  count>0时 按从头到尾的顺序删除 反之 按从尾到头的顺序删除 count = 0 时 删除全部
ltrim listkey start stop 保留指定范围内的数据
lpop listkey 从list头部删除元素,并返回删除的元素
rpop listkey 从list尾部删除元素,并返回删除的元素
rpoplpush poplist pushlist 从list尾部删除元素并添加到第二个list的头部 ps:整个操作是原子的,如果第一个list是空或者不存在返回nil
lindex listkey 返回list中index位置的元素
llen listkey 返回list的长度
--------------------------------sets类型及操作--------------------------------------------------
set 是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,
有对多个集合 求交并差等操作,操作中 key 理解为集合的名字。 
不会有重复元素
Redis 的 set 是 string 类型的无序集合。set 元素最大可以包含(2 的 32 次方)个元素。 
 
set 的是通过 hash table 实现的,所以添加、删除和查找的复杂度都是 O(1)。
hash table 会随 着添加或者删除自动的调整大小。
需要注意的是调整 hash table 大小时候需要同步(获取写 锁)会阻塞其他读写操作
,可能不久后就会改用跳表(skip list)来实现,跳表已经在 sorted set 中使用了。
关于 set 集合类型除了基本的添加删除操作,其他有用的操作还包含集合的 
取并集(union),交集(intersection),差集(difference)。
通过这些操作可以很容易的实现 sns 中的好友推荐和 blog 的 tag 功能
-----------------------set相关命令----------------
sadd setkey value 向set中添加元素
smembers setkey 查看set中的全部元素
srem setkey value 删除set中value的元素
spop setkey 随机返回并删除set中的一个元素
sdiff setkey1 setkey2 返回所有给定setkey1 与 setkey2 的差集 ps  第一个和第二个比 例如 setkey1 (1,2,3,4) setkey2(3,4,5,6) 那么差集为1,2
sdiffstore setkey1 setkey2 setkey3 返回个给定setkey1与setkey2的差集,并将结果存放在setkey3中
sinter setkey1 setkey2 setkey3 ...返回给定key的所有的交集
sunion setkey setkey1 setkey2 ... 返回所有给定setkey的并集 ps:会去除重复后返回结果
sunionstore setkey setkey1 ... 返回所有给定setkey的并集,并将结果存放在另一个key中
smove setkey1 setkey2 value 从setkey1一处value 并添加到第二个setkey2中
scard setkey 返回setkey的元素个数
sismember setkey value 返回value是否在setkey中 存在返回1 不存在返回0
srandmember setkey count 随机从setkey返回count个元素,但不删除元素
-------------------sorted set 类型及操作------------------
sorted set 是 set 的一个升级版本,它在 set 的基础上增加了一个顺序属性,
这一属性在添加 修改元素的时候可以指定,每次指定后,zset 会自动重新按新的值调整顺序
。可以理解为有 两列的 mysql 表,一列存 value,一列存顺序。操作中 key 理解为 zset 的名字。
和 set 一样 sorted set 也是 string 类型元素的集合,不同的是每个元素都会关联一个 double 
类型的 score。sorted set 的实现是 skip list 和 hash table 的混合体。 
当元素被添加到集合中时,一个元素到 score 的映射被添加到 hash table 中,
所以给定一个 元素获取 score 的开销是 O(1),另一个 score 到元素的映射被添加到 skip list,并按照 score 排 序,
所以就可以有序的获取集合中的元素。添加,删除操作开销都是 O(log(N))和 skip list 的 开销一致,redis 的 skip list
实现用的是双向链表,这样就可以逆序从尾部取元素。
sorted set 最 经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为 score 存储,对象的 id 当元素存储
zadd setkey index value 向setkey中添加元素 index用于排序,如果该元素存在,怎根据最新score更新给元素顺序
zrem setkey value 从setkey中删除元素value
zincrby setkey index value 如果value在setkey中已存在,那么该元素score增加index 否则向集合中添加该元素,其score的值为index
zrank setkey  value 返回setkey中value的下标 ps下标 不是score 
zrevrank setkey value 返回setkey中value元素的下标 按score从大到小排序以后返回
zrevrange setkey start stop withscores 对setkey 按sccore从大到小排序 返回start 到 stop 的所有元素
zrangebyscore setkey start stop withscores 返回集合中score在给定区间的元素
zcount setkey start stop withscores 返回集合中score在给定区间的数量
zcard setkey 返回集合中元素的个数
zscore setkey value 返回value对于的score
zremrangebyrank setkey start stop withscores 删除set中 start到stop区间内的元素 ps下标
zremrangebyscore setkey start stop withscores 删除set中 start到stop区间内的元素 ps 排名 score

-------------------redis-command 命令-----------------------------------
keys pattern 返回满足给定表达式的所有key
exists key 确认一个key是否存在 存在返回1 否则 0
del key 删除一个key
expire key min  这是一个key min秒后过期
move 将当前数据库中的key转移到其他数据库中
persist key 移除给定key的过期时间
ttl key 查看一个key还有多久过期
randomkey 随机返回一个key空间的一个key
rename oldkey newkey 重命名key名字
type key 返回值的类型
ping 测试链接是否存活
echo 在命令行打印一些内容
select 选择数据库 redis数据库编号从0-15
quit 退出链接
dbsize 返回数据库中key的数目
info 获取服务器的信息和统计
monitor 调试命令  返回服务器处理的所有的命令
config get 获取服务器配置信息
flushdb 删除当前选择数据库中所有的key
flushall 删除所有数据库中所有的key

------------------主从复制------------------------
redis 主从复制配置和使用非常简单 通过主从复制可以允许多个 slave server 拥有和 master server 相同的数据库副本
特点:
1.master可以拥有多个slave
2.多个slave可以连接同一个master外,还可以链接到其他slave
3.主从复制不会阻塞master,在同步数据时,master可以继续出来client请求
3.提高系统的伸缩性
主从复制过程:
当配置好slave后,slave与master建立连接,然后发送sync命令。无论是第一次连接还是重新连接,master都会启动一个后台进程,
将数据库快照保存在文件中,同时master主进程会开始收集新的写命令并缓存,后台进程完成写文件后,master就发送文件
给slave,slave将文件保存到硬盘上,再加载到内存中,接着master就会把缓存的命令转发给slave,后续master将会受到的写命令发送给
slave。如果master同时受到多个slave发来的同步链接命令,master只会启动一个进程来写数据库镜像,然后发送给所有的slave
如何配置:
配置slave服务器 在slave的配置文件中加入配置
slaveof ip 端口 指定master的ip和端口
事务控制:
redis 对事务的控制的支持目前还是比较简单的。redis只能保证一个client发起事务中的命令可以连续的执行,而中间不会插入其他的
client的命令。由于redis是单线程来处理所有client的请求的所以做到这点是很容易的。一般情况下redis在接受到一个client发来的命令后悔立即处理
并返回结果,但是当一个client在一个连接中发出multi命令后,这个链接会进入一个事务上戏文,该链接后续的命令并不是立即执行
而是先放到一个队列中。当此连接接收到exec命令以后,redis会顺序的执行对列中的命令,并将返回命令的运行结果打包到一起返回给
client,然后此链接就结束事务上下文了。  当接受到discard时 会清空事务命令队列并退出事务上下文
乐观锁复杂事务控制
乐观锁:大多数是基于数据版本(version)的记录机制实现的。何谓数据版本?
即为数据增 加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个 “version”字段来实现读取出数据时
,将此版本号一同读出,之后更新时,对此版本号加 1。
 此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,
 如果提交的数据版 本号大于数据库表当前版本号,则予以更新,否则认为是过期数据
watch key 监视给定key,当exec时候如果监视的key从调用watch后发生了改变,则整个事物失败
如果链接断开,监视和食物都会被自动清除,exec,discard,unwatch命令都会清除连接中的所有监视
redis事务出现的问题
1.redis只能保证食物的每个命令的连续执行,如果事务中的一个命令失败,并不会回滚其他命令
redis持久化机制
redis是一个支持持久化的内存数据库 持久化的两种方式:一种 snapshotting 快照 默认方式 另一种 append-only file 方式
1.snapshotting 方式
快照是默认的持久化方式,这种方式就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb.可以通过配置
设置自动做快照持久化的方式。配置redis在n秒内如果超过m个key被修改就自动做快照
快照保存过程:
(1).redis调用fork,现在有子进程和父进程
(2).父进程继续处理client处理,子进程负责将内存内容写入到临时文件。由于os的实时复制机制 父子进程会共享相同的物理页面,
当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址控件的数据是fork时刻的一个快照
(3).当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进退出

client 可以调用save bgsave命令通知redis做一次快照持久化,save操作是在主进程上执行的,由于redis是用一个主线程来处理所有的
client请求  这样会造成阻塞以后的client请求,所以不推荐使用。另每一次快照持久化都是一次完整写完一次,并不是增量或只同步变更数据
如果数据量大的话,必然会引起大量的磁盘io操作,可能会严重影响性能 另外如果redis意外down掉的话,会失去最后一次快照保存
2.apf append-only file
aof 比快照方式有更好的持久化性,是由于在使用 aof 持久化方式时,redis 会将每一个收到 的写命令都通过 write 
函数追加到文件中(默认是 appendonly.aof)。当 redis 重启时会通过重 新执行文件中保存的写命令来在内存中重建
整个数据库的内容。当然由于 os 会在内核中缓 存 write 做的修改,所以可能不是立即写到磁盘上。这样 aof 方式
的持久化也还是有可能会 丢失部分修改。不过我们可以通过配置文件告诉 redis 我们想要通过 fsync 函数强制 os 
写入 到磁盘的时机。
有三种方式如下 默认是:每秒 fsync 一次)
appendonly yes         //启用 aof 持久化方式 
# appendfsync always    //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化 
appendfsync everysec   //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中 
# appendfsync no      //完全依赖 os,性能最好,持久化没保证 
aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用 incr test 命令 100 次,文件中必须保存全部的
 100 条命令,其实有 99 条都是多余的。因为要恢复数 据库的状态其实文件中保存一条 set test 100 就够了。为了压缩 aof 的
 持久化文件。redis 提 供了 bgrewriteaof 命令。收到此命令 redis 将使用与快照类似的方式将内存中的数据以命令 的方式保存到
 临时文件中,最后替换原来的文件。具体过程如下 
1、redis 调用 fork ,现在有父子两个进程 
2、子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令  
3、父进程继续处理 client 请求,除了把写命令写入到原来的 aof 文件中。同时把收到的写命 令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。 
4、当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然 后父进程把缓存的写命令也写入到临时文件。 
5、现在父进程可以使用临时文件替换老的 aof 文件,并重命名,后面收到的写命令也开始 往新的 aof 文件中追加。 
 
需要注意到是重写 aof 文件的操作,并没有读取旧的 aof 文件,
而是将整个内存中的数据库 内容用命令的方式重写了一个新的 aof 文件,这点和快照有点类似

pipeline 批量发送请求
解决每次命令每次请求的问题  可以把命令打包 然后一起执行  一起返回

虚拟内存的配置
说明:
首先说明下 redis 的虚拟内存与操作系统的虚拟内存不是一码事,但是思路和目的都是相同 的。
就是暂时把不经常访问的数据从内存交换到磁盘中,从而腾出宝贵的内存空间用于其他 需要访问
的数据。尤其是对于 redis 这样的内存数据库,内存总是不够用的。除了可以将数 据分割到多个
 redis server 外。另外的能够提高数据库容量的办法就是使用虚拟内存把那些 不经常访问的数
 据交换的磁盘上。如果我们的存储的数据总是有少部分数据被经常访问,大 部分数据很少被访问
 ,对于网站来说确实总是只有少量用户经常活跃。当少量数据被经常访 问时,使用虚拟内存不但
 能提高单台 redis server 数据库的容量,而且也不会对性能造成太 多影响
redis 没有使用操作系统提供的虚拟内存机制而是自己在实现了自己的虚拟内存机制,主要 的理由有两点: 
1、操作系统的虚拟内存是已 4k 页面为最小单位进行交换的。而 redis 的大多数对象都远小 于 4k,
所以一个操作系统页面上可能有多个 redis 对象。另外 redis 的集合对象类型如 list,set 可能存在
与多个操作系统页面上。最终可能造成只有 10%key 被经常访问,但是所有操作系 统页面都会被操作系
统认为是活跃的,这样只有内存真正耗尽时操作系统才会交换页面。 
2、相比于操作系统的交换方式,redis 可以将被交换到磁盘的对象进行压缩,保存到磁盘的对 象可以去除
指针和对象元数据信息,一般压缩后的对象会比内存中的对象小10倍,这样redis 的虚拟内存会比操作系统
虚拟内存能少做很多 io 操作

下面是 vm 相关配置 vm-enabled yes                       
#开启 vm 功能 vm-swap-file /tmp/redis.swap            
#交换出来的 value 保存的文件路径 vm-max-memory 1000000              
#redis 使用的最大内存上限 vm-page-size 32                      
#每个页面的大小 32 个字节 vm-pages 134217728                  
#最多使用多少页面 vm-max-threads 4                    
#用于执行 value 对象换入换出的工作线程数量 
 
redis 的虚拟内存在设计上为了保证 key 的查找速度,只会将 value 交换到 swap 文件中。
所 以如果是内存问题是由于太多 value 很小的 key 造成的,那么虚拟内存并不能解决,和
操作 系统一样 redis 也是按页面来交换对象的。redis 规定同一个页面只能保存一个对象。
但是一 个对象可以保存在多个页面中。在 redis 使用的内存没超过 vm-max-memory 之前是不
会交换 任何 value 的。当超过最大内存限制后,redis 会选择较过期的对象。如果两个对象一样
过期 会优先交换比较大的对象,精确的公式 swappability = age*log(size_in_memory)。对于 
vm-page-size 的设置应该根据自己的应用将页面的大小设置为可以容纳大多数对象的大小, 太
大了会浪费磁盘空间,太小了会造成交换文件出现碎片。对于交换文件中的每个页面,redis 会
在内存中对应一个 1bit 值来记录页面的空闲状态。所以像上面配置中页面数量(vm-pages 134217728 )
会占用 16M 内存用来记录页面空闲状态。vm-max-threads 表示用做交换任务的 线程数量。如果大于 0 
推荐设为服务器的 cpu 内核的数量,如果是 0 则交换过程在主线程进