缓存相关问题及解决方案

缓存相关问题及解决方案

缓存雪崩

问题: 指设置缓存时大面积的数据采用相同的过期时间,导致这一面积的缓存在某一时刻集体失效,所有请求落在数据库上,数据库压力过大。

解决方案: 在设置过期时间时,在一定的范围内使用随机值,尽可能降低过期时间的重复率。

缓存击穿

问题: 对于某个可能被超高并发访问的热点数据,在某个时刻突然失效,那对于这个数据的查询都落在数据库上,数据库压力过大。

解决方案:

  • 对于热点数据的过期时间够长。
  • 使用互斥锁,并发时只让一个请求去查询数据库,并保存在缓存里,其它请求再从缓存中查询。

缓存穿透

问题: 指查询一个一定不存在的数据,缓存未命中,去查询数据库,但是数据库也没有该记录,返回为 null,不写入缓存里。之后每次查询这个不存在的数据都要穿透到数据库查询。高并发下数据库压力过大。

解决方案:

  • 将该不存在的数据返回的 null 结果缓存,加上短暂的过期时间。
  • 布隆过滤器。

布隆过滤器相关内容介绍

特点:

  • 元素判断为存在的时候,其实不一定存在;
  • 元素判断为不存在的时候,一定不存在。

缺点:以上特性导致,想要从布隆过滤器中删除一个元素的时候,可能会误删元素。

优点:在空间和时间上的优势都很明显

Java 实现(随意版)

package com.lvshui5u.datastructure.redis;

import java.util.BitSet;

/**
 * @author: lvshui5u
 * @date: 2021/8/20 11:24
 * @describe:
 */
public class BloomFilter {

    /**
     * 默认大小为 2^30,这个大小应该是有讲究的,但是我讲究不明白
     */
    private static final int DEFAULT_SIZE = 1 << 30;
    /**
     * 布隆过滤器主体
     */
    private static final BitSet SET = new BitSet(DEFAULT_SIZE);
    /**
     * 算法种子,六个种子代表六个 hash 算法
     */
    private static final int[] SEEDS = {3,5,7,11,13,31};
    /**
     * 六个种子代表六个 hash 算法
     */
    private static final HashFunction[] FUNCTIONS = new HashFunction[SEEDS.length];
    /**
     * hash 方法初始化
     */
    static {
        for (int i = 0; i < SEEDS.length; i++) {
            FUNCTIONS[i] = new HashFunction(DEFAULT_SIZE, SEEDS[i]);
        }
    }

    /**
     * 将某个值加入到 BloomFilter 里,其实添加了 6 个位置
     * @param value
     */
    public void add(String value){
        if(value != null){
            for (HashFunction function : FUNCTIONS) {
                int hash = function.hash(value);
                SET.set(hash);
            }
        }
    }

    /**
     * 是否包含
     * @param value
     * @return
     */
    public boolean contains(String value){
        boolean res = true;
        if(value != null){
            for (HashFunction function : FUNCTIONS){
                int hash = function.hash(value);
                boolean b = SET.get(hash);
                // 有一个位置对不上 就不存在
                res &= b;
            }
        }
        return res;
    }

    public int size(){
        return SET.size();
    }

    public int length(){
        return SET.length();
    }

    static class HashFunction{
        private final int size;
        private final int seed;
        public HashFunction(int size, int seed){
            this.size = size;
            this.seed = seed;
        }
        public int hash(String value){
            int hash = 0;
            char[] chars = value.toCharArray();
            for (char ch : chars) {
                hash = hash * seed + ch;
            }
            return (size-1) & hash;
        }
    }
}

实验

package com.lvshui5u.datastructure.redis;

/**
 * @author: lvshui5u
 * @date: 2021/8/20 14:59
 * @describe:
 */
public class BloomFilterTest {
    public static void main(String[] args) {
        BloomFilter bloomFilter = new BloomFilter();
        for (int i = 0; i < 100000; i++) {
            bloomFilter.add("helloWorld-" + i);
        }

        System.out.println(bloomFilter.contains("helloWorld-1"));
        System.out.println(bloomFilter.contains("helloWorld-9"));
        System.out.println(bloomFilter.contains("helloWorld-10"));
        System.out.println(bloomFilter.contains("helloWorld-99"));
        System.out.println(bloomFilter.contains("helloWorld-100"));
        System.out.println(bloomFilter.contains("helloWorld-999"));
        System.out.println(bloomFilter.contains("helloWorld-1000"));
        System.out.println(bloomFilter.contains("helloWorld-9999"));
        System.out.println(bloomFilter.contains("helloWorld-10000"));
        System.out.println(bloomFilter.contains("helloWorld-99999"));
        System.out.println(bloomFilter.contains("helloWorld-100000"));
    }

}

结果

true
true
true
true
true
true
true
true
true
true
false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值