Skip to content

Latest commit

 

History

History

cache

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Redis

原理

数据结构

内存淘汰机制

过期键的删除策略

  • 定时删除(redis不使用):
    在设置键的过期时间的同时,创建一个定时器,让定时器执行对键的删除操作,占用大量CPU
  • 惰性删除
    每次取的时候先判断 expires 对象里面的键是否已经过期,如果过期,则删除键,否则,返回该键
  • 定期删除
    每隔一段时间,程序对数据库遍历检查一遍,然后删除过期的键

集群部署方式

主从复制原理和优化策略

持久化原理

client端并发原子性

分布式锁实现

setnx redisLock true
...业务逻辑执行...
del redisLock

异常情况下锁自动释放

setnx redisLock true
expire redisLock 5
... 业务逻辑执行 ...
del redisLock

原子命令

set redisLock true ex 10 nx
... 业务逻辑执行 ...
del redisLock
  • 在zookeeper中一但服务器进程down掉或者心跳超时,zk中的临时序列会自动释放。但是Redis中没有这样的机制。
  • 如果业务在加锁和释放锁之间的逻辑执行的太长,超出了锁的超时时间,锁就会自动超时释放。甚至在第一个业务执行结束后,释放了后进入业务的分布式锁,打乱了整个锁的持有和释放。

合理设定锁持有时间,使用lua脚本,乐观锁的方式删除锁

String random = Math.random() + "";
jedis.set("redisLock", random, "NX", "EX", 5);
... 业务逻辑执行 ...
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
jedis.eval(script,Collections.singletonList(lockKey), Collections.singletonList(random));

缓存

缓存和数据库双写一致性问题

缓存雪崩问题

缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常

缓存雪崩解决方案:

  • 给缓存的失效时间,加上一个随机值,避免集体失效。
  • 使用互斥锁,但是该方案吞吐量明显下降了。
  • 双缓存。我们有两个缓存,缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟,缓存 B 不设失效时间。自己做缓存预热操作。
  • 然后细分以下几个小点:从缓存 A 读数据库,有则直接返回;A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存 A 和缓存 B。

缓存击穿问题

缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。 缓存穿透解决方案:

  • 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
  • 采用异步更新策略,无论 Key 是否取到值,都直接返回。Value 值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
  • 提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的 Key。迅速判断出,请求所携带的 Key 是否合法有效。如果不合法,则直接返回。

缓存的并发竞争问题