Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King. — Jim Grayhtml
Redis不是比较成熟的Memcache或者Mysql的替代品,是对于大型互联网类应用在架构上很好的补充。如今有愈来愈多的应用也在纷纷基于Redis作架构的改造。linux
能够简单公布一下Redis平台实际状况redis
2200+亿 commands/day 5000亿Read/day 500亿Write/daysql
18TB+ Memory后端
500+ Servers in 6 IDC 2000+instances缓存
应该是国内外比较大的Redis使用平台,今天主要从应用角度谈谈Redis服务平台。服务器
计数的应用在另一篇文章里较详细的描述,计数场景的优化 http://www.xdata.me/?p=262 这里就不坳述了。数据结构
能够预见的是,有不少同窗认为把计数所有存在内存中成本很是高,我在这里用个图表来表示下个人观点:架构
不少状况你们都会设想纯使用内存的方案会颇有很高成本,但实际状况每每会有一些不同:运维
1.COST,对于有必定吞吐需求的应用来讲,确定会单独申请DB、Cache资源,不少担忧DB写入性能的同窗还会主动将DB更新记入异步队列,而这三块的资源的利用率通常都不会过高。资源算下来,你惊异的发现:反而纯内存的方案会更精简!
2.KISS原则,这对于开发是很是友好的,我只须要创建一套链接池,不用担忧数据一致性的维护,不用维护异步队列。
3.Cache穿透风险,若是后端使用DB,确定不会提供很高的吞吐能力,cache宕机若是没有妥善处理,那就悲剧了。
4.大多数的起始存储需求,容量较小。
面对微博经常出现的热点,如最近出现了较为火爆的短链,短期有数以万记的人点击、跳转,而这里会经常涌现一些需求,好比咱们向快速在跳转时断定用户等级,是否有一些帐号绑定,性别爱好什么的,已给其展现不一样的内容或者信息。
普通采用Memcache+Mysql的解决方案,当调用id合法的状况下,可支撑较大的吞吐。但当调用id不可控,有较多垃圾用户调用时,因为memcache未有命中,会大量的穿透至Mysql服务器,瞬间形成链接数疯长,总体吞吐量下降,响应时间变慢。
这里咱们能够用redis记录全量的用户断定信息,如string key:uid int:type,作一次反向的cache,当用户在redis快速获取本身等级等信息后,再去Mc+Mysql层去获取全量信息。如图:
固然这也不是最优化的场景,如用Redis作bloomfilter,可能更加省用内存。
产品运营总会让你展现最近、最热、点击率最高、活跃度最高等等条件的top list。不少更新较频繁的列表若是使用MC+MySQL维护的话缓存失效的可能性会比较大,鉴于占用内存较小的状况,使用Redis作存储也是至关不错的。
用户最近访问记录也是redis list的很好应用场景,lpush lpop自动过时老的登录记录,对于开发来讲仍是很是友好的。
这里把两个功能放在最后,由于这两个功能在现实问题当中遇到了一些困难,但在必定阶段也确实解决了咱们不少的问题,故在这里只作说明。
Pinterest使用Redis存储社交graph信息:
http://blog.gopivotal.com/case-studies-2/using-redis-at-pinterest-for-billions-of-relationships
Message Queue就是经过list的lpop及lpush接口进行队列的写入和消费,因为自己性能较好也能解决大部分问题。
Redis 的Lua的功能扩展实际给Redis带来了更多的应用场景,你能够编写若干command组合做为一个小型的非阻塞事务或者更新逻辑,如:在收到 message推送时,同时1.给本身的增长一个未读的对话 2.给本身的私信增长一个未读消息 3.最后给发送人回执一个完成推送消息,这一层逻辑彻底能够在Redis Server端实现。
可是,须要注意的是Redis会将lua script的所有内容记录在aof和传送给slave,这也将是对磁盘,网卡一个不小的开销。
不少测试和应用均已证实,
1.在性能方面Redis并无落后Memcache多少,而单线程的模型给Redis反而带来了很强的扩展性。
2.在不少场景下,Redis对同一份数据的内存开销是小于Memcache的slab分配的。
3.Redis提供的数据同步功能,实际上是对cache的一个强有力功能扩展。
咱们线上的Redis 95%以上是承担后端存储功能的,咱们不只用做cache,而更为一种k-v存储,他彻底替代了后端的存储服务(MySQL),故其数据是很是重要的,如 果出现数据污染和丢失,误操做等状况,将是难以恢复的。因此备份是很是必要的!为此,咱们有共享的hdfs资源做为咱们的备份池,但愿能随时能够还原业务 所需数据。
因为Redis单线程(严格意义上不是单线程,但认为对request的处理是单线程的)的模型,大的数据结构list,sorted set,hash set的批量处理就意为着其余请求的等待,故使用Redis的复杂数据结构必定要控制其单key-struct的大小。
另外,Redis单实例的内存容量也应该有严格的限制。单实例内存容量较大后,直接带来的问题就是故障恢复或者Rebuild从库的时候时间较长, 而更糟糕的是,Redis rewrite aof和save rdb时,将会带来很是大且长的系统压力,并占用额外内存,极可能致使系统内存不足等严重影响性能的线上故障。咱们线上96G/128G内存服务器不建议 单实例容量大于20/30G。
业界资料和使用比较多的是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的实现。
发现一种状况,开发在沟通后端资源设计的时候,经常由于习惯使用和错误了解产品定位等缘由,而忽视了对真实使用用户的评估。也许这是一份历史数据,只有最近一天的数据才有人进行访问,而把历史数据的容量和最近一天请求量都抛给内存类的存储现实是很是不合理的。
因此当你在究竟使用什么样的数据结构存储的时候,请务必先进行成本衡量,有多少数据是须要存储在内存中的?有多少数据是对用户真正有意义的。由于这其实对后端资源的设计是相当重要的,1G的数据容量和1T的数据容量对于设计思路是彻底不同的
所有改造线上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的改进。
细心的同窗发现咱们除了使用DNS做为命名系统,也在zookeeper中有一份记录,为何不让用户直接访问一个系统,zk或者DNS选择其一呢?
其实仍是很简单,命名系统是个很是重要的组件,而dns是一套比较完善的命名系统,咱们为此作了不少改进和试错,zk的实现仍是相对复杂,咱们尚未较强的把控粒度。咱们也在思考用什么作命名系统更符合咱们需求。
大内存的使用确定是一个重要的成本优化方向,flash盘及分布式的存储也在咱们将来计划之中。