缓存优化

Posted 程序员爱学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓存优化相关的知识,希望对你有一定的参考价值。

1.穿透优化

缓存穿透 是指查询一个根本不存在的数据,缓存层和存储层都不会命中,由于每次请求都要到存储层去查询,导致存储层负载加大,造成存储层宕机。

1.1 缓存空对象
当客户端查询数据不存在时,将空对象保留到缓存中,之后在访问这个数据将会从缓存中获取,有效的减轻了存储层的压力。伪代码如下:

 1String cacheValue = redis.get(key)
2if(isNull(cacheValue)){
3    String dbValue=mysql.get(key);
4    redis.set(key,dbValue);
5    if(dbValue == null){
6      redis.expire(key,expireTime);
7    }
8    return dbValue;
9}else{
10   return cacheValue;
11}

缓存空对象需要更多的缓存空间,而且会出现数据不一致的情况。

1.2 布隆过滤器
在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来。bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中,可以利用Redis的Bitmaps实现布隆过滤器。

布隆过滤器的相关知识可以参考:https://www.cnblogs.com/liyulong1982/p/6013002.html

2.雪崩优化

由于在同一时刻出现 大面积的缓存过期,所有原本应该访问缓存的请求都去查询数据库了,造成存储层负载巨大压力,严重导致数据库宕机。

2.1 加锁
利用加锁的方式保证不会有大量的并发请求对数据库一次性进行读写,从而避免缓存失效时大量的并发请求查询数据库。伪代码如下:

 1String get(String key){
2    //从redis中获取数据
3    String value = redis.get(key);
4    if(value=null){
5      //只允许一个线程重构缓存
6      String mutexKey= "mutex:key:"+key;
7      if(redis.set(mutexKey,"1","ex 180","nx")){
8        //从数据库获取数据
9         value = db.get(key);
10         //写redis,设置过期时间
11         redis.setex(key,timeout,value);
12         //删除互斥锁
13         redis.delete(mutexKey);
14      }else{
15          Thead.sleep(50);
16          get(key);
17      }
18    }
19  return value;
20}

2.2 设置不过期
该方法就是缓存不设置过期时间,另外可以为value设置一个逻辑过期时间,当发现超过逻辑时间,会使用单独的线程去数据库重新获取数据。该方法会产生数据不一致的情况。伪代码如下:

 1String get(String key){
2    V v = redis.get(key);
3    String value = v.getValue();
4    //获取逻辑过期时间
5    long logicTimeout = v.getLogicTimeout();
6    //如果逻辑过期时间小于当前时间,开始重新获取数据
7    if(v.logicTimeout<=System.currentTimeMillis()){
8      String mutexKey = "mutex:key:"+key;
9      if(redis.set(mutexKey,"1","ex 180","nx")){
10         theadPool.execute(new Runnable(){
11              public void run(){
12                   String dbValue = db.get(key);
13                   redis.set(key,(dbvalue,newLogicTimeout));
14                   redis.delete(mutexKey);
15              }
16         })
17      }
18    }
19     return value;
20}

3.参考资料

《Redis开发与运维》



以上是关于缓存优化的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 反转句子中的每个单词需要对我的代码片段进行代码优化

如何优化C ++代码的以下片段 - 卷中的零交叉

C# Cache的一些总结

从JVM的角度看JAVA代码--代码优化

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题