编辑
2023-11-03
缓存中间件
0

缓存预热

​ 缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题,用户直接查询事先被预热的缓存数据,大大减少数据库的查询压力。

缓存雪崩

​ Redis主机挂了,导致Redis全盘崩溃,比如缓存中有大量数据同时过期。

如何解决呢

​ 1、监控redis服务器的性能指标。

​ 2、构建多层的缓存机构,在nginx缓存下面做redis缓存,在redis缓存下面在做ehcache缓存。

​ 3、redis缓存集群要实现高可用,可以使用主从 + 哨兵模式,或者Redis Cluster。

​ 4、数据库的性能也要优化,把数据库里面的超时查询和耗时比较高的事务想办法优化。

​ 5、开启Redis持久化机制aof/rdb,能尽快恢复缓存集群。

​ 6、要做好降级措施,如果出现缓存雪崩,要有兜底机制。可以限流、降级,短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问。

​ 7、LRU和LFU进行切换,LRU和LFU可以保证删除数据的时候不要去淘汰按照时间淘汰的,要去淘汰按照访问次数的。

​ 8、调整有效期的策略,例如把商品和热点新闻,我们把他们的错峰时间分开,不要让他们一次性全崩,过期时间使用固定时间+随机值的形式,稀释集中到期的key的数量。

​ 9、定期做维护,对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时。

编辑
2023-10-19
缓存中间件
0

可以解决什么问题?

存在50亿个电话号码(或者ip、黑名单、url),给10万个电话号码,如何快速准确判断这些号码是否存在?

基本概念

布隆过滤器是一个很长的二进制数组+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中。

能高效的插入和查询,占用空间少,返回的结果是不确定性的。一个元素如果判断结果为存在的时候元素不一定存在,但是判断结果为不存在时则一定不存在。 布隆过滤器可以添加元素但是不能删除元素,因为删掉元素会导致误判率增加。误判只会发生在过滤器没有添加过的元素,对于添加过的元素不会发生误判。

使用场景

1、主要是解决缓存穿透问题

  • 把已存在的数据的key存在布隆过滤器中,相当于在redis前面挡了一层布隆过滤器。
  • 当有新的请求时,先到布隆过滤器中查询是否已经存在;
  • 如果布隆过滤器中不存在该数据则直接返回;
  • 如果布隆过滤器中已存在,才去查询缓存redis,如果redis里没有查到则到MySQL数据库中查询。

2、黑名单校验

原理

编辑
2023-03-27
缓存中间件
0

在Redis集群中{user}:123和{user}:456两个key会被放到同一个槽中吗?

答案是会的。

在Redis集群中,数据是通过哈希槽来分片的。每个槽都有一个编号,从0到16383。当Redis集群中有多个节点时,每个节点负责处理一部分槽。当一个客户端向Redis集群中写入一个键值对时,Redis会根据键名计算出一个哈希值,然后将这个哈希值对16384取模,得到一个槽编号。Redis会根据这个槽编号将键值对分配到相应的节点上。

在Redis集群中,如果两个键名被分配到同一个槽上,它们就会被放到同一个节点上。因此,如果两个键名的哈希值对16384取模的结果相同,它们就会被放到同一个槽中。

编辑
2023-11-05
缓存中间件
0

1、缓存延时双删

​ 先删除缓存,再更新数据库,休眠一会(比如1秒),再次删除缓存。这个休眠时间 = 读业务逻辑数据的耗时 + 几百毫秒。为了确保读请求结束,写请求可以删除读请求可能带来的缓存脏数据。而且这个休眠时间在某些业务环境下不太好拿捏。这种方案还算可以,只有休眠那一会(比如就那1秒),可能有脏数据,一般业务也会接受的。但是如果第二次删除缓存失败呢?缓存和数据库的数据还是可能不一致。给Key设置一个自然的expire过期时间,让它自动过期怎样?那业务要接受过期时间内,数据的不一致。

2、删除缓存重试机制

延时双删可能会存在第二步的删除缓存失败,导致的数据不一致问题。可以使用这个方案优化:删除失败就多删除几次,保证删除缓存成功就可以了, 所以可以引入删除缓存重试机制。先写请求更新数据库,缓存因为某些原因,删除失败,把删除失败的key放到消息队列,消费消息队列的消息,获取要删除的key,重试删除缓存操作。

3、读取biglog异步删除缓存

​ 重试删除缓存机制还不粗,但是会造成很多业务代码入侵。其实,还可以这样优化:通过数据库的binlog来异步淘汰key。以mysql为例:可以使用阿里的canal将binlog日志采集发送到MQ队列里面,然后通过ACK机制确认处理这条更新消息,删除缓存,保证数据缓存一致性。

想要保证数据库和缓存一致性,推荐采用「先更新数据库,再删除缓存」方案,并配合「消息队列」或「订阅变更日志」的方式来做

​ 引入缓存后,需要考虑缓存和数据库一致性问题,可选的方案有:「更新数据库 + 更新缓存」、「更新数据库 + 删除缓存」。

​ 更新数据库 + 更新缓存方案,在「并发」场景下无法保证缓存和数据一致性,解决方案是加「分布锁」,但这种方案存在「缓存资源浪费」和「机器性能浪费」的情况。

​ 采用「先删除缓存,再更新数据库」方案,在「并发」场景下依旧有不一致问题,解决方案是「延迟双删」,但这个延迟时间很难评估。

​ 采用「先更新数据库,再删除缓存」方案,为了保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据最终一致。

​ 采用「先更新数据库,再删除缓存」方案,「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率。

编辑
2023-11-04
缓存中间件
0

有哪些方案?

1、setnx + expire

但是setnx和expire分2步执行,非原子操作;若setnx执行成功,但expire执行失败,就可能出现死锁。而且不支持阻塞等待、不可重入。还有一个问题,如果业务逻辑执行时间超过锁的过期时间,没有办法续约,其他线程可以抢到锁,导致并发问题。

2、Redisson实现分布式锁

说说红锁(RedLock)

RedLock算法

​ RedLock:基于Redis实现的分布式锁,在分布式环境下必须保证不同的进程是以互斥的方式使用共享资源,具体的实现根据编程语言有很多,Java中是Redisson。

加锁:加锁实际上就是redis中,给key设置一个值,为避免死锁,还需要给定一个超时时间。

解锁:将key删除,但是前提是只能自己删除自己的锁,而且需要保证删锁的原子性。

超时:key要有过期时间,不能长时间占用。

​ Redis加锁只作用在一个Redis节点上,无论通过哨兵或者主从保证高可用,当master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:

​ 1、客户端1在Redis的master节点上拿到了锁

​ 2、Master宕机了,存储锁的key还没有来得及同步到Slave上

​ 3、master故障,发生故障转移,slave节点升级为master节点

​ 4、客户端2从新的Master获取到了对应同一个资源的锁

 于是,客户端1和客户端2同时持有了同一个资源的锁,锁的安全性被打破了,RedLock正是用来解决这个问题的方案: