关于缓存穿透以及简单的处理方式

简介: 1、什么是缓存穿透        缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

1、什么是缓存穿透

        缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

如图1-1为简单的通过缓存提高系统吞吐量的系统,访问请求会先通过去访问缓存,缓存中未找到的时候再去查询数据库,(此处提及一下,优化到极致的mysql的数据库连接为300-700之间,300为机械硬盘数据,700为固态硬盘数据)

        如果这个请求是一个比较消耗时间的sql,比如说电商中的查询总消费额这种,会消耗比较大的数据库资源,这种数据一般会放入缓存中,我们此处可以据一个例子sql:select sum(money) from order where userCode = '123';查询出来的数据,以userCode为key,以结果为value存入到缓存中,这种方法有一定的漏洞,如果我们找到一个根本就不存在的userCode,进行查询,这样的话每次查询都会绕过缓存,直接访问到数据库,只要我这边并发访问量稍微多一点,基本就能把mysql跑崩溃。

img_c370fe6d14cc86c107a3892ab021dfe8.png
图1-1

2、如何处理缓存穿透

        处理缓存穿透的方法有很多,其实无外乎就是对数据进行过滤筛选,把真正有效的数据进行访问,无效数据直接过滤掉。

        1、在某些特定场景下(登录),进行验证码,这种方法并不是很安全,因为目前图像识别技术在很大程度上能够解决验证码的问题,所以仅供简单使用。

        2、布隆过滤器:这个是需要着重说明的一种方法,

       首先我们需要对数据进行过滤,肯定要查询一下这个数据是否存在,比较简单的就是直接查询数据库,"select  userCount from user where userCode = '123';",但是其实这种意义并不大,因为查询的过程其实也是要建立数据库链接的,唯一优化的是查询这种查询语句速度更快,对于并发的数据量处理速度可能会快一点,但是当黑客攻击并发量再高一点的时候,此时这种方式可能也就扛不住了。

        此时我们该怎么处理呢?还是缓存,我们把代表数据标识位的数据放到缓存中,查询数据库之前先去缓存中查询一下是否存在如果数据存在的话,再做后续的操作。这种做法还算是比较有效的,但是唯一的缺点就是用户量比较大的时候讲所有的用户存储在内存中,对内存的负载压力太大,需要比较高的内存,很容易把内存撑爆。

        或者我们可以通过solr等搜索引擎这种方式进行搜索,这种方式后面再说。

        此处我们选用布隆过滤器进行查询,算法的简单图解如下图2-1:


img_ebffa59f7a97a8c05202b07062695694.png
图2-1

        因为我们只需要判断客户端传过来的userCode是否存在就可以,图中的hash1,hash2,hash3分别代表着三种不同的hash算法,你可以认为是md5,sha1,sha256等等,不同的userCode对应着不同的数据位,当需要校验的时候,判断每一种算法的得出来的byte位是否相同,只要一位不同,那么我们可以认为这个userCode不存在,直接返回就不存在就可以,这种方法就可以在很大程度上避免黑客攻击的情况。当然这种方法存在一定的风险,因为无论哪一种hash算法都会有hash碰撞,即使是几种算法在一块,仍会有这种可能(只不过是可能性非常小而已),在此需要根据具体的情况进行分析,而且一般情况下不能从布隆过滤器里面删除数据,还有就是创建布隆过滤器的时候byte数组的长度需要先确定初始化,这个数组长度和hash函数不太好确定。

        关于布隆过滤器的代码,这里可以推荐一款比较好用的java库,Google Guava

在此附上一个例程代码


package com.kevin.demo;

import com.google.common.base.Charsets;

import com.google.common.hash.BloomFilter;

import com.google.common.hash.Funnels;

import java.util.*;

/**

* google guava实现 bloom filter

* bitArray,numHashFunction,funnel,Strategy,put()

* demo实例

* 场景描述:100W字符放入布隆过滤器中,另外随机生成1W字符串,判断他们在100W里面是否存在

*/

public class demo {

private static final int insertions =1000000;//100W

    public static void main(String[] args) {

//创建一个布隆过滤器对象,初始化字符集和100W大小

        BloomFilter bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),insertions);

        //初始化一个存储String数据的set,初始化大小100W

        Set sets =new HashSet(insertions);

        //初始化一个存储String数据的list,初始化大小100W

        List lists =new ArrayList(insertions);

        //向三个容器中初始化100W个随机数据

        for (int i =0; i

String uuid = UUID.randomUUID().toString();

            bf.put(uuid);

            sets.add(uuid);

            lists.add(uuid);

        }

int wrong =0;//纪录错误次数

        int right =0;//纪录正确次数

// 随机生成1W字符串

        for (int i =0; i <10000; i++) {

String test = i%100==0?lists.get(i/100):UUID.randomUUID().toString();//按照一定比例选择BF中肯定存在的

            if(bf.mightContain(test)){

if(sets.contains(test)){

right++;

                }else {

wrong++;

                }

}

}

        System.out.println("========right======="+right);

        System.out.println("========wrong======="+wrong);

    }

}



相关文章
|
3月前
|
存储 缓存 监控
缓存击穿、缓存穿透、缓存雪崩 3大问题,如何彻底解决?
【10月更文挑战第8天】在分布式系统中,缓存的使用极大地提高了系统的性能和响应速度。然而,缓存击穿、缓存穿透和缓存雪崩是三个常见的缓存相关问题,它们可能导致系统性能下降,甚至引发系统崩溃。本文将深入探讨这三个问题的成因、影响以及彻底的解决方案。
121 1
|
3月前
|
缓存 NoSQL 关系型数据库
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
本文深入探讨了Redis缓存的相关知识,包括缓存的概念、使用场景、可能出现的问题(缓存预热、缓存穿透、缓存雪崩、缓存击穿)及其解决方案。
244 0
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
|
5月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
13天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
2月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
2月前
|
缓存 NoSQL 数据库
缓存穿透、缓存击穿和缓存雪崩及其解决方案
在现代应用中,缓存是提升性能的关键技术之一。然而,缓存系统也可能遇到一系列问题,如缓存穿透、缓存击穿和缓存雪崩。这些问题可能导致数据库压力过大,甚至系统崩溃。本文将探讨这些问题及其解决方案。
|
2月前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
75 10
|
2月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
61 5
|
2月前
|
缓存 监控 NoSQL
Redis 缓存穿透及其应对策略
【10月更文挑战第23天】通过以上对 Redis 缓存穿透的详细阐述,我们对这一问题有了更深入的理解。在实际应用中,我们需要根据具体情况综合运用多种方法来解决缓存穿透问题,以保障系统的稳定运行和高效性能。同时,要不断关注技术的发展和变化,及时调整策略,以应对不断出现的新挑战。
59 4
|
3月前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
81 4