Redis过期删除采用的是定期删除,默认是每100ms检测一次,遇到过期的key则进行删除,这里的检测并不是顺序检测,而是随机检测。那这样会不会有漏网之鱼?显然Redis也考虑到了这一点,当我们去读/写一个已经过期的key时,会触发Redis的惰性删除策略,直接回干掉过期的key
内存淘汰是指用户存储的一部分key是可以被Redis自动的删除,从而会出现从缓存中查不到数据的情况。加入我们的服务器内存为2G、但是随着业务的发展缓存的数据已经超过2G了。但是这并不影响我们程序的运行,因为操作系统的可见内存并不受物理内存的限制。物理内存不够用没关系,计算机会从硬盘中划出一片空间来作为虚拟内存。这就是Redis设计两种应用场景的初衷:缓存、持久存储
缓存击穿
缓存只是为了缓解数据库压力而添加的一层保护层,当从缓存中查询不到我们需要的数据就要去数据库中查询了。如果被黑客利用,频繁去访问缓存中没有的数据,那么缓存就失去了存在的意义,瞬间所有请求的压力都落在了数据库上,这样会导致数据库连接异常。
解决方案:
1、后台设置定时任务,主动的去更新缓存数据。这种方案容易理解,但是当key比较分散的时候,操作起来还是比较复杂的
2、分级缓存。比如设置两层缓存保护层,1级缓存失效时间短,2级缓存失效时间长。有请求过来优先从1级缓存中去查找,如果在1级缓存中没有找到相应数据,则对该线程进行加锁,这个线程再从数据库中取到数据,更新至1级和2级缓存。其他线程则直接从2级线程中获取
3、提供一个拦截机制,内部维护一系列合法的key值。当请求的key不合法时,直接返回
如何避免雪崩:
1、给缓存加上一定区间内的随机生效时间,不同的key设置不同的失效时间,避免同一时间集体失效。
2、和缓存击穿解决方案类似,做二级缓存,原始缓存失效时从拷贝缓存中读取数据。
3、利用加锁或者队列方式避免过多请求同时对服务器进行读写操作。
用户请求进来,根据商品id获取redi缓存中商品的库存信息,此时系统判断缓存充足则预减库存并进入队列,之后请求消息会出队,然后秒杀接口就会消费消息并且生成订单信息,我们采用redisson实现分布式锁防止缓存超卖,并采用客户端轮询的方式检查是否下单成功,如果没有就会再次调用秒杀接口。请求成功之后那么就会同步redis缓存的数据到数据库持久层,返回给控制层处理展示给用户。
Jedis连接就是资源,JedisPool管理的就是Jedis连接。
redisson
注意:getLock时,RLock lock = redissonClient.getLock(lockName); 这个lockName一定要唯一,redisson应该是将这个lockName同时作为lock的name和key的名称,如果和别人重复了,就需要和别人竞争同一把锁了,而不是自己的业务和自己的业务竞争锁了。
-
首先就是获取一个可重入锁(ReentrantLock)的实例 lock。
其中关键是tryLock方法。 -
尝试获取锁tryAcquireAsync的核心逻辑:
Redisson对于永久锁(就是不带过期时间的锁)处理比较特殊,并不是真的永久。而是先设置一个内部锁过期时间internalLockLeaseTime,之后每过三分之内部锁过期时间之后刷新这个锁的过期时间为internalLockLeaseTime。
redisson重入锁
JCIP 提到了在 Java 6 中引入了两个新的并发集合类 ConcurrentSkipListMap 和 ConcurrentSkipListSet。其实只要介绍一下 ConcurrentSkipListMap 即可(后面简称为 CSLM),因为我们都知道 JDK 中 Set 是基于 Map 实现的。简而言之,CSLM 是一个并发的、可排序的 Map,因此它可以在多线程环境中弥补 ConcurrentHashMap 不支持排序的功能不足。从名字上就可以看出 CSLM 是基于 SkipList 跳表实现。学过算法的同学应该对跳表不陌生。不过还是要简单说一下跳表。
渐进式rehash
以下是哈希表渐进式 rehash 的详细步骤:
为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。
在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。
在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。
随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1, 表示 rehash 操作已完成。
渐进式 rehash 的好处在于它采取分而治之的方式, 将 rehash 键值对所需的计算工作均滩到对字典的每个添加、删除、查找和更新操作上, 从而避免了集中式 rehash 而带来的庞大计算量。
概念
消息队列?
消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠专递,消息发布者只管把消息发布到MQ中而不管谁来取,消息使用者只管从MQ中取消息而不管谁发布的,这样发布者和使用者都不用知道对方的存在。
分布式锁?
分布式缓存?
一致性hash算法?
一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对232取模,什么意思呢?简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-232-1(即哈希值是一个32位无符号整形)。
原子操作的原因
因为 Redis 实际上并不是单线程,它背后还有几个异步线程也在默默工作。这几个线程也要访问 Redis 时钟,所以 lruclock 字段是需要支持多线程读写的。使用 atomic 读写能保证多线程 lruclock 数据的一致性。