预防缓存穿透方案设计

预防缓存穿透方案设计

前言

最近公司有一些公司频繁发生一些重大故障, 加上最近核心域凌晨比较多的一些缓存超时(Caused by: net.spy.memcached.internal.CheckedOperationTimeoutException: Timed out waiting for operation),不得不让人提高警惕。此时间段超时比较多,是因为该时间段是缓存预热高峰期。

排查有3种原因:

  1. memcached服务端支持的并发连接数已满,spymemcache客户端操作超时;
  2. memcache客户端添加获取数据时,主要spymemcache是基于nio异步获取的,所以当获取数据时会把任务添加任务队列等待执行,同时spymemcache也会做数据获取的链接超时验证,如果超过设置的超时时间(默认时间2500ms)就会报异常;
  3. 一次性get的key过多;

目前该超时在总请求数占比相对很小,假如某个时间点,有大部分超时,将导致大部分缓存穿透,对mysql数据库造成巨大压力。下面我们讨论一些关于缓存穿透的一些预防措施及相关设计。

缓存穿透

我们先来了解一下缓存穿透的定义

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题.

业界有两种常用预防缓存穿透的方法

(1)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
(2)如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,这个根据业务上允许的时间为准。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!

针对第一种方法,大体的预防方案设计如下图
在这里插入图片描述

在访问所有资源(cache, storage)之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,例如: 我们的价格服务有1亿个sku, 我们可以对所有sku对应的key做一份布隆过滤器,这样可以过滤掉一些不在本系统定价的一些请求,减少cache\storage资源的压力。

扫描二维码关注公众号,回复: 4063757 查看本文章

伪代码如下

if (!bloomfilter.mightContain(key)) {
   return null;
}
String value = redis.get(key);
if (value == null) {
   return null;
} else {
   //这里用mutex锁实现单线程回源i)
   value = getFromCacheDb(key);
}
return value;

private String getFromCacheDb(String key) {
   String redis = null;
   String value = redis.get(key);
   if (value == null) {
      value = db.get(key);
      redis.set(key, value, expire_secs);
      redis.del(key_mutex);
   } else{
      sleep(50);
      getFromCacheDb(key);//重试
   }
   return value;
}

一、布隆过滤器是什么?

  1. 又快又小的处理方法
  2. 布隆过滤器(Bloom Filter):是一种空间效率极高的概率型算法和数据结构,用于判断一个元素是否在集合中(类似Hashset)。
  3. 它的核心一个很长的二进制向量和一系列hash函数
  4. 数组长度以及hash函数的个数都是动态确定的
  5. Hash函数:SHA1,SHA256,MD5…
    在这里插入图片描述

二、优势和劣势

优势

  1. 全量存储但是不存储元素本身,在某些对保密要求非常严格的场合有优势;
  2. 空间高效率
  3. 插入/查询时间都是常数O(k),远远超过一般的算法

劣势

  1. 存在误算率(False Positive),随着存入的元素数量增加,误算率随之增加;
  2. 一般情况下不能从布隆过滤器中删除元素;
  3. 数组长度以及hash函数个数确定过程复杂;

参考文章:
https://en.wikipedia.org/wiki/Bloom_filter
http://www.cnblogs.com/haippy/archive/2012/07/13/2590351.html
https://github.com/erikdubbelboer/Redis-Lua-scaling-bloom-filter
https://www.cnblogs.com/atomicbomb/p/8979582.html

猜你喜欢

转载自blog.csdn.net/vipshop_fin_dev/article/details/82985659
今日推荐