八、Redis消息模式与缓存问题

八、Redis消息模式

8.1、队列模式

使用list类型的lpush和rpop实现消息队列
在这里插入图片描述

注意事项
  • 消息接收方如果不知道队列中是否有消息,会一直发送rpop命令,如果这样的话,会每一次都建立一次连接,这样显然不好。
  • 可以使用brpop命令,它如果从队列中取不出来数据,会一直阻塞,在一定范围内没有取出则返回null、

8.2、发布订阅模式

  • 订阅消息(subscribe)

在这里插入图片描述
示例:subscribe kkb-channel

  • 发布消息(publish)
    在这里插入图片描述
    publish kkb-channel “我是灭霸詹”
  • Redis发布订阅命令

在这里插入图片描述

九、缓存穿透、缓存击穿、缓存失效

9.1、缓存数据的步骤

  • 查询缓存,如果没有数据,则查询数据库。
  • 查询数据库,如果数据不为空,将结果写入缓存。

9.2、缓存穿透

什么叫缓存穿透?

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何解决?
  • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
  • 对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。(布隆表达式)

9.3、缓存雪崩

什么叫缓存雪崩?

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

如何解决?
  • 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
  • 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(此点为补充)

9.4、缓存击穿

什么叫缓存击穿?
  • 对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
  • 缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
如何解决?

使用redis的setnx互斥锁先进行判断,这样其他线程就处于等待状态,保证不会有大并发操作去操作数据库。

if(redis.sexnx()==1){
	//查询数据库
	//加入线程
}

十、缓存淘汰策略之LRU

10.1、Redis内置缓存淘汰策略

最大缓存

  • 在 redis中,允许用户设置最大使用内存大小maxmemory,默认为0,没有指定最大缓存,如果有新的数据添加,超过最大内存,则会使redis崩溃,所以一定要设置。
  • redis 内存数据集大小上升到一定大小的时候,就会实行数据淘汰策略。

淘汰策略

redis淘汰策略配置:maxmemory-policy voltile-lru,支持热配置。

redis 提供 6种数据淘汰策略:

  • voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰。
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
  • no-enviction(驱逐):禁止驱逐数据。

10.2、LRU原理

LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

10.3、LRU实现

最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
在这里插入图片描述

  1. 新数据插入到链表头部;
  2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
  3. 当链表满的时候,将链表尾部的数据丢弃。

在Java中可以使用LinkHashMap去实现LRU。

10.4、分析

【命中率】
当存在热点数据时,LRU的效率很好,但偶发性的、周期性的批量操作会导致LRU命中率急剧下降,缓存污染情况比较严重。
【复杂度】
实现简单。
【代价】
命中时需要遍历链表,找到命中的数据块索引,然后需要将数据移到头部。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值