简单谈谈redis缓存问题

边路缓存

cache aside pattern 边路缓存的问题。其实是一种指导思想,思想中包含:

1.查询的时候应该先查询缓存,如果缓存不存在,再查询数据库。

2.修改缓存数据时,应该先修改数据库,再修改缓存。

缓存穿透

在实际开发中,添加缓存工具的目的,较少对数据库的访问次数,增加访问效率。

肯定会存在Redis中不存在的缓存数据。例如:访问id= -1的数据 。可能出现绕过redis依然频繁访问数据库的情况,称为缓存穿透,多出现在数据库查询为null时的情况不被缓存时。

解决办法:

如果查询出来为null的数据,把null数据依然放入到redis缓存中,同时设置这个key的有效时间比正常有效时间更短一些。

if(list==null){
    // key value 有效时间 时间单位
    redisTemplate.opsForValue().set(navKey,null,10, TimeUnit.MINUTES);
}else{
    redisTemplate.opsForValue().set(navKey,result,7,TimeUnit.DAYS);
}

缓存击穿


        实际开发中,考虑redis所在服务器中内存压力,都会设置key的有效时间。一定会出现键值对过期的情况。如果正好key过期了,此时出现大量并发访问,这些访问都会去访问数据库,这种情况成为缓存击穿。

解决办法:

        永久数据(设置热点数据永远不过期)

        加锁。防止出现数据库的并发访问

ReentrantLock(重入锁)

JDK 对于并发访问处理的内容都放入了java.until.concurrent中

ReentrantLock性能和synchronized没有区别的,但是API使用起来更加方便。

@SpringBootTest
public class MyTest {
 
    @Test
    public void test(){
        new Thread(){
            @Override
            public void run() {
                test2("第一个线程111111");
            }
        }.start();
 
        new Thread(){
            @Override
            public void run() {
                test2("第二个线程222222");
            }
        }.start();
 
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    ReentrantLock lock = new ReentrantLock();
    public void test2(String who){
        lock.lock();
        if(lock.isLocked()) {
            System.out.println("开始执行:" + who);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行完:" + who);
            lock.unlock();
        }
    }
}
2.2 解决缓存击穿实例代码

只有在第一次访问时和key过期时才会访问数据库。对于性能来说没有过大影响,因为平时都是直接访问redis

private ReentrantLock lock = new ReentrantLock();
@Override
public Item selectByid(Integer id) {
    String key = "item:"+id;
    if(redisTemplate.hasKey(key)){
        return (Item) redisTemplate.opsForValue().get(key);
    }

    // lock.lock()------  开始获取锁  lock.isLocked()----查询此锁定是否任意线程保持(加锁是否成功)
    lock.lock();
    if(lock.isLocked()) {
        Item item = itemDubboService.selectById(id);
        // 由于设置了有效时间,就可能出现缓存击穿问题
        redisTemplate.opsForValue().set(key, item, 7, TimeUnit.DAYS);

   // lock.unlock()------ 开锁
        lock.unlock();
        return item;
    }
    // 如果加锁失败,为了保护数据库,直接返回null
    return null;
}

 缓存雪崩


        在一段时间内容,出现大量缓存数据失效,这段时间内容数据库的访问频率骤增,这种情况称之为缓存雪崩,与缓存击穿不同的是,缓存击穿是指并发查同一条数据,缓存雪崩是不同的数据都过期了,很多数据都查不到从而查数据库。

解决办法:

int seconds = random.nextInt(10000);

redisTemplate.opsForValue().set(key, item, 100+ seconds, TimeUnit.SECONDS);

        缓存数据的过期时间设置成随机,防止同一时间大量数据过期的现象产生。
        如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中
        设置热点数据永远不过期

Redis脑裂


        Redis脑裂主要是指因为一些网络原因导致Redis Master和Redis Slave和Sentinel集群处于不同的网络分区。sentinel连接不上Master就会重新选择Master,此时就会出现两个不同的Master,好像大脑分裂成两个一样

        Redis集群中不同的节点存储不同的数据,脑裂会导致大量数据丢失。

        解决Redis脑裂只需要在Redis配置文件中配置两个参数

min-slaves-to-write 3 //连接到master的最小slave数量

min-slaves-max-lag 10 //slave连接到master的最大延迟时间


Redis 缓存淘汰策略/当内存不足时如何回收数据/保证Redis中数据不出现内存溢出情况


Redis中数据都放入到内存中。如果没有淘汰策略将会导致内存中数据越来越多,最终导致内存溢出。在Redis5内置了缓存淘汰策略。在配置文件中有如下配置

# maxmemory-policy noeviction 默认策略noevication

# maxmemory <bytes> 缓存最大阈值

# volatile-lru -> 在设置过期key集中选择使用数最小的。

# allkeys-lru -> 在所有key中选择使用最小的。

# volatile-lfu -> 在设置过期时间key集中采用lfu算法。

# allkeys-lfu -> 在所有key中采用lfu算法。

# volatile-random -> 在设置过期key集中随机删除。

# allkeys-random -> 在所有key中随机删除。

# volatile-ttl -> 在设置了过期时间key中删除最早过期时间的。

# noeviction ->  不删除key,超过时报错。


Lru和lfu算法


LRU 

LRU(least recently used) 最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高。LRU算法实现简单,运行时性能也良好,被广泛的使用在缓存/内存淘汰中。

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


 LFU 

        Least  Frequently Used(最近最不经常使用)如果一个数据在最近一段时间很少被访问到, 那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰。

LRU 和LFU的区别

LRU淘汰时淘汰的是链表最尾部的数据。而LFU是一段时间内访问次数最少的

何时淘汰数据 


 1.消极方法(passive way):在读取数据时先判断是否过期,如果过期删除他,例如:get、hget、hmget等

2.积极算法(active way)周期性判断是否有失效内容,如果有就删除。

3.主动删除:当超过阈值时会删除。

在Redis中每次新增数据都会判断是否超过阈值。如果超过了,就会按照淘汰策略删除一些key。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值