一:Redis基本操做redis
基于RedisTemplate(Spring对操做Redis数据库的封装)对五种数据类型的操做数据库
string类型 缓存
适用场景:通常的key-value缓存,计数功能的缓存。安全
list类型 服务器
适用场景: value存放的是结构化的对象,比较方便的就是操做其中的某个字段。博主在作单点登陆的时候,就是用这种数据结构存储用户信息,以cookieId做为key,设置30分钟为缓存过时时间,能很好的模拟出相似session的效果。cookie
hash类型 session
使用场景:使用List的数据结构,能够作简单的消息队列的功能。另外还有一个就是,能够利用lrange命令,作基于redis的分页功能,性能极佳,用户体验好。数据结构
set类型 多线程
使用场景: set堆放的是一堆不重复值的集合。因此能够作全局去重的功能。为何不用JVM自带的Set进行去重?由于咱们的系统通常都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个作一个全局去重,再起一个公共服务,太麻烦了。另外,就是利用交集、并集、差集等操做,能够计算共同喜爱,所有的喜爱,本身独有的喜爱等功能。架构
zset类型
使用场景: sorted set多了一个权重参数score,集合中的元素可以按score进行排列。能够作排行榜应用,取TOP N操做。另外,参照另外一篇《分布式之延时任务方案解析》,该文指出了sorted set能够用来作延时任务。最后一个应用就是能够作范围查找。
常见的几个问题
(一)缓存和数据库双写一致性问题
获取缓存的基本流程:
那么有几个问题出现:
1. 先操做缓存中的数据再更新数据库的数据
2. 修改数据库中的数据再操做缓存中的数据
3. 更新缓存仍是让缓存失效
redis中的数据和数据库中的数据不可能保证绝对事务性,这个是毫无疑问的,因此在实际应用中,咱们都是基于当前的场景进行权衡下降出现不一致问题的出现几率。更新缓存表示数据不但会写入到数据库,还会同步更新缓存,而让缓存失效是表示只更新数据库中的数据,而后删除缓存中对应的key。那么这两种方式怎么去选择?
1. 若是更新缓存的代价很小,那么能够先更新缓存,这个代价很小的意思是不须要很复杂的计算。
2. 若是是更新缓存的代价很大,意味着须要经过多个接口调用和数据查询才能得到最新的结果,那么能够先淘汰缓存。淘汰缓存之后后续的请求若是在缓存中找不到,天然去数据库中检索。
更新数据库和更新缓存这两个操做,是没法保证原子性的,因此咱们须要根据当前业务的场景的容忍性来选择。也就是若是出现不一致的状况下,哪种更新方式对业务的影响最小,就先执行影响最小的方案。
(二)缓存雪崩问题
缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而致使数据库链接异常
1. 对缓存的访问,若是发现从缓存中取不到值,那么经过加锁或者队列的方式保证缓存的单进程操做,从而避免失效时并发请求所有落到底层的存储系统上,可是这种方式会带来性能上的损耗。
2. 将缓存失效的时间分散,下降每个缓存过时时间的重复率。
3. 若是是由于缓存服务器故障致使的问题,一方面须要保证缓存服务器的高可用、另外一方面,应用程序中能够采用多级缓存。
(三)缓存击穿问题
黑客故意去请求缓存中不存在的数据,致使全部的请求都怼到数据库上,从而数据库链接异常
1. 若是查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。好比,”key” , “&&”。在返回这个&&值的时候,我 们的应用就能够认为这是不存在的key,那咱们的应用就能够 决定是否继续等待继续访问,仍是放弃掉此次操做。若是继续等待访问,过一个时间轮询点后,再次请求这个key,若是取到的值再也不是&&,则能够认为这时候key有值了,从而避免了透传到数据库,从而把大量的相似请求挡在了缓存之中。
2. 根据缓存数据Key的设计规则,将不符合规则的key进行过滤采用布隆过滤器,将全部可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查 询压力。