博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【商城】redis分布式缓存安全应用(穿透问题)
阅读量:4119 次
发布时间:2019-05-25

本文共 3797 字,大约阅读时间需要 12 分钟。

缓存穿透

什么是缓存穿透?缓存里面不存在数据,数据库里面也不存在的数据。新的请求(例如黑客恶意攻击:https://item.jd.com/6729892714444444.html查询一个不存在商品)进来会不断查询数据库,严重可能会导致数据库服务停止。

Null值返回解决方案:

如果数据库查询不到数据,缓存Null值的对象返回。

布隆过滤器

显然返回Null值方案存在问题,如果查询编码不存在数据,之后又新增了此编号的数据,将导致此数据永远查不到。

布隆过滤器(性能问题不用担心,可以自行查阅资料),例如将商品所有Id加入布隆过滤器,后续访问必须先经过bloom布隆过滤器判断是否存在,如果不存在就直接返回,否则放行。以下是bloom过滤器的redis实现。

bloom.filter.expectedInsertions=10000000bloom.filter.fpp=0.001F// 基于Java 配置@ConfigurationProperties("bloom.filter")@Componentpublic class RedisBloomFilter {    private static final String BLOOM_NAME = "bf.name";    //预计插入量    @Getter @Setter    private long expectedInsertions;    //可接收错误率    @Getter @Setter    private double fpp;    //bit数组长度     @Getter @Setter    private long numBits;    //hash函数数量    @Getter @Setter    private int numHashFunctions;    @Autowired    private RedisTemplate redisTemplate;    @PostConstruct    public void init(){        this.numBits = optimalNumOfBits(expectedInsertions, fpp);        this.numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);    }    /**     * 计算bit数组长度     * @return     */    private long optimalNumOfBits(long n, double p){        if (p == 0){            p = Double.MIN_VALUE;        }        return (long)(-n * Math.log(p) / (Math.log(2) * Math.log(2)));    }    /**     * 计算hash函数个数     * @return     */    private int optimalNumOfHashFunctions(long n, long m){        return Math.max(1, (int)Math.round((double)m / n * Math.log(2)));    }    /**     * 判断keys是否存在于集合中     * @param key     * @return     */    public boolean isExist(String key){        long[] indexs = getIndexs(key);        List list = redisTemplate.executePipelined(new RedisCallback() {            @Nullable            @Override            public Object doInRedis(RedisConnection connection) throws DataAccessException{                connection.openPipeline();                for (long index: indexs){                    //加入布隆过滤器                    connection.getBit(BLOOM_NAME.getBytes(), index);                }                connection.close();                return null;            }        });        return !list.contains(false);    }    /**     * 将key存入redis bitmap     * @param key     */    public void put(String key){        long[] indexs = getIndexs(key);        redisTemplate.executePipelined(new RedisCallback() {            @Nullable            @Override            public Object doInRedis(RedisConnection connection) throws DataAccessException{                connection.openPipeline();                for (long index: indexs){                    //加入布隆过滤器                    connection.setBit(BLOOM_NAME.getBytes(), index, true);                }                connection.close();                return null;            }        });    }    /**     * 根据key获取bitmap的下标     * @param key     * @return     */    private long[] getIndexs(String key){        long hash1 = hash(key);        long hash2 = hash1 >>> 16;        long[] result = new long[numHashFunctions];        for (int i = 0; i < numHashFunctions; i++){            long combineHash = hash1 + i * hash2;            if (combineHash < 0){                combineHash = ~combineHash;            }            result[i] = combineHash % numBits;        }        return result;    }}

实战应用

/*     * 系统初始化,将所有商品ID加入布隆过滤器,后续增加商品ID也加入布隆过利器     * 注意:如果是在分布式情况下,使用分布式锁限定一次创建即可     */    @PostConstruct    public void init(){        List
products = productService.findAll(); products.forEach(p->{ redisBloomFilter.put(String.valueOf(p.getProductId())); }); }
//布隆过滤器判断商品是否存在,不存在直接返回 public Product getProductById(Long productId){       log.debug("查询商品信息id:{}", productId);        //先走布隆过滤器【缓存穿透】       if (!redisBloomFilter.isExist(String.valueOf(productId))){            return null;        }     .......  }

转载地址:http://iccpi.baihongyu.com/

你可能感兴趣的文章
Java代码检查工具Checkstyle常见输出结果
查看>>
北京十大情人分手圣地
查看>>
Android自动关机代码
查看>>
Android中启动其他Activity并返回结果
查看>>
2009年33所高校被暂停或被限制招生
查看>>
GlassFish 部署及应用入门
查看>>
iWatch报错: Authorization request cancled
查看>>
iWatch报错: Authorizationsession time out
查看>>
如何运行从网上下载的iWatch项目详细步骤.
查看>>
X-code7 beta error: warning: Is a directory
查看>>
Error: An App ID with identifier "*****" is not avaliable. Please enter a different string.
查看>>
X-code beta 开发iWatch项目,运行没有错误,但是某些操作一点就崩,而且找不错误的原因场景一
查看>>
Xcode 报错: Extra argument in call
查看>>
iTunes Connect 上传APP报错: Communication error. please use diagnostic mode to check connectivity.
查看>>
#import <Cocoa/Cocoa.h> 报错 Lexical or Preprocessor Issue 'Cocoa/Cocoa.h' file not found
查看>>
`MQTTClient (~> 0.2.6)` required by `Podfile`
查看>>
X-Code 报错 ld: library not found for -lAFNetworking
查看>>
Bitcode
查看>>
If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
查看>>
为什么新手也要学习微服务架构设计?
查看>>