前几天微博发生了一块儿大的系统故障,不少技术的朋友都比较关心,其中的缘由不会超出James Hamilton在On Designing and Deploying Internet-Scale Service(1)归纳的那几个范围,James第一条经验“Design for failure”是全部互联网架构成功的一个关键。互联网系统的工程理论其实很是简单,James paper中内容几乎称不上理论,而是多条实践经验分享,每一个公司对这些经验的理解及执行力决定了架构成败。html
题外话说完,最近又研究了Redis。去年曾作过一个MemcacheDB, Tokyo Tyrant, Redis performance test,到目前为止,这个benchmark结果依然有效。这1年咱们经历了不少眼花缭乱的key value存储产品的诱惑,从Cassandra的淡出(Twitter暂停在主业务使用)到HBase的兴起(Facebook新的邮箱业务选用HBase(2)),当再回头再去看Redis,发现这个只有1万多行源代码的程序充满了神奇及大量未经挖掘的特性。Redis性能惊人,国内前十大网站的子产品估计用1台Redis就能够知足存储及Cache的需求。除了性能印象以外,业界其实广泛对Redis的认识存在必定误区。本文提出一些观点供你们探讨。redis
这个问题的结果影响了咱们怎么用Redis。若是你认为Redis是一个key value store, 那可能会用它来代替MySQL;若是认为它是一个能够持久化的cache, 可能只是它保存一些频繁访问的临时数据。Redis是REmote DIctionary Server的缩写,在Redis在官方网站的的副标题是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,这个定义偏向key value store。还有一些见解则认为Redis是一个memory database,由于它的高性能都是基于内存操做的基础。另一些人则认为Redis是一个data structure server,由于Redis支持复杂的数据特性,好比List, Set等。对Redis的做用的不一样解读决定了你对Redis的使用方式。数据库
互联网数据目前基本使用两种方式来存储,关系数据库或者key value。可是这些互联网业务自己并不属于这两种数据类型,好比用户在社会化平台中的关系,它是一个list,若是要用关系数据库存储就须要转换成一种多行记录的形式,这种形式存在不少冗余数据,每一行须要存储一些重复信息。若是用key value存储则修改和删除比较麻烦,须要将所有数据读出再写入。Redis在内存中设计了各类数据类型,让业务可以高速原子的访问这些数据结构,而且不须要关心持久存储的问题,从架构上解决了前面两种存储须要走一些弯路的问题。设计模式
不少开发者都认为Redis不可能比Memcached快,Memcached彻底基于内存,而Redis具备持久化保存特性,即便是异步的,Redis也不可能比Memcached快。可是测试结果基本是Redis占绝对优点。一直在思考这个缘由,目前想到的缘由有这几方面。数据结构
Redis的数据所有放在内存带来了高速的性能,可是也带来一些不合理之处。好比一个中型网站有100万注册用户,若是这些资料要用Redis来存储,内存的容量必须可以容纳这100万用户。可是业务实际状况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,所以所有100万用户的数据都放在内存有不合理之处,RAM须要为冷数据买单。架构
这跟操做系统很是类似,操做系统全部应用访问的数据都在内存,可是若是物理内存容纳不下新的数据,操做系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操做系统给应用提供的并非物理内存,而是虚拟内存(Virtual Memory)的概念。并发
基于相同的考虑,Redis 2.0也增长了VM特性。让Redis数据容量突破了物理内存的限制。并实现了数据冷热分离。app
Redis的VM依照以前的epoll实现思路依旧是本身实现。可是在前面操做系统的介绍提到OS也能够自动帮程序实现冷热数据分离,Redis只须要OS申请一块大内存,OS会自动将热数据放入物理内存,冷数据交换到硬盘,另一个知名的“理解了现代操做系统(3)”的Varnish就是这样实现,也取得了很是成功的效果。异步
做者antirez在解释为何要本身实现VM中提到几个缘由(6)。主要OS的VM换入换出是基于Page概念,好比OS VM1个Page是4K, 4K中只要还有一个元素即便只有1个字节被访问,这个页也不会被SWAP, 换入也一样道理,读到一个字节可能会换入4K无用的内存。而Redis本身实现则能够达到控制换入的粒度。另外访问操做系统SWAP内存区域时block进程,也是致使Redis要本身实现VM缘由之一。oop
做为一个key value存在,不少开发者天然的使用set/get方式来使用Redis,实际上这并非最优化的使用方法。尤为在未启用VM状况下,Redis所有数据须要放入内存,节约内存尤为重要。
假如一个key-value单元须要最小占用512字节,即便只存一个字节也占了512字节。这时候就有一个设计模式,能够把key复用,几个key-value放入一个key中,value再做为一个set存入,这样一样512字节就会存放10-100倍的容量。
这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis,详细方法见参考文献(7)。
Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化以后若是出现crash则会丢失一段数据。所以在完美主义者的推进下做者增长了aof方式。aof即append only mode,在写入内存数据的同时将操做命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个很是庞大的数据,管理维护成本很是高,恢复重建时间会很是长,这样致使失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,全部的优点都是创建在对内存复杂数据结构高效的原子操做上,这样就看出aof是一个很是不协调的部分。
其实aof目的主要是数据可靠性及高可用性,在Redis中有另一种方法来达到目的:Replication。因为Redis的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。
要想成功使用一种产品,咱们须要深刻了解它的特性。Redis性能突出,若是可以熟练的驾驭,对国内不少大型应用具备很大帮助。但愿更多同行加入到Redis使用及代码研究行列。