redis应用场景

1.  MySql+Memcached架构的问题html

 

  实际MySQL是适合进行海量数据存储的,经过Memcached将热点数据加载到cache,加速访问,不少公司都曾经使用过这样的架构,但随着业务数据量的不断增长,和访问量的持续增加,咱们遇到了不少问题:ios

  1.MySQL须要不断进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工做占据大量开发时间。redis

  2.Memcached与MySQL数据库数据一致性问题。算法

  3.Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL没法支撑。sql

  4.跨机房cache同步问题。mongodb

  众多NoSQL百花齐放,如何选择数据库

  最近几年,业界不断涌现出不少各类各样的NoSQL产品,那么如何才能正确地使用好这些产品,最大化地发挥其长处,是咱们须要深刻研究和思考的问题,实际归根结底最重要的是了解这些产品的定位,而且了解到每款产品的tradeoffs,在实际应用中作到扬长避短,整体上这些NoSQL主要用于解决如下几种问题json

  1.少许数据存储,高速读写访问。此类产品经过数据所有in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景。后端

  2.海量数据存储,分布式系统支持,数据一致性保证,方便的集群节点添加/删除。api

  3.这方面最具表明性的是dynamo和bigtable 2篇论文所阐述的思路。前者是一个彻底无中心的设计,节点之间经过gossip方式传递集群信息,数据保证最终一致性,后者是一个中心化的方案设计,经过相似一个分布式锁服务来保证强一致性,数据写入先写内存和redo log,而后按期compat归并到磁盘上,将随机写优化为顺序写,提升写入性能。

  4.Schema free,auto-sharding等。好比目前常见的一些文档数据库都是支持schema-free的,直接存储json格式数据,而且支持auto-sharding等功能,好比mongodb。

  面对这些不一样类型的NoSQL产品,咱们须要根据咱们的业务场景选择最合适的产品。

       Redis最适合全部数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差异,那么可能你们就会有疑问,彷佛Redis更像一个增强版的Memcached,那么什么时候使用Memcached,什么时候使用Redis呢?

       若是简单地比较Redis与Memcached的区别,大多数都会获得如下观点:

     1 、Redis不只仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
     2 、Redis支持数据的备份,即master-slave模式的数据备份。
     3 、Redis支持数据的持久化,能够将内存中的数据保持在磁盘中,重启的时候能够再次加载进行使用。

 

 

2.  Redis经常使用数据类型

Redis最为经常使用的数据类型主要有如下:

  • String
  • Hash
  • List
  • Set
  • Sorted set
  • pub/sub
  • Transactions

在具体描述这几种数据类型以前,咱们先经过一张图了解下Redis内部内存管理中是如何描述这些不一样数据类型的:

         首先Redis内部使用一个redisObject对象来表示全部的key和value,redisObject最主要的信息如上图所示:

         type表明一个value对象具体是何种数据类型,

         encoding是不一样数据类型在redis内部的存储方式,

         好比:type=string表明value存储的是一个普通字符串,那么对应的encoding能够是raw或者是int,若是是int则表明实际redis内部是按数值型类存储和表示这个字符串的,固然前提是这个字符串自己能够用数值表示,好比:"123" "456"这样的字符串。

       这里须要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的,该功能会在后面具体描述。经过上图咱们能够发现Redis使用redisObject来表示全部的key/value数据是比较浪费内存的,固然这些内存管理成本的付出主要也是为了给Redis不一样数据类型提供一个统一的管理接口,实际做者也提供了多种方法帮助咱们尽可能节省内存使用,咱们随后会具体讨论。

 

 

 

3.  各类数据类型应用和实现方式

下面咱们先来逐一的分析下这7种数据类型的使用和内部实现方式:

  • String:
Strings 数据结构是简单的key-value类型,value其实不只是String,也能够是数字.

经常使用命令:  set,get,decr,incr,mget 等。

 

应用场景:String是最经常使用的一种数据类型,普通的key/ value 存储均可以归为此类.便可以彻底实现目前 Memcached 的功能,而且效率更高。还能够享受Redis的定时持久化,操做日志及 Replication等功能。除了提供与 Memcached 同样的get、set、incr、decr 等操做外,Redis还提供了下面一些操做:

 

 

    • 获取字符串长度
    • 往字符串append内容
    • 设置和获取字符串的某一段内容
    • 设置及获取字符串的某一位(bit)
    • 批量设置一系列字符串的内容

 

 

实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操做时会转成数值型进行计算,此时redisObject的encoding字段为int。

 

  • Hash

经常使用命令:hget,hset,hgetall 等。

应用场景:在Memcached中,咱们常常将一些结构化的信息打包成HashMap,在客户端序列化后存储为一个字符串的值,好比用户的昵称、年龄、性别、积分等,这时候在须要修改其中某一项时,一般须要将全部值取出反序列化后,修改某一项的值,再序列化存储回去。这样不只增大了开销,也不适用于一些可能并发操做的场合(好比两个并发的操做都须要修改积分)。而Redis的Hash结构能够使你像在数据库中Update一个属性同样只修改某一项属性值。

        咱们简单举个实例来描述下Hash的应用场景,好比咱们要存储一个用户信息对象数据,包含如下信息:

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,若是用普通的key/value结构来存储,主要有如下2种存储方式:

 

第一种方式将用户ID做为查找key,把其余信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增长了序列化/反序列化的开销,而且在须要修改其中一项信息时,须要把整个对象取回,而且修改操做须要对并发进行保护,引入CAS等复杂问题。

第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称做为惟一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,可是用户ID为重复存储,若是存在大量这样的数据,内存浪费仍是很是可观的。

那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,以下图:

也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取均可以直接经过其内部Map的Key(Redis里称内部Map的key为field), 也就是经过 key(用户ID) + field(属性标签) 就能够操做对应属性数据了,既不须要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。

这里同时须要注意,Redis提供了接口(hgetall)能够直接取到所有的属性数据,可是若是内部Map的成员不少,那么涉及到遍历整个内部Map的操做,因为Redis单线程模型的缘故,这个遍历操做可能会比较耗时,而另其它客户端的请求彻底不响应,这点须要格外注意。

实现方式:

上面已经说到Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不一样实现,这个Hash的成员比较少时Redis为了节省内存会采用相似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

  • List

经常使用命令:lpush,rpush,lpop,rpop,lrange等。

应用场景:

Redis list的应用场景很是多,也是Redis最重要的数据结构之一,好比twitter的关注列表,粉丝列表等均可以用Redis的list结构来实现。

Lists 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用Lists结构,咱们能够轻松地实现最新消息排行等功能。Lists的另外一个应用就是消息队列,
能够利用Lists的PUSH操做,将任务存在Lists中,而后工做线程再用POP操做将任务取出进行执行。Redis还提供了操做Lists中某一段的api,你能够直接查询,删除Lists中某一段的元素。

实现方式:

Redis list的实现为一个双向链表,便可以支持反向查找和遍历,更方便操做,不过带来了部分额外的内存开销,Redis内部的不少实现,包括发送缓冲队列等也都是用的这个数据结构。

  • Set

经常使用命令:

sadd,spop,smembers,sunion 等。

应用场景:

Redis set对外提供的功能与list相似是一个列表的功能,特殊之处在于set是能够自动排重的,当你须要存储一个列表数据,又不但愿出现重复数据时,set是一个很好的选择,而且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

Sets 集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构,能够存储一些集合性的数据,好比在微博应用中,能够将一个用户全部的关注人存在一个集合中,将其全部粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操做,能够很是方便的实现如共同关注、共同喜爱、二度好友等功能,对上面的全部集合操做,你还能够使用不一样的命令选择将结果返回给客户端仍是存集到一个新的集合中。

实现方式:

set 的内部实现是一个 value永远为null的HashMap,实际就是经过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的缘由。

  • Sorted Set

经常使用命令:

zadd,zrange,zrem,zcard等

使用场景:

Redis sorted set的使用场景与set相似,区别是set不是自动有序的,而sorted set能够经过用户额外提供一个优先级(score)的参数来为成员排序,而且是插入有序的,即自动排序。当你须要一个有序的而且不重复的集合列表,那么能够选择sorted set数据结构,好比twitter 的public timeline能够以发表时间做为score来存储,这样获取时就是自动按时间排好序的。

另外还能够用Sorted Sets来作带权重的队列,好比普通消息的score为1,重要消息的score为2,而后工做线程能够选择按score的倒序来获取工做任务。让重要的任务优先执行。

实现方式:

Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是全部的成员,排序依据是HashMap里存的score,使用跳跃表的结构能够得到比较高的查找效率,而且在实现上比较简单。

 

  • Pub/Sub

 

Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你能够设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,全部订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用做实时消息系统,好比普通的即时聊天,群聊等功能。

 

  • Transactions

 

谁说NoSQL都不支持事务,虽然Redis的Transactions提供的并非严格的ACID的事务(好比一串用EXEC提交执行的命令,在执行中服务器宕机,那么会有一部分命令执行了,剩下的没执行),可是这个Transactions仍是提供了基本的命令打包执行的功能(在服务器不出问题的状况下,能够保证一连串的命令是顺序在一块儿执行的,中间有会有其它客户端命令插进来执行)。Redis还提供了一个Watch功能,你能够对一个key进行Watch,而后再执行Transactions,在这过程当中,若是这个Watched的值进行了修改,那么这个Transactions会发现并拒绝执行。

 

 

 

4.  Redis实际应用场景

 

        Redis在不少方面与其余数据库解决方案不一样:它使用内存提供主存储支持,而仅使用硬盘作持久性的存储;它的数据模型很是独特,用的是单线程。另外一个大区别在于,你能够在开发环境中使用Redis的功能,但却不须要转到Redis。

转向Redis固然也是可取的,许多开发者从一开始就把Redis做为首选数据库;但设想若是你的开发环境已经搭建好,应用已经在上面运行了,那么更换数据库框架显然不那么容易。另外在一些须要大容量数据集的应用,Redis也并不适合,由于它的数据集不会超过系统可用的内存。因此若是你有大数据应用,并且主要是读取访问模式,那么Redis并非正确的选择。

        然而我喜欢Redis的一点就是你能够把它融入到你的系统中来,这就可以解决不少问题,好比那些你现有的数据库处理起来感到缓慢的任务。这些你就能够经过Redis来进行优化,或者为应用建立些新的功能。在本文中,我就想探讨一些怎样将Redis加入到现有的环境中,并利用它的原语命令等功能来解决 传统环境中碰到的一些常见问题。在这些例子中,Redis都不是做为首选数据库。

一、显示最新的项目列表

下面这个语句经常使用来显示最新项目,随着数据多了,查询毫无疑问会愈来愈慢。

 

  1. SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10   

 

        在Web应用中,“列出最新的回复”之类的查询很是广泛,这一般会带来可扩展性问题。这使人沮丧,由于项目原本就是按这个顺序被建立的,但要输出这个顺序却不得不进行排序操做。

        相似的问题就能够用Redis来解决。好比说,咱们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上咱们有一个“显示所有”的连接,点击后就能够得到更多的评论。

        咱们假设数据库中的每条评论都有一个惟一的递增的ID字段。

        咱们能够使用分页来制做主页和评论页,使用Redis的模板,每次新评论发表时,咱们会将它的ID添加到一个Redis列表:

 

  1. LPUSH latest.comments <ID>   

 

       咱们将列表裁剪为指定长度,所以Redis只须要保存最新的5000条评论:

       LTRIM latest.comments 0 5000 

      每次咱们须要获取最新评论的项目范围时,咱们调用一个函数来完成(使用伪代码):

 

  1. FUNCTION get_latest_comments(start, num_items):  
  2.     id_list = redis.lrange("latest.comments",start,start+num_items - 1)  
  3.     IF id_list.length < num_items  
  4.         id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")  
  5.     END  
  6.     RETURN id_list  
  7. END  

 

 

      这里咱们作的很简单。在Redis中咱们的最新ID使用了常驻缓存,这是一直更新的。可是咱们作了限制不能超过5000个ID,所以咱们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才须要去访问数据库。

        咱们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其余类型数据库)只是在用户须要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。

二、删除与过滤

      咱们能够使用LREM来删除评论。若是删除操做很是少,另外一个选择是直接跳过评论条目的入口,报告说该评论已经不存在。

       有些时候你想要给不一样的列表附加上不一样的过滤器。若是过滤器的数量受到限制,你能够简单的为每一个不一样的过滤器使用不一样的Redis列表。毕竟每一个列表只有5000条项目,但Redis却可以使用很是少的内存来处理几百万条项目。

三、排行榜相关

      另外一个很广泛的需求是各类数据库的数据并不是存储在内存中,所以在按得分排序以及实时更新这些几乎每秒钟都须要更新的功能上数据库的性能不够理想。

      典型的好比那些在线游戏的排行榜,好比一个Facebook的游戏,根据得分你一般想要:

         - 列出前100名高分选手

         - 列出某用户当前的全球排名

      这些操做对于Redis来讲小菜一碟,即便你有几百万个用户,每分钟都会有几百万个新的得分。

      模式是这样的,每次得到新得分时,咱们用这样的代码:

      ZADD leaderboard  <score>  <username> 

     你可能用userID来取代username,这取决于你是怎么设计的。

      获得前100名高分用户很简单:ZREVRANGE leaderboard 0 99。

      用户的全球排名也类似,只须要:ZRANK leaderboard <username>。

 

四、按照用户投票和时间排序

      排行榜的一种常见变体模式就像Reddit或Hacker News用的那样,新闻按照相似下面的公式根据得分来排序:

       score = points / time^alpha 

      所以用户的投票会相应的把新闻挖出来,但时间会按照必定的指数将新闻埋下去。下面是咱们的模式,固然算法由你决定。

      模式是这样的,开始时先观察那些多是最新的项目,例如首页上的1000条新闻都是候选者,所以咱们先忽视掉其余的,这实现起来很简单。

      每次新的新闻贴上来后,咱们将ID添加到列表中,使用LPUSH + LTRIM,确保只取出最新的1000条项目。

      有一项后台任务获取这个列表,而且持续的计算这1000条新闻中每条新闻的最终得分。计算结果由ZADD命令按照新的顺序填充生成列表,老新闻则被清除。这里的关键思路是排序工做是由后台任务来完成的。

 

五、处理过时项目

      另外一种经常使用的项目排序是按照时间排序。咱们使用unix时间做为得分便可。

      模式以下:

       - 每次有新项目添加到咱们的非Redis数据库时,咱们把它加入到排序集合中。这时咱们用的是时间属性,current_time和time_to_live。

       - 另外一项后台任务使用ZRANGE…SCORES查询排序集合,取出最新的10个项目。若是发现unix时间已通过期,则在数据库中删除条目。

 

六、计数

       Redis是一个很好的计数器,这要感谢INCRBY和其余类似命令。

       我相信你曾许屡次想要给数据库加上新的计数器,用来获取统计或显示新信息,可是最后却因为写入敏感而不得不放弃它们。

       好了,如今使用Redis就不须要再担忧了。有了原子递增(atomic increment),你能够放心的加上各类计数,用GETSET重置,或者是让它们过时。

       例如这样操做:

         INCR user:<id> EXPIRE 

         user:<id> 60 

       你能够计算出最近用户在页面间停顿不超过60秒的页面浏览量,当计数达到好比20时,就能够显示出某些条幅提示,或是其它你想显示的东西。

七、特定时间内的特定项目

        另外一项对于其余数据库很难,但Redis作起来却垂手可得的事就是统计在某段特色时间里有多少特定用户访问了某个特定资源。好比我想要知道某些特定的注册用户或IP地址,他们到底有多少访问了某篇文章。

      每次我得到一次新的页面浏览时我只须要这样作:

       SADD page:day1:<page_id> <user_id> 

      固然你可能想用unix时间替换day1,好比time()-(time()%3600*24)等等。

      想知道特定用户的数量吗?只须要使用SCARD page:day1:<page_id>。

       须要测试某个特定用户是否访问了这个页面?SISMEMBER page:day1:<page_id>。

 

八、实时分析正在发生的状况,用于数据统计与防止垃圾邮件等

        咱们只作了几个例子,但若是你研究Redis的命令集,而且组合一下,就能得到大量的实时分析方法,有效并且很是省力。使用Redis原语命令,更容易实施垃圾邮件过滤系统或其余实时跟踪系统。

 

九、Pub/Sub

       Redis的Pub/Sub很是很是简单,运行稳定而且快速。支持模式匹配,可以实时订阅与取消频道。

十、队列

        你应该已经注意到像list push和list pop这样的Redis命令可以很方便的执行队列操做了,但能作的可不止这些:好比Redis还有list pop的变体命令,可以在列表为空时阻塞队列。

       现代的互联网应用大量地使用了消息队列(Messaging)。消息队列不只被用于系统内部组件之间的通讯,同时也被用于系统跟其它服务之间的交互。消息队列的使用能够增长系统的可扩展性、灵活性和用户体验。非基于消息队列的系统,其运行速度取决于系统中最慢的组件的速度(注:短板效应)。而基于消息队列能够将系统中各组件解除耦合,这样系统就再也不受最慢组件的束缚,各组件能够异步运行从而得以更快的速度完成各自的工做。

    此外,当服务器处在高并发操做的时候,好比频繁地写入日志文件。能够利用消息队列实现异步处理。从而实现高性能的并发操做。

 

十一、缓存

        Redis的缓存部分值得写一篇新文章,我这里只是简单的说一下。Redis可以替代memcached,让你的缓存从只能存储数据变得可以更新数据,所以你再也不须要每次都从新生成数据了。

此部份内容的原文地址:http://antirez.com/post/take-advantage-of-redis-adding-it-to-your-stack.html

 

5.  国内外三个不一样领域巨头分享的Redis实战经验及使用场景

 

   

     随着应用对高性能需求的增长,NoSQL逐渐在各大名企的系统架构中生根发芽。这里咱们将为你们分享社交巨头新浪微博、传媒巨头Viacom及图片分享领域佼佼者Pinterest带来的Redis实践,首先咱们看新浪微博 @启盼cobain的Redis实战经验分享:

1、新浪微博:史上最大的Redis集群

Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King. — Jim Gray

Redis不是比较成熟的memcache或者Mysql的替代品,是对于大型互联网类应用在架构上很好的补充。如今有愈来愈多的应用也在纷纷基于Redis作架构的改造。首先简单公布一下Redis平台实际状况:

 

  • 2200+亿 commands/day 5000亿Read/day 500亿Write/day
  • 18TB+ Memory
  • 500+ Servers in 6 IDC 2000+instances

 

应该是国内外比较大的Redis使用平台,今天主要从应用角度谈谈Redis服务平台。

Redis使用场景

1.Counting(计数)

计数的应用在另一篇文章里较详细的描述,计数场景的优化 http://www.xdata.me/?p=262这里就很少加描述了。

能够预见的是,有不少同窗认为把计数所有存在内存中成本很是高,我在这里用个图表来表达下个人观点:

不少状况你们都会设想纯使用内存的方案会颇有很高成本,但实际状况每每会有一些不同:

 

  • COST,对于有必定吞吐需求的应用来讲,确定会单独申请DB、Cache资源,不少担忧DB写入性能的同窗还会主动将DB更新记入异步队列,而这三块的资源的利用率通常都不会过高。资源算下来,你惊异的发现:反而纯内存的方案会更精简!
  • KISS原则,这对于开发是很是友好的,我只须要创建一套链接池,不用担忧数据一致性的维护,不用维护异步队列。
  • Cache穿透风险,若是后端使用DB,确定不会提供很高的吞吐能力,cache宕机若是没有妥善处理,那就悲剧了。
  • 大多数的起始存储需求,容量较小。

 

2.Reverse cache(反向cache)

面对微博经常出现的热点,如最近出现了较为火爆的短链,短期有数以万计的人点击、跳转,而这里会经常涌现一些需求,好比咱们向快速在跳转时断定用户等级,是否有一些帐号绑定,性别爱好什么的,已给其展现不一样的内容或者信息。

普通采用memcache+Mysql的解决方案,当调用id合法的状况下,可支撑较大的吞吐。但当调用id不可控,有较多垃圾用户调用时,因为memcache未有命中,会大量的穿透至Mysql服务器,瞬间形成链接数疯长,总体吞吐量下降,响应时间变慢。

这里咱们能够用redis记录全量的用户断定信息,如string key:uid int:type,作一次反向的cache,当用户在redis快速获取本身等级等信息后,再去Mc+Mysql层去获取全量信息。如图:

固然这也不是最优化的场景,如用Redis作bloomfilter,可能更加省用内存。

3.Top 10 list

产品运营总会让你展现最近、最热、点击率最高、活跃度最高等等条件的top list。不少更新较频繁的列表若是使用MC+MySQL维护的话缓存失效的可能性会比较大,鉴于占用内存较小的状况,使用Redis作存储也是至关不错的。

4.Last Index

用户最近访问记录也是redis list的很好应用场景,lpush lpop自动过时老的登录记录,对于开发来讲仍是很是友好的。

5.Relation List/Message Queue

这里把两个功能放在最后,由于这两个功能在现实问题当中遇到了一些困难,但在必定阶段也确实解决了咱们不少的问题,故在这里只作说明。

Message Queue就是经过list的lpop及lpush接口进行队列的写入和消费,因为自己性能较好也能解决大部分问题。

6.Fast transaction with Lua

Redis 的Lua的功能扩展实际给Redis带来了更多的应用场景,你能够编写若干command组合做为一个小型的非阻塞事务或者更新逻辑,如:在收到message推送时,同时1.给本身的增长一个未读的对话 2.给本身的私信增长一个未读消息 3.最后给发送人回执一个完成推送消息,这一层逻辑彻底能够在Redis Server端实现。

可是,须要注意的是Redis会将lua script的所有内容记录在aof和传送给slave,这也将是对磁盘,网卡一个不小的开销。

7.Instead of Memcache

 

  1. 不少测试和应用均已证实,
  2. 在性能方面Redis并无落后memcache多少,而单线程的模型给Redis反而带来了很强的扩展性。
  3. 在不少场景下,Redis对同一份数据的内存开销是小于memcache的slab分配的。
  4. Redis提供的数据同步功能,实际上是对cache的一个强有力功能扩展。

 

Redis使用的重要点

1.rdb/aof Backup!

咱们线上的Redis 95%以上是承担后端存储功能的,咱们不只用做cache,而更为一种k-v存储,他彻底替代了后端的存储服务(MySQL),故其数据是很是重要的,若是出现数据污染和丢失,误操做等状况,将是难以恢复的。因此备份是很是必要的!为此,咱们有共享的hdfs资源做为咱们的备份池,但愿能随时能够还原业务所需数据。

2.Small item & Small instance!

因为Redis单线程(严格意义上不是单线程,但认为对request的处理是单线程的)的模型,大的数据结构list,sorted set,hash set的批量处理就意味着其余请求的等待,故使用Redis的复杂数据结构必定要控制其单key-struct的大小。

另外,Redis单实例的内存容量也应该有严格的限制。单实例内存容量较大后,直接带来的问题就是故障恢复或者Rebuild从库的时候时间较长,而更糟糕的是,Redis rewrite aof和save rdb时,将会带来很是大且长的系统压力,并占用额外内存,极可能致使系统内存不足等严重影响性能的线上故障。咱们线上96G/128G内存服务器不建议单实例容量大于20/30G。

3.Been Available!

业界资料和使用比较多的是Redis sentinel(哨兵)

http://www.huangz.me/en/latest/storage/redis_code_analysis/sentinel.html

http://qiita.com/wellflat/items/8935016fdee25d4866d9

2000行C实现了服务器状态检测,自动故障转移等功能。

但因为自身实际架构每每会复杂,或者考虑的角度比较多,为此 @许琦eryk和我一同作了hypnos项目。

hypnos是神话中的睡神,字面意思也是但愿咱们工程师无需在休息时间处理任何故障。:-)

其工做原理示意以下:

Talk is cheap, show me your code! 稍后将单独写篇博客细致讲下Hypnos的实现。

4.In Memory or not?

发现一种状况,开发在沟通后端资源设计的时候,经常由于习惯使用和错误了解产品定位等缘由,而忽视了对真实使用用户的评估。也许这是一份历史数据,只有最近一天的数据才有人进行访问,而把历史数据的容量和最近一天请求量都抛给内存类的存储现实是很是不合理的。

因此当你在究竟使用什么样的数据结构存储的时候,请务必先进行成本衡量,有多少数据是须要存储在内存中的?有多少数据是对用户真正有意义的。由于这其实对后端资源的设计是相当重要的,1G的数据容量和1T的数据容量对于设计思路是彻底不同的

Plans in future?

1.slave sync改造

所有改造线上master-slave数据同步机制,这一点咱们借鉴了MySQL Replication的思路,使用rdb+aof+pos做为数据同步的依据,这里简要说明为何官方提供的psync没有很好的知足咱们的需求:

假设A有两个从库B及C,及 A `— B&C,这时咱们发现master A服务器有宕机隐患须要重启或者A节点直接宕机,须要切换B为新的主库,若是A、B、C不共享rdb及aof信息,C在做为B的从库时,仍会清除自身数据,由于C节点只记录了和A节点的同步情况。

故咱们须要有一种将A`–B&C 结构切换切换为A`–B`–C结构的同步机制,psync虽然支持断点续传,但仍没法支持master故障的平滑切换。

实际上咱们已经在咱们定制的Redis计数服务上使用了如上功能的同步,效果很是好,解决了运维负担,但仍需向全部Redis服务推广,若是可能咱们也会向官方Redis提出相关sync slave的改进。

2.更适合redis的name-system Or proxy

细心的同窗发现咱们除了使用DNS做为命名系统,也在zookeeper中有一份记录,为何不让用户直接访问一个系统,zk或者DNS选择其一呢?

其实仍是很简单,命名系统是个很是重要的组件,而dns是一套比较完善的命名系统,咱们为此作了不少改进和试错,zk的实现仍是相对复杂,咱们尚未较强的把控粒度。咱们也在思考用什么作命名系统更符合咱们需求。

3.后端数据存储

大内存的使用确定是一个重要的成本优化方向,flash盘及分布式的存储也在咱们将来计划之中。(原文连接: Largest Redis Clusters Ever

2、Pinterest:Reids维护上百亿的相关性

      Pinterest已经成为硅谷最疯故事之一,在2012年,他们基于PC的业务增长1047%,移动端采用增长1698%, 该年3月其独立访问数量更飙升至533亿。在Pinterest,人们关注的事物以百亿记——每一个用户界面都会查询某个board或者是用户是否关注的行为促成了异常复杂的工程问题。这也让Redis得到了用武之地。通过数年的发展,Pinterest已经成为媒体、社交等多个领域的佼佼者,其辉煌战绩以下:

 

  • 得到的推荐流量高于Google+、YouTube及LinkedIn三者的总和
  • 与Facebook及Twitter一块儿成为最流行的三大社交网络
  • 参考Pinterest进行购买的用户比其它网站更高( 更多详情

 

如您所想,基于其独立访问数,Pinterest的高规模促成了一个很是高的IT基础设施需求。

 

经过缓存来优化用户体验

近日,Pinterest工程经理Abhi Khune对其公司的用户体验需求及Redis的使用经验 进行了分享。即便是滋生的应用程序打造者,在分析网站的细节以前也不会理解这些特性,所以先大体的理解一下使用场景:首先,为每一个粉丝进行说起到的预检查;其次,UI将准确的显示用户的粉丝及关注列表分页。高效的执行这些操做,每次点击都须要很是高的性能架构。

不能免俗,Pinterest的软件工程师及架构师已经使用了MySQL及memcache,可是缓存解决方案仍然达到了他们的瓶颈;所以为了拥有更好的用户体验,缓存必须被扩充。而在实际操做过程当中,工程团队已然发现缓存只有当用户sub-graph已经在缓存中时才会起到做用。所以。任何使用这个系统的人都须要被缓存,这就致使了整个图的缓存。同时,最多见的查询“用户A是否关注了用户B”的答案常常是否认的,然而这却被做为了缓存丢失,从而促成一个数据库查询,所以他们须要一个新的方法来扩展缓存。最终,他们团队决定使用Redis来存储整个图,用以服务众多的列表。

使用Redis存储大量的Pinterest列表

Pinterest使用了Redis做为解决方案,并将性能推至了内存数据库等级,为用户保存多种类型列表:

 

  • 关注者列表
  • 你所关注的board列表
  • 粉丝列表
  • 关注你board的用户列表
  • 某个用户中board中你没有关注的列表
  • 每一个board的关注者及非关注者

 

Redis为其7000万用户存储了以上的全部列表,本质上讲能够说是储存了全部粉丝图,经过用户ID分片。鉴于你能够经过类型来查看以上列表的数据,分析概要信息被用看起来更像事务的系统储存及访问。Pinterest当下的用户like被限制为10万,初略进行统计:若是每一个用户关注25个board,将会在用户及board间产生17.5亿的关系。同时更加剧要的是,这些关系随着系统的使用天天都会增长。

Pinterest的Reids架构及运营

经过Pinterest的一个创始人了解到,Pinterest开始使用Python及订制的Django编写应用程序,并一直持续到其拥有1800万用户级日410TB用户数据的时候。虽然使用了多个存储对数据进行储存,工程师根据用户id使用了8192个虚拟分片,每一个分片都运行在一个Redis DB之上,同时1个Redis实例将运行多个Redis DB。为了对CPU核心的充分使用,同一台主机上同时使用多线程和单线程Redis实例。

鉴于整个数据集运行在内存当中,Redis在Amazon EBS上对每秒传输进来的写入都会进行持久化。扩展主要经过两个方面进行:第一,保持50%的利用率,经过主从转换,机器上运行的Redis实例一半会转译到一个新机器上;第二,扩展节点和分片。整个Redis集群都会使用一个主从配置,从部分将被当作一个热备份。一旦主节点失败,从部分会马上完成主的转换,同时一个新的从部分将会被添加,ZooKeeper将完成整个过程。同时他们每一个小时都会在Amazon S3上运行BGsave作更持久的储存——这项Reids操做会在后端进行,以后Pinterest会使用这些数据作MapReduce和分析做业。(更多内容见原文)

3、Viacom:Redis在系统中的用例盘点

Viacom是全球最大的传媒集体之一,同时也遭遇了当下最大的数据难题之一:如何处理日益剧增的动态视频内容。

着眼这一挑战的上升趋势,咱们会发现:2010年世界上全部数据体积达到ZB级,而单单2012这一年,互联网产生的数据就增长了2.8个ZB,其中大部分的数据都是非结构化的,包括了视频和图片。

覆盖MVN(之前称为MTV Networks、Paramount及BET),Viacom是个名副其实的传媒巨头,支持众多人气站点,其中包括The Daily Show、osh.0、South Park Studios、GameTrailers.com等。做为媒体公司,这些网站上的文档、图片、视频短片都在无时无刻的更新。长话短说,下面就进入Viacom高级架构师Michael Venezia 分享的Redis实践:

Viacom的网站架构背景

对于Viacom,横跨多个站点传播内容让必须专一于规模的需求,同时为了将内容竟可能快的传播到相应用户,他们还必须聚焦内容之间的关系。然而即便The Daily Show、Nickelodeon、Spike或者是VH1 这些单独的网站上,日平均PV均可以达到千万,峰值时流量更会达到平均值的20-30倍。同时基于对实时的需求,动态的规模及速度已成为架构的基础之一。

除去动态规模以外,服务还必须基于用户正在浏览的视频或者是地理位置来推测用户的喜爱。好比说,某个页面可能会将一个独立的视频片断与本地的促销,视频系列的额外部分,甚至是相关视频联系起来。为了能让用户能在网站上停留更长的时间,他们创建了一个能基于详细元数据自动创建页面的软件引擎,这个引擎能够根据用户当下兴趣推荐额外的内容。鉴于用于兴趣的随时改变,数据的类型很是普遍——相似graph-like,实际上作的是大量的join。

这样作有利于减小相似视频的大致积文件副本数,好比数据存储中一个独立的记录是Southpark片断“Cartman gets an Anal Probe”,这个片断可能也会出如今德语的网站上。虽然视频是同样的,可是英语用户搜索的可能就是另外一个不一样的词语。元数据的副本转换成搜索结果,并指向相同的视频。所以在美国用户搜索真实标题的状况下,德国浏览者可能会使用转译的标题——德国网站上的“Cartman und die Analsonde”。

这些元数据覆盖了其它记录或者是对象,同时还能够根据使用环境来改变内容,经过不一样的规则集来限制不一样地理位置或者是设备请求的内容。

Viacom的实现方法

尽管许多机构经过使用ORM及传统关系型数据库来解决这个问题,Viacom却使用了一个迥然不一样的方法。

本质上,他们彻底承担不了对数据库的直接访问。首先,他们处理的大部分都是流数据,他们偏向于使用Akamai从地理上来分配内容。其次,基于页面的复杂性可能会取上万个对象。取如此多的数据显然会影响到性能,所以JSON在1个数据服务中投入了使用。固然,这些JSON对象的缓存将直接影响到网站性能。同时,当内容或者是内容之间的关系发生改变时,缓存还须要动态的进行更新。

Viacom依靠对象基元和超类解决这个问题,继续以South Park为例:一个私有的“episode”类包含了全部该片断相关信息,一个“super object”将有助于发现实际的视频对象。超类这个思想确实很是有益于建设低延迟页面的自动建设,这些超类能够帮助到基元对象到缓存的映射及保存。

Viacom为何要使用Redis

每当Viacom上传一个视频片断,系统将创建一个私有的对象,并于1个超类关联。每一次修改,他们都须要重估私有对象的每一个改变,并更新全部复合对象。同时,系统还须要无效Akamail中的URL请求。系统现有架构的组合及更敏捷的管理方法需求将Viacom推向了Redis。

基于Viacom主要基于PHP,因此这个解决方案必须支持PHP。他们首先选择了memcached作对象存储,可是它并不能很好的支持hashmap;同时他们还须要一个更有效的进行无效步骤的重估,即更好的理解内容的依赖性。本质上说,他们须要时刻跟进无效步骤中的依赖性改变。所以他们选择了Redis及Predis的组合来解决这个问题。

他们团队使用Redis给southparkstudios.com和thedailyshow.com两个网站建设依赖性图,在取得了很大的成功后他们开始着眼Redis其它适合场景。

Redis的其它使用场景

显而易见,若是有人使用Redis来建设依赖性图,那么使用它来作对象处理也是说得通的。一样,这也成了架构团队为Redis选择的第二使用场景。Redis的复制及持久化特性同时也征服了Viacom的运营团队,所以在几个开发周期后,Redis成为他们网站的主要数据及依赖性储存。

后两个用例则是行为追踪及浏览计数的缓冲,改变后的架构是Redis每几分钟向MySQL中储存一次,而浏览计数则经过Redis进行存储及计数。同时Redis还被用来作人气的计算,一个基于访问数及访问时间的得分系统——若是某个视频最近被访问的次数越多,它的人气就越高。在如此多内容上每隔10-15分钟作一次计算绝对不是相似MySQL这样传统关系型数据库的强项,Viacom使用Redis的理由也很是简单——在1个存储浏览信息的Redis实例上运行Lua批处理做业,计算出全部的得分表。信息被拷贝到另外一个Redis实例上,用以支持相关的产品查询。同时还在MySQL上作了另外一个备份,用以之后的分析,这种组合会将这个过程耗费的时间下降60倍。

Viacom还使用Redis存储一步做业信息,这些信息被插入一个列表中,工做人员则使用BLPOP命令行在队列中抓取顶端的任务。同时zsets被用于从众多社交网络(好比Twitter及Tumblr)上综合内容,Viacom经过Brightcove视频播放器来同步多个内容管理系统。

横跨这些用例,几乎全部的Redis命令都被使用——sets、lists、zlists、hashmaps、scripts、counters等。同时,Redis也成为Viacom可扩展架构中不可或缺的一环。