Redis利用内存发挥的高性能读写在很多场景下大有所为,但是Redis本身毕竟还是一个单机数据库,如果系统对其属于强依赖,那么还是必须做好必要的容灾,针对这个问题,有以下几种策略:

一、M/S切换

由于Redis是单机数据库,所以针对MySQL的一些容灾方案也能顺利适用,例如当Redis意外宕机,可以将请求马上切到备库,同时快速恢复数据。


二、AOF

Redis有两种持久化的方式,分别是SnapShotting和Append-Only File,其原理和特性可以参考《对redis数据持久化的一些想法》一文,总得来说,快照对性能影响更小,也只会备份需要的数据,但两次快照中间的数据是没法保证一定会持久化的。

相比之下AOF的粒度更细,持久化效果更好,类似于MySQL的BinLog,缺点是会损失一部分性能,而且会记录不必要的日志,这一点当系统运行时间很长时会特别突出,也许恢复所有数据本来只要1个小时,却可能要花100甚至1000小时去搞。

三、读取数据源直接恢复

这个方案是和业务场景相关的,由于之前某个项目中Redis起到了存放索引的作用,所以利用MySQL的数据可以容易地重新建立Redis的所有内容,这里可以临时搞一个Trigger,不断读MySQL写Redis,利用MySQL的顺序读和Redis高TPS的特性,实践中,可以在几分钟内重建上千万的数据量。

目前Redis在功能上通常仍用于Cache,如果需要保证HA的持久化存储,请考虑具体场景,此外也可以考虑是否可以使用原生分布式的memcached或升级硬件(如SSD、Fusion-IO)增强原有DB的性能。    

我的应用里为了保证高性能,数据没有做dump,也没有用aof。因为不做dump发生的故障远远低于做dump的时候,即使数据丢失了,自动修复脚本可以马上数据恢复。毕竟对海量数据redis只能做数据分片,那么落到每个节点上的数据量也不会很多。

redis的虚拟内存建议也不要用,用redis本来就是为了达到变态的性能,虚拟内存、aof看起来都有些鸡肋。

现在还离不开redis,因为它的mget是现在所有db里性能最好的,以前也考虑过用tokyocabinet hash方式做mget,性能不给力。直接用redis,基本上单个redis节点mget可以达到10W/s 

从这个图中可以看出:

  1) 对于没有持久化的方式,读写都在数据量达到800万的时候,性能下降几倍,此时正好是达到内存10G,Redis开始换出到磁盘的时候。并且从那以后再也没办法重新振作起来,性能比Mongodb还要差很多。

  2) 对于AOF持久化的方式,总体性能并不会比不带持久化方式差太多,都是在到了千万数据量,内存占满之后读的性能只有几百。

  3) 对于Dump持久化方式,读写性能波动都比较大,可能在那段时候正在Dump也有关系,并且在达到了1400万数据量之后,读写性能贴底了。在Dump的时候,不会进行换出,而且所有修改的数据还是创建的新页,内存占用比平时高不少,超过了15GB。而且Dump还会压缩,占用了大量的CPU。也就是说,在那个时候内存、磁盘和CPU的压力都接近极限,性能不差才怪。

  总结一下:

  1) Redis其实只适合作为缓存,而不是数据库或是存储。它的持久化方式适用于救救急啥的,不太适合当作一个普通功能来用。对于这个版本的Redis,不建议使用任何的持久化方式。否则到时候可能会死的比较难看。说白了,期望Redis是memcached的升级版,带有各种数据结构,但是不要期望 Redis来和Mongodb/Kt等来比。

  2) 对于VM其实也是不建议开启,虽然开启VM可以让Redis保存比内存更多的数据,但是如果冷热数据不是很明显的话性能会非常差(我的测试都是随机查询 Key,冷热不明显)。当然,对于冷热明显的情况下可以设置200% - 400%的内存作为VM空间,也不建议设置10倍的内存空间作为VM(像我的配置一样)。

  3) ServiceStack.Redis客户端好像有几个Bug,首先RedisTypedClient的Dispose居然没有实现,应该是要调用 client.Dispose(),其次RedisNativeClient的Info属性不是每次都获取最新值的,第三 PooledRedisClientManager的WritePoolIndex和ReadPoolIndex只看到加没看到减的地方,也不知道这是干啥的,其实每次都取第一个不是Active的Client就可以了,PooledRedisClientManager也没有把超时使用的Active的 Client强制回收(避免使用的时候忘记Dispose占用过多的连接)。