redis中有哪些过期策略
定期删除 + 惰性删除
- 定期删除:是指redis默认每100ms就随机检查设置了过期时间的key,如果过期就删除。假设redis中有10w条key设置了过期时间,每隔几百毫秒就检查这10w个key,cpu负载太高了,redis可能就会挂掉。实际上是随机抽取这10w个中的某些key进行检查删除。
- 惰性删除:若这10w条数据中有的过期了,而没被redis删除,那么当下次获取这个key的时候,redis会先检查这个key是否过期,若过期就删除该key,返回null
当要过期的key没有经过惰性删除删除掉,或者长期保存的key大量积压在内存,导致redis内存耗尽,该怎么办
redis为提供了内存淘汰机制,若redis占用过多的内存,此redis本身会进行内存淘汰。删除一些key给内存腾地儿。
- noeviction:当内存不足以容纳新的key插入时,就会插入报错。
- allkeys-lru:当内存不足时,在键空间中,移除最近最少使用的key(常用)
- allkeys-random:随机删除key
- volatile-lru:删除设置了过期时间且最少使用到的key
- volatile-random:随机删除设置了过期时间的key
- volatile-ttl:删除设置了过期时间中快要过期的key
模拟手写LRU
我们可以根据LinkedHashMap的热点词汇进行模拟LRU的实现
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int CACHE_SIZE;
public LRUCache(int cacheSize) {
// 初始map的大小,true表示让linkedHashMap按照key的访问热度进行排序
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > CACHE_SIZE; // map中指的数量大于指定的数量时,就会删除最老的数据
}
public static void main(String[] args) {
LRUCache<Object, Object> lruCache = new LRUCache<>(3);
lruCache.put("name",23);
lruCache.put("home","潍坊");
lruCache.put("degree","本科");
//todo 如果此时新添加一个元素,此时map中并没有热词,就会把最新插入的元素的删除,插入新的元素
// lruCache.put("department","开发部");
// System.out.println(lruCache); // {home=潍坊, degree=本科, department=开发部}
for (int i = 0; i < 10; i++) {
lruCache.get("name"); // 此时name就会成为热词并保留下, 那么home就会被删除
}
lruCache.put("department","开发部");
System.out.println(lruCache); // {degree=本科, name=23, department=开发部}
}
}
redis的高并发和高可用,redis的主从复制
单机redis并发量QPS最多也就几万吧,简单的k v形式,读写分离,缓存写相对于读会少很多。 主从复制 - maste slave可水平扩容 请求量增加,增加slave即可。
注意:
- master必须要有持久化机制,若没有,宕机重启时,就会把其他的salve也置空。
- master及时备份,如果本地的数据丢失,就可以把备份的rdb去恢复master中的数据,重启master就会重新加载备份的数据。
redis持久化方式有哪几种?各有那些优缺点
- RDB(存储的是数据) :客户端发出写入数据时 在指定的时间内 将内存中的数据集快照(当前数据)写入磁盘 生成RDB文件, 它恢复时是将快照文件直接读取到内存中。 ROB比AOF更加高效,节省空间,但是ROB的缺点是最后一次持久化的数据可能会丢失。
- AOF(存储的是指令):以日志的形式记录每个写操作。
缓存雪崩
避免同一时间大量的key同时过期,分布设置key的过期时间。
若redis宕机,避免雪崩如下
- 事前:建立一个高可用架构的redis集群
- 事中:数据缓存之前可以结合本地缓存,ehcache 本地缓存+ 限流组件(hystrix),发生雪崩后,开启限流组件,每秒只允许少部分请求请求数据库,其他的请求调用我们写好的降级组件返回一些默认值或其他友情提示。
- 事后:在redis开启持久化的前提下,重启redis集群,恢复数据。
缓存穿透
布隆过滤器解决缓存穿透
保证缓存与数据库数据的一致性
- 读的时候先读缓存,缓存没有去查数据库,并把结果保存至缓存,做出相应。
- 缓存双删:更新的时候,先删缓存,然后更新数据库,更新成功后,再删缓存。
高并发的情况下, 更新数据库的时候, 请求请求缓存, 没有数据, 然后去请求数据库, 此时数据库还是旧的数据, 我们可以根据这种方式, 将读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况 , 串行化之后,就会导致系统的吞吐量会大幅度的降低,增加机器
redis并发竞争以及解决方案
并发导致同一key执行的顺序不一致。
分布式锁 + 数据的时间戳 : 分布式锁保证同一时间只允许一个线程对数据进行操作,结合时间戳判断该数据的时间是否比缓存中的数据时间戳新,若新则写,否则不操作。