http://blog.csdn.net/mengxianhua/article/details/8961713
按照Redis启动时的提醒,设置 vm.overcommit_memory = 1 ,使得fork()一条10G的进程时,因为COW策略而不一定需要有10G的free memory.
当最大内存到达时,按照配置的Policy进行处理, 默认policy为volatile-lru, 对设置了expire time的key进行LRU清除(不是按实际expire time)。如果沒有数据设置了expire time或者policy为noeviction,则直接报错,但此时系统仍支持get之类的读操作。 另外还有几种policy,比如volatile-ttl按最接近expire time的,allkeys-lru对所有key都做LRU。
原来2.0版的VM(将Value放到磁盘,Key仍然放在内存),2.4版后又不支持了。
内存占用:
测试表明,stirng类型需要90字节的额外代价,就是说key1个字节,value一个字节时,还是需要占用92字节的长度,而上述的benchmark的记录就占用了239个字节。
用make 32bit可以编译出32位的版本,每个指针占用的内存更小,但只支持最大4GB内存。
Sharding:
Jedis支持在客户端做分区,局限是不能动态re-sharding, 有分区的master倒了,必须用slave顶上。要增加分区的话,呃.....
Redis-Cluster是今年工作重点,支持automatic re-sharding, 采用和Hazelcast类似的算法,总共有N个分区,每台Server负责若干个分区。客户端先hash出key 属于哪个分区,然后发给负责这个分区的Server。Re-sharding时,会将某些分区的数据移到新的Server上,然后各Server周知分区<->Server映射的变化,因为分区数量有限,所以通讯量不大。 在迁移过程中,原server对于已经迁移走的数据的get请求,会回一个临时转向的应答。
5. 高可用性
5.1 持久化
综述: 解密Redis持久化(中文概括版),英文原版
RDB文件:
整个内存的压缩过的Snapshot,RDB的数据结构, 可以配置写Snapshot的复合触发条件,默认是60秒内改了1万次或300秒内改了10次或900秒内改了1次。
RDB在写入过程中,会连内存一起Fork出一个新进程,遍历新进程内存中的数据写RDB。
先写到临时文件再Rename,这样外部程序对RDB文件的备份和传输过程是安全的。而且即使写新快照的过程中Server被强制关掉了,旧的RDB文件还在。
可配置是否进行压缩,方法是是字符串的LZF算法 和String形式的数字变回int形式存储。
AOF文件:
append only的操作日志,等于mysql的binlog,记录所有有效的写操作,格式是明文的Redis协议的纯文本文件。
一般配置成每秒调用一次fsync将数据写到磁盘,坏处是操作系统非正常关机时,可能会丢1秒的数据。 如果设为fsync always,性能只剩几百TPS,不用考虑。
如果使用了AOF,重启时只会从AOF文件载入数据,不会管RDB文件。
AOF文件过大时,会fork出一条新进程来将文件重写(也是先写临时文件再rename), 遍历新进程的内存中数据,每条记录有一条的Set语句。默认配置是当AOF文件大小是上次rewrite后的大小的一倍时触发。
Redis协议的内容,如set mykey hello, 将持久化成*3 $3 set $5 mykey $5 hello, 第一个数字代表这条语句有多少元,其他的数字代表后面字符串的长度。这样的设计,使得即使在写文件过程中突然关机导致文件不完整,也能自我修复,执行redis-check-aof即可。
RDB不会实时写入数据,而且如果同时使用两者,但服务器重启只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库,快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
读写性能:
AOF重写和RDB写入都是在fork出进程后,遍历新进程内存顺序写的,既不影响主进程,顺序写的速度也比随机写快,在普通PC服务器上把刚才的1.5G数据写成一个200M的RDB文件大约8秒, 启动时载入一个1.4G的AOF文件大约13秒。
2.4版以后,lpush可以一次push多个值了,使得AOF重写时可以将旧版本中的多个lpush指令合成一个。
有人建议设置no-appendfsync-on-rewrite 为 yes,aof rewrite时就不执行fsync了,先都存在内存里,减少IO资源争用。 当然这样会丢数据。
Fork一个使用了大量内存的进程也要时间,大约10ms per GB的样子,各种系统的对比。
其他:
正确关闭服务器:redis-cli shutdown 或者 kill,都会graceful shutdown,保证写RDB文件以及将AOF文件fsync到磁盘,不会丢失数据。 如果是Ctrl+C,或者kill -9 就会丢失数据。
执行指令bgsave 可触发rdb存盘,bgrewriteaof可触发aof重写。
5.2 Master-Slave复制
可以在配置文件、命令行参数、以及执行SLAVEOF指令的来设置。
当前版本,一旦执行SlaveOF, slave会清掉自己的所有数据,执行一次全同步:Master要bgsave出自己的一个RDB文件,发给Slave。然后再增量同步: Master作为一个普通的client连入slave,将所有写操作转发给slave,没有特殊的同步协议。
作者在2.8版本中将支持PSYNC部分同步
测试表明同步延时非常小。
有建议只在Slave上写RDB和AOF文件,但这样master启动时就需要从slave copy文件,fail-over脚本也更复杂。只要有足够内存,master平时IO也不高的话,还是简化架构更好。
5.3 Fail-Over
5.3.1 概述
Redis-sentinel是2.6版开始加入的另一组独立运行的节点, 提供自动Fail Over的支持。
每秒钟对所有master,slave和其他sentinel执行ping,redis-server节点要应答+PONG或-LOADING或-MASTERDOWN.
如果某一台Sentinel没有在30秒内(可配置得短一些哦)收到上述正确应答,它就会认为master处于sdown状态(主观Down)
它向其他sentinel询问是否也认为master倒了(SENTINEL is-master-down-by-addr ), 如果quonum台(默认是2)sentinels在5秒钟内都这样认为,就会认为master真是odown了(客观Down)。
此时会选出一台sentinel作为Leader执行fail-over, Leader会从slave中选出一个提升为master(执行slaveof none),这台slave必须状态正常,而且INFO显示它与master的复制连接并没有断开太久。然后让其他slave指向它(执行slaveof new master)。
5.3.2 master/slave 及 其他sentinels的发现
master地址在sentinel的配置文件里, sentinel会每10秒一次向master发送INFO,知道master的slave有哪些。 如果master已经变为slave,sentiel会分析INFO的应答指向新的master。所以当sentiel重启时,它的配置文件里master的地址并没变,那它仍然会去找old master,然后被redirect到新的master。但如果old master还没起来,或者old master没把自己变成slave,悲剧就可能发生。
另外,sentinel会在master上建一个pub/sub channel,通告各种信息,比如+sdown/-sdown, 而且sentinel们也是通过接收pub/sub channel上的+sentinel的信息发现彼此,因为每台sentinel每5秒会发送一次__sentinel__:hello,宣告自己的存在。
5.3.3 自定义脚本
sentinel在failover时还会执行配置文件里指定的用户reconfig脚本,让master变为slave并指向新的master。
脚本在如下时机被调用: 1. slave开始提升成master,2.所有slave都已指向新master,3.各种原因提升被终止。
脚本的将会在命令行按顺序传入如下参数: <master-name> <role(leader/observer)> <state(上述三种情况)> <from-ip> <from-port> <to-ip> <to-port>
脚本返回0是正常,如果返回1会被重新执行,如果返回2或以上不会。 如果超过60秒没返回会被强制终止。
另一种notify脚本在收到任何pub/sub信息时都会调用,让你去通知O&M系统。
5.3.4 Client集成
client中执行语句SENTINEL get-master-addr-by-name mymaster 可获得当前master的地址。 但是Jedis还没集成sentinel,只有一个热心网友提交了pull request
淘宝的Tedis driver,使用了完全不同的思路,不基于Sentinel,而是多写随机读,学术名词是ReadOne-WriteAll-tx(see NoSQL数据库的分布式算法), 一开始就同步写入到所有节点,读的话随便读一个还活着的节点就行了。(但节点死掉重新起来后怎么重新同步?什么时候可以重新作为一个可选的master?)
Redis作者也在博客里抱怨怎么没有人做Dynamo-style 的client。
5.4 Geographic-Redundancy
一个方法是用rsync等工具同步RDB文件,但RDB文件是非常不实时的。
如果要求更高,可以自己写程序读取AOF文件或MONITOR,把指令转发给远处的站点,反正里头的内容就是Redis协议。
6. 维护
配置
可以在配置文件中编写, 也可以在启动时的命令行配置, 如redis-server --port 7777 --slaveof 127.0.0.1 8888,还可以在cli中执行CONFIG GET, 可以达到不重启服务的修改配置参数的效果。
监控
Redis监控技巧 有详细的介绍。
INFO指令将返回非常丰富的信息。
着重监控检查内存使用,比如是否已接近上限,比如有无大量使用swap(used_memory - used_memory_rss)
还有AOF与RDB文件的保存情况,master-slave的关系也要重点监控。
STAT中信息还包括key命中率,所有命令的执行次数,所有client连接数量等, CONFIG RESETSTAT 可重置。
其他
SlowLog 检查慢操作(见2.性能)
配置sentinel的notify.sh脚本对所有事件告警或自己用PING/INFO监控节点状态(见5.3.3)
MONITOR可以显示Server收到的所有指令,可以用于debug。
Redis live, 基于Python的DashBoard,使用INFO和MONITOR获得系统情况和指令统计分析。
Instagram的Redis Faina,基于Python,使用MONITOR对指令进行统计分析.
Redis-rdb-tools 基于Python,可以分析RDB文件,比如每条Key对应value所占的大小,还可以将RDB dump成文本文件然后进行比较,还可以将RDB输出成JSON格式。
Redis作者自己写的Redis Sampler,基于Ruby,统计数据分布情况。
维护
用redis-check-aof/redis-check-dump 修复烂掉的文件。
在系统闲时调用 bgrewriteaof 重写AOF文件。
7. 其他
过期数据清除 ,过期数据的清除从来不容易,Redis使用了一种相对务实的做法
当client主动get的时候会先进行判断。
如果clien永远都不再get那条key呢? 它会在后台,每秒10次的执行如下操作: 随机选取100个key校验是否过期,如果有25个以上的key过期了,立刻随机选取下100个key,可见如果数据不被主动get,它什么时候最终被清理掉是未知的。
上述主动清理只会在master进行,slave们会收到从master发过来的DEL指令,master的AOF文件也会插入一条DEL。
Redis如何处理客户端连接
8. Java Driver
各个Driver好像只有Jedis比较活跃。
不需要Spring Data Redis的封装,因为Jedis已足够简单,所以它没有像对MongoDB java driver的封装那样能简化代码,所谓屏蔽各种底层driver的差异并不太吸引人,因为我就没打算选其他几种driver。
Jedis基于Apache Commons Pool做的连接池,默认最大连接数只有8,一般需要重新设置。
9. Windows的版本
Windows版本方便单机调测,但Redis并没有提供,好在微软提供了一个,暂时基于Redis 2.4版本。 https://github.com/MSOpenTech/redis 因为github现在已经没有Download服务了,所以编译好的可执行文件藏在这里 https://github.com/MSOpenTech/redis/tree/2.4/msvs/bin/release
原文出处:https://github.com/springside/springside4/wiki/redis
TechTarget中国原创内容,原文链接:http://www.searchdatabase.com.cn/showcontent_70423.htm
当最大内存到达时,按照配置的Policy进行处理, 默认policy为volatile-lru, 对设置了expire time的key进行LRU清除(不是按实际expire time)。如果沒有数据设置了expire time或者policy为noeviction,则直接报错,但此时系统仍支持get之类的读操作。 另外还有几种policy,比如volatile-ttl按最接近expire time的,allkeys-lru对所有key都做LRU。
原来2.0版的VM(将Value放到磁盘,Key仍然放在内存),2.4版后又不支持了。
内存占用:
测试表明,stirng类型需要90字节的额外代价,就是说key1个字节,value一个字节时,还是需要占用92字节的长度,而上述的benchmark的记录就占用了239个字节。
用make 32bit可以编译出32位的版本,每个指针占用的内存更小,但只支持最大4GB内存。
Sharding:
Jedis支持在客户端做分区,局限是不能动态re-sharding, 有分区的master倒了,必须用slave顶上。要增加分区的话,呃.....
Redis-Cluster是今年工作重点,支持automatic re-sharding, 采用和Hazelcast类似的算法,总共有N个分区,每台Server负责若干个分区。客户端先hash出key 属于哪个分区,然后发给负责这个分区的Server。Re-sharding时,会将某些分区的数据移到新的Server上,然后各Server周知分区<->Server映射的变化,因为分区数量有限,所以通讯量不大。 在迁移过程中,原server对于已经迁移走的数据的get请求,会回一个临时转向的应答。
5. 高可用性
5.1 持久化
综述: 解密Redis持久化(中文概括版),英文原版
RDB文件:
整个内存的压缩过的Snapshot,RDB的数据结构, 可以配置写Snapshot的复合触发条件,默认是60秒内改了1万次或300秒内改了10次或900秒内改了1次。
RDB在写入过程中,会连内存一起Fork出一个新进程,遍历新进程内存中的数据写RDB。
先写到临时文件再Rename,这样外部程序对RDB文件的备份和传输过程是安全的。而且即使写新快照的过程中Server被强制关掉了,旧的RDB文件还在。
可配置是否进行压缩,方法是是字符串的LZF算法 和String形式的数字变回int形式存储。
AOF文件:
append only的操作日志,等于mysql的binlog,记录所有有效的写操作,格式是明文的Redis协议的纯文本文件。
一般配置成每秒调用一次fsync将数据写到磁盘,坏处是操作系统非正常关机时,可能会丢1秒的数据。 如果设为fsync always,性能只剩几百TPS,不用考虑。
如果使用了AOF,重启时只会从AOF文件载入数据,不会管RDB文件。
AOF文件过大时,会fork出一条新进程来将文件重写(也是先写临时文件再rename), 遍历新进程的内存中数据,每条记录有一条的Set语句。默认配置是当AOF文件大小是上次rewrite后的大小的一倍时触发。
Redis协议的内容,如set mykey hello, 将持久化成*3 $3 set $5 mykey $5 hello, 第一个数字代表这条语句有多少元,其他的数字代表后面字符串的长度。这样的设计,使得即使在写文件过程中突然关机导致文件不完整,也能自我修复,执行redis-check-aof即可。
RDB不会实时写入数据,而且如果同时使用两者,但服务器重启只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库,快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
读写性能:
AOF重写和RDB写入都是在fork出进程后,遍历新进程内存顺序写的,既不影响主进程,顺序写的速度也比随机写快,在普通PC服务器上把刚才的1.5G数据写成一个200M的RDB文件大约8秒, 启动时载入一个1.4G的AOF文件大约13秒。
2.4版以后,lpush可以一次push多个值了,使得AOF重写时可以将旧版本中的多个lpush指令合成一个。
有人建议设置no-appendfsync-on-rewrite 为 yes,aof rewrite时就不执行fsync了,先都存在内存里,减少IO资源争用。 当然这样会丢数据。
Fork一个使用了大量内存的进程也要时间,大约10ms per GB的样子,各种系统的对比。
其他:
正确关闭服务器:redis-cli shutdown 或者 kill,都会graceful shutdown,保证写RDB文件以及将AOF文件fsync到磁盘,不会丢失数据。 如果是Ctrl+C,或者kill -9 就会丢失数据。
执行指令bgsave 可触发rdb存盘,bgrewriteaof可触发aof重写。
5.2 Master-Slave复制
可以在配置文件、命令行参数、以及执行SLAVEOF指令的来设置。
当前版本,一旦执行SlaveOF, slave会清掉自己的所有数据,执行一次全同步:Master要bgsave出自己的一个RDB文件,发给Slave。然后再增量同步: Master作为一个普通的client连入slave,将所有写操作转发给slave,没有特殊的同步协议。
作者在2.8版本中将支持PSYNC部分同步
测试表明同步延时非常小。
有建议只在Slave上写RDB和AOF文件,但这样master启动时就需要从slave copy文件,fail-over脚本也更复杂。只要有足够内存,master平时IO也不高的话,还是简化架构更好。
5.3 Fail-Over
5.3.1 概述
Redis-sentinel是2.6版开始加入的另一组独立运行的节点, 提供自动Fail Over的支持。
每秒钟对所有master,slave和其他sentinel执行ping,redis-server节点要应答+PONG或-LOADING或-MASTERDOWN.
如果某一台Sentinel没有在30秒内(可配置得短一些哦)收到上述正确应答,它就会认为master处于sdown状态(主观Down)
它向其他sentinel询问是否也认为master倒了(SENTINEL is-master-down-by-addr ), 如果quonum台(默认是2)sentinels在5秒钟内都这样认为,就会认为master真是odown了(客观Down)。
此时会选出一台sentinel作为Leader执行fail-over, Leader会从slave中选出一个提升为master(执行slaveof none),这台slave必须状态正常,而且INFO显示它与master的复制连接并没有断开太久。然后让其他slave指向它(执行slaveof new master)。
5.3.2 master/slave 及 其他sentinels的发现
master地址在sentinel的配置文件里, sentinel会每10秒一次向master发送INFO,知道master的slave有哪些。 如果master已经变为slave,sentiel会分析INFO的应答指向新的master。所以当sentiel重启时,它的配置文件里master的地址并没变,那它仍然会去找old master,然后被redirect到新的master。但如果old master还没起来,或者old master没把自己变成slave,悲剧就可能发生。
另外,sentinel会在master上建一个pub/sub channel,通告各种信息,比如+sdown/-sdown, 而且sentinel们也是通过接收pub/sub channel上的+sentinel的信息发现彼此,因为每台sentinel每5秒会发送一次__sentinel__:hello,宣告自己的存在。
5.3.3 自定义脚本
sentinel在failover时还会执行配置文件里指定的用户reconfig脚本,让master变为slave并指向新的master。
脚本在如下时机被调用: 1. slave开始提升成master,2.所有slave都已指向新master,3.各种原因提升被终止。
脚本的将会在命令行按顺序传入如下参数: <master-name> <role(leader/observer)> <state(上述三种情况)> <from-ip> <from-port> <to-ip> <to-port>
脚本返回0是正常,如果返回1会被重新执行,如果返回2或以上不会。 如果超过60秒没返回会被强制终止。
另一种notify脚本在收到任何pub/sub信息时都会调用,让你去通知O&M系统。
5.3.4 Client集成
client中执行语句SENTINEL get-master-addr-by-name mymaster 可获得当前master的地址。 但是Jedis还没集成sentinel,只有一个热心网友提交了pull request
淘宝的Tedis driver,使用了完全不同的思路,不基于Sentinel,而是多写随机读,学术名词是ReadOne-WriteAll-tx(see NoSQL数据库的分布式算法), 一开始就同步写入到所有节点,读的话随便读一个还活着的节点就行了。(但节点死掉重新起来后怎么重新同步?什么时候可以重新作为一个可选的master?)
Redis作者也在博客里抱怨怎么没有人做Dynamo-style 的client。
5.4 Geographic-Redundancy
一个方法是用rsync等工具同步RDB文件,但RDB文件是非常不实时的。
如果要求更高,可以自己写程序读取AOF文件或MONITOR,把指令转发给远处的站点,反正里头的内容就是Redis协议。
6. 维护
配置
可以在配置文件中编写, 也可以在启动时的命令行配置, 如redis-server --port 7777 --slaveof 127.0.0.1 8888,还可以在cli中执行CONFIG GET, 可以达到不重启服务的修改配置参数的效果。
监控
Redis监控技巧 有详细的介绍。
INFO指令将返回非常丰富的信息。
着重监控检查内存使用,比如是否已接近上限,比如有无大量使用swap(used_memory - used_memory_rss)
还有AOF与RDB文件的保存情况,master-slave的关系也要重点监控。
STAT中信息还包括key命中率,所有命令的执行次数,所有client连接数量等, CONFIG RESETSTAT 可重置。
其他
SlowLog 检查慢操作(见2.性能)
配置sentinel的notify.sh脚本对所有事件告警或自己用PING/INFO监控节点状态(见5.3.3)
MONITOR可以显示Server收到的所有指令,可以用于debug。
Redis live, 基于Python的DashBoard,使用INFO和MONITOR获得系统情况和指令统计分析。
Instagram的Redis Faina,基于Python,使用MONITOR对指令进行统计分析.
Redis-rdb-tools 基于Python,可以分析RDB文件,比如每条Key对应value所占的大小,还可以将RDB dump成文本文件然后进行比较,还可以将RDB输出成JSON格式。
Redis作者自己写的Redis Sampler,基于Ruby,统计数据分布情况。
维护
用redis-check-aof/redis-check-dump 修复烂掉的文件。
在系统闲时调用 bgrewriteaof 重写AOF文件。
7. 其他
过期数据清除 ,过期数据的清除从来不容易,Redis使用了一种相对务实的做法
当client主动get的时候会先进行判断。
如果clien永远都不再get那条key呢? 它会在后台,每秒10次的执行如下操作: 随机选取100个key校验是否过期,如果有25个以上的key过期了,立刻随机选取下100个key,可见如果数据不被主动get,它什么时候最终被清理掉是未知的。
上述主动清理只会在master进行,slave们会收到从master发过来的DEL指令,master的AOF文件也会插入一条DEL。
Redis如何处理客户端连接
8. Java Driver
各个Driver好像只有Jedis比较活跃。
不需要Spring Data Redis的封装,因为Jedis已足够简单,所以它没有像对MongoDB java driver的封装那样能简化代码,所谓屏蔽各种底层driver的差异并不太吸引人,因为我就没打算选其他几种driver。
Jedis基于Apache Commons Pool做的连接池,默认最大连接数只有8,一般需要重新设置。
9. Windows的版本
Windows版本方便单机调测,但Redis并没有提供,好在微软提供了一个,暂时基于Redis 2.4版本。 https://github.com/MSOpenTech/redis 因为github现在已经没有Download服务了,所以编译好的可执行文件藏在这里 https://github.com/MSOpenTech/redis/tree/2.4/msvs/bin/release
原文出处:https://github.com/springside/springside4/wiki/redis
TechTarget中国原创内容,原文链接:http://www.searchdatabase.com.cn/showcontent_70423.htm