使用Redis做为高速缓存

Redis适合哪些业务场景
常规业务系统的数据库访问中,读写操做的比例通常在7/3到9/1,也就是说读操做远多于写操做,所以高并发系统设计里,经过NoSQL技术将热点数据(短时间内变更几率小的数据)放入内存以达到减轻DB压力,提高数据访问速度的目的,Redis和MongoDB是当下应用最普遍的NoSQL产品,固然若是系统里的写操做居多,也没有必要使用缓存,所以Redis主要用于解决访问性能和并发能力的问题。除了纯数据缓存的做用以外,得益于其超高速的响应能力,Redis也经常使用于提供分布式锁的解决方案。redis

 

哪些设计思路保证了Redis高性能
单个Redis server对请求的处理是基于单线程工做模型的,但因为是纯内存操做,而且单线程的工做模式避免了线程上下文切换带来的额外开销,同时使用NIO多路复用机制(单线程维护多个I/O socket的状态,socket event handler统一进行event分发,并通知到各个event listener),因此即便是单台Redis server的性能也是很是的快,可支持11万次/秒的SET操做,8.1万次/秒的GET操做。算法

高并发系统里有时候单台Redis server不能知足性能需求,Redis 3.0以前的办法是Redis Sentinel,多个节点同时提供服务,而且每一个节点都保存全量数据,Redis 3.0以后引入了Redis Cluster,经过数据分片(Data Sharding)在每一个节点上只保留部分数据(总共有16384个slot)来实现高可用。数据库

Redis Cluster采用无中心节点方式实现,客户端直接与redis集群的每一个节点链接,客户请求到达节点以后,使用统一的哈希算法,CRC16(key)%16384,计算出key对应的slot,而后从Redis Cluster定位出具体的server,具体的data sharding,最终将数据返回给用户 。但因为Redis的事务仅能解决单台server上的ACID问题,对于多台server常见的问题是多个请求针对同一个key的操做一致性问题,须要结合Zookeeper使用分布式锁的机制解决一致性问题和顺序操做问题。缓存

Redis支持动态添加和删除节点,动态迁移和再平衡slot,动态从新选举Leader并进行fail-over;每个节点虽然只保存一部分的slot,但会保存一份相同的data sharding mapping table,这张表记录全部16384个slot的host分布位置,而且节点之间会按期同步更新这张表的信息,这样的设计能够保证Redis cluster内部节点之间只须要不多的信息就能够相互同步信息。客户端访问Redis Cluster的时候会指定集群内的一台host:port,若是操做的key不在当前的host上,则host会根据data sharding mapping table告诉客户端正确的host:port;若是访问的host:port下线了,则客户端的连接自动转移到对应的master或者slave节点。cookie

 

Redis中各类数据类型的使用场景
Redis的数据存储主要经过key/value实现,key都是string类型,value则分不一样的应用场景有五种类型定义:
#1 string类型:能够包含任何数据(jps图片或者通过序列化的对象,单个key最大能够存储512M的数据),具备全局统计功能的数据,如全局ID生成器、集群配置信息等;
#2 hash类型:用于存储对象结构的数据,多个field绑定到一个key上(对比使用string类型存储对象的优点在于hash类型能够直接update具体field的值而不影响其余field),如实现SSO,cookie为key,用户信息为value,并有指定过时时间;
#3 list类型:用于存储须要基于队列或者栈操做的系列数据,如消息队列;
#4 set类型:用于存储须要维护一个全局不重复的集合,如服务注册发现,能够实现全局去重的功能,如访问网页的独立IP,共同好友等;
#5 zset类型:用于存储须要维护一个全局不重复但有权重排序的列表可使用SORTED SET,如积分排行榜、带权重的消息队列。并发

对上述的字段类型均可以进行的相似的操做,
设置一个值:[set|hmset|lpush|sadd] key value
获取一个值:[get|hget] key
删除一个值:[del|hdel] key
设置一个具备过时时间的值:[setex] key time value
若是值不存在就设置这个值:[setnx] key value
查找redis中的keys或者pattern:[keys/scan] key
判断一个值是否存在:[exists|hexists] key
给指定值设置过时时间:[expire] key seconds
将指定key的value加1|减1:[incr|decr] key
将一个key\value迁移到指定server:[migrate] host port key dest-db timeout [copy] [replace]app

HyperLogLog用于作基数统计(基于set类型的封装,仅根据输入的独立元素个数进行统计,而不存储元素自己),能够保证在输入元素数量或者体积很是大的时候能够保证统计所需的空间固定为12kb(最大2^64个元素) 。
在指定的key中添加基数:[pfadd] key value
统计指定key中不一样基数的个数:[pfcount] key
将sourceKey的技术合并到destKey的基数统计中:[pfmerge] destKey sourceKeydom

Pub/Sub用于作消息的发布订阅(基于list类型的封装,将消息封装成list的节点)。
建立一个信息接收channel:[subscribe] channel
向指定的channel发送一个信息:[publish] channel messagesocket

单个redis命令的执行具备原子性,对于多个命令而言redis提供基础事务机制,可是不保证多个命令执行的原子性,一个典型的redis事务以下:
开启一个事务:[multi]
以后能够计划多条redis命令,但并不会执行
提交并执行以前的全部命令:[exec]
开始执行以前计划的redis命令,若是其中某条命令执行失败并不会影响其余命令的执行
取消执行事务块内全部计划的redis命令:[discard]
监视一个或者多个key:[watch] key
表示在执行exec以前若是key被事务以前的命令修改,则当前事务被discard。分布式

 

Redis数据过时策略和内存回收策略
针对已通过期的数据Redis采用按期删除和延迟删除结合的策略,可是二者都有缺陷;因为按期检查全部的key是否过时会带来性能问题,所以按期删除策略使用的是随机抽查,另外在操做Key前会判断是否已通过期,如过时则当即删除;这样的策略会致使一些已通过期的key还堆积在内存里,使得redis server内存占用率居高不下,所以须要结合redis.conf中的maxmemory-policy配置使用,也就是当redis server的内存不足以写入新数据时的内存回收策略,
#1 noeviction:表示直接报错;
#2 allkeys-lur:表示在全部keys中根据LRU删除key;
#3 allkeys-random:表示在全部keys中随机删除key;
#4 volatile-lru/volatile-random/volatile-ttl用于当redis server既充当cache又当DB的时候,表示在设置了expire date的keys中进行删除,ttl表示删除拥有更早过时时间的key。

 

解决Redis缓存穿透和缓存雪崩问题缓存穿透和雪崩能够看作一个问题,只是严重程度不一样;当一个请求到达redis以后发现没有对应的缓存数据,而后向DB发送数据请求,若是能获取到数据那问题就停留在了缓存穿透上,DB获取到的数据会缓存到redis上;若是DB中也没有对应的数据,而且当这样的请求达到必定数量级而且耗用完全部的DB资源,最终致使DB链接异常就出现了缓存雪崩问题。解决缓存穿透问题的思路有下述几种,不论是否从DB中查找到对应的值(没有值就为null),都在redis中记录一条缓存记录;在Dao层维护一张BitMap,用bit记录对应的key是否有对应值,从而避免冗余的DB操做;后台线程专门用于更新即将过时的Redis数据,从而避免缓存穿透。解决缓存雪崩问题的思路有下述几种,在DB Connection上添加互斥锁,这样当大量缓存请求失效的时候须要排队去DB请求数据;对设置了相同过时时间的数据设置一个随机值,避免数据集体失效;使用双缓存或者多层缓存策略,须要配合缓存预热。

相关文章
相关标签/搜索