关于Redis的应用

写这篇文章主要是在开发www.ximalaya.com的feed(登陆首页看到的好友动态,未登陆是看不到的哭)模块使用Redis的一些经验。(www.ximalaya.com是音频为传播介质的SNS网站,喜欢的同窗不妨用一用,也有APP的,仍是一款很是不错的产品。音乐,相声,有声小说等等 一网打尽)。关于Feed自己的讨论之后再专门发博,有兴趣的同窗也能够先开博,而后共同讨论。 java

Redis这个神器已经在互联网名声大做了,主要是对关系型数据库的补充。由于在大并发下,IO每每是性能的瓶颈,因此把数据尽可能放到离cpu近的地方,是解决IO瓶颈的有效途径。呵呵,谁都想把数据放到寄存器,L1 L2 L3cache上,由于这些都是离cpu很近的地方,在一到几十个cpu时钟周期内能读到数据,可是这些缓存空间实在过小了。因此只能把最热的数据去征用这部分缓存。那么比这些数据稍微"冷"一点,但又常常访问的数据怎么办呢?目前最好的途径就是放在内存中。redis,memcache这类的内存数据库就是这样作的。放到内存中就意味着cpu能够在几百个时钟周期内能读到数据。通常服务器配置也是16个G内存吧,在64位系统下,理论可让你的程序彻底占用这16G内存。既然能够在这么快速的读到数据,那么采用什么算法读数据呢?线性查找?那又是浪费cpu时钟周期的。查找最快的莫过于hash表,它的时间复杂度是O(1)。因此本质来讲Redis,memcache都是在内存上的hash数据库。Redis和memcache在互联网的应用都比较多,如何选择呢?固然两个都是解决缓存问题的神器,我更趋向于Redis这个神器。缘由以下:  redis

1,丰富的数据结构,string,hash,list,set,sortset等数据结构都支持,而memcache仅支持string(至关于key-value结构,这里说string是说的redis中的string),而其余数据结构也是在互联网中经常使用的。若是你想用就只能选Redis了。 算法

2,可持久化,memcache是不支持持久化的。那么对于缓存的应用,一旦memcache服务挂掉了,内存的数据就丢失了,那么能够快速重启是吧,内存的数据全没了,这时候就有一个热点故障。或许你说能够经过预热来解决这个问题。可是Redis能够不须要预热,他会从rdb或aof中自动重建内存。以前的Redis版本中重启是须要花费很长时间的,可是在2.6版本后这个过程很是快了。即便是开启aof的状况下重启,9G的数据也只须要六分半的时间(www.ximalaya.com的真实案例)。这主要是Redis做者对aof的命令进行了合并,加快了重启的速度。对于须要持久化的应用,memcache就无能为力了,或许你能够选择memcached,固然Redis任然是更好的方案。 数据库

3,至于速度方面,Redis不会差于memcache,主要是Redis采用了epoll进行通讯吧。 数组

4,memcache是多线程的,Redis是单线程的,虽然更喜欢多线程的应用。但貌似Redis在单线程的操做下速度一点也不逊色,并且让操做更安全了,不须要锁,也不须要线程切换的开销了。Redis在备份rdb的时候会fork一个进程出来,让主进程不受任何影响。 缓存

Redis这个服务器,对于高并发快速读写,原子计数,消息队列,实时排名都是实用的。对于互联网网站来讲这些都是频繁使用,也是关系型数据库比较头疼的。刚好以上提到的用途都在生成环境中有用到。根据实际经验来看,Redis仍是实用于缓存,原子计数。对于持久化存储真的不太适合。由于它会把数据都加载到内存中(若是内存不够用会load到虚拟内存,但这是一个悲剧)。固然若是你用于持久存储的数据是有限的,那么也是很是适合的。可是对于数据须要无限增加的业务,这个真不太适合。网站登陆首页的feed,收件箱列表所有放在Redis中。收件箱列表随着注册用户的增加而增加,须要消耗的内存也是逐步增加。为了缓解这个内存压力,客户端作了sharding,实现内存分片。这虽然可以解决内存问题,但须要更多的机器来作。因此我也一直在想怎么来缓解这块内存的问题。扯远了之后在把关于这方面的思考写出来吧。如今仍是讲一讲Redis的应用。 安全

在缓存中的应用: 服务器

缓存中的应用在memcache中就是对key-value的缓存。它之因此能快,是由于它是存放在内存中的hash数组。内存,hash。这两个关键词就足够解释为何读写快了。如今对于速度和容量都比合适的存储也就内存最合适吧。ssd的速度快,容量也大。但须要在价格和寿命上有更大的突破才能被普遍使用。何况,ssd的速度比起主存来讲仍是有必定差距的。 网络

下面对redis中string hash list set sortset分别说下使用场景。 数据结构

string:这是使用最简单,也是很是频繁的一种数据类型。它就是一种单纯的key-value对。适用于那些经过键直接找值得业务场景。get string的时候须要用到mutil get,这是能够减小网络通讯的,也是很是高效的。

hash:hash类型是对于string类型的补充,主要是有些key有共同的特征,不如一个用户对应的多个值,那么用户id只须要出现一次就能够了,对于string来讲是须要出现屡次的。因此hash是比string更节约了存储。一样hash也能够对多列mutil get,一次网络传输就能够获得全部值。

list:适用于不排重,且有序的操做。这其实就是一个队列,先进先出。放不排重的列表颇有用。曾经还用它来作过队列。但队列仍是用专门的消息队列更好,由于list不支持消息应答的,也就是不能确保你的消息被处理成功。

set:至关于java中的HashSet,用于排重的列表,可是无序的,在无序的列表仍是很适合的。

sortset:这是有序,排重的列表,至关于java中的TreeSet。不过TreeSet是用的红黑树算法,sortset是用的skip table。sortset是颇有用的一种数据结构,以前提到的收集箱列表就是用的sortset存放。不过这个数据结构很耗存储。特别是否是用ziplist时。后面谈优化的时候具体说。


Redis中的一些常见优化:

Redis中最好不要开启VM,在2.6版本也是默认关闭的。即便把vm指定到ssd中,redis做者也是反对的。

对于cache的redis,必定要设置最大内存。这样后台线程的LRU数据淘汰策略才能被触发。因此在未设置最大内存的状况下,对数据设置过时时间每每是无效的。这是一个坑,曾经跳到这个大坑里面,通宵解决性能问题。切记!

ziplist颇有必要设置大一点。好比以前提到的收件箱长度是500条,但有些时候长度可能达到700条,因此把ziplist设置成1024会是一个好的策略。下面具体介绍下这几个参数:

hash-max-ziplist-entries:针对hash类型,只要hash的filed在这个范围内使用紧凑存储,这能够节约存储,也是为何要尽可能使用hash少使用string的理由,特别是在原子计数的时候,对一个用户可能要记录不少数量,必定要采用hash的策略,这是很是有用的。固然这个值毫不是越大越好,一般不要超过1024
hash-max-ziplist-value:hash的value的大小,在这个大小内会使用紧凑存储。这个值也不是越大越好,最好不要超过512。

list-max-ziplist-entries
list-max-ziplist-value
这两个参数和hash用法同样。不过这是针对list类型的。
 
zset-max-ziplist-entries
这个参数是针对sortset。在这个范围内,将不使用红黑树,是线性查找,因此这个值也不能太大,通常不要超过1024。
 
Redis的扩容问题:
 Redis扩容目前来仍是比较麻烦一点的。由于服务端是不支持数据的sharding的。须要在客户端作sharding。一般有两种sharding策略。一致性hash和非一致性hash。
对于非一致性hash:
 能够实现把Redis实例事先切分红多个数据库,好比32或64个库。或者在同一个机器上启多台Redis实例,这样还能够利用多核系统多进程的优点提升并发。当单台机器上的Redis难以支撑时。把这些实例迁移到其余机器上,这样就变相的减轻了单台机器的压力。还能够把数据库切分开,分别放到多台机器上启动。这种作法最大的缺点是,当单台Redis实例的每一个数据库都没法支撑数据时,麻烦就来了。这是须要程序把数据迁移出来,这个迁移每每是很耗时的,也是很容易出错的。对于线上的产品这每每是不能够接受的。那么就一致性hash登场吧。
对于一致性hash:
 对于一致性hash的介绍能够搜索一下。主要的优点就是,在扩容的时候只须要移动受影响的节点。对于整个集群来讲,这些受影响节点的数据是很是少的。若是对于cache来讲,加一台机器,几乎不须要移动数据。让cache miss重建缓存也是能够的。固然这个得针对具体应用评估。不要所以而热点故障,挂网站了,呵呵。一致性hash的优点是能够任意加机器解决容量问题。理论上只要机器够,容量就不是问题。

嗯,暂时就写到这里吧,redis中的注意事项还不少,应用也毫不限于此,具体的官方文档已经介绍的很详细。用到的同窗,能够发表和补充下Redis的其余用途。若有任何纰漏还多多指出,谢谢!

相关文章
相关标签/搜索