网站开发多长时间,餐厅装修设计,公司建设网站多少钱,静安网站建设哪里有预热雪崩穿透击穿 缓存预热 缓存雪崩 有这两种原因
redis key 永不过期or过期时间错开redis 缓存集群实现高可用 主从哨兵Redis Cluster开启redis持久化aof#xff0c;rdb#xff0c;尽快恢复集群 多缓存结合预防雪崩#xff1a;本地缓存 ehcache redis 缓存服务降级…预热雪崩穿透击穿 缓存预热 缓存雪崩 有这两种原因
redis key 永不过期or过期时间错开redis 缓存集群实现高可用 主从哨兵Redis Cluster开启redis持久化aofrdb尽快恢复集群 多缓存结合预防雪崩本地缓存 ehcache redis 缓存服务降级Hystrix 或者 sentinel 限流降级人民币玩家阿里云给了你多少广告笑
缓存穿透
恶意请求不存在的数据 guava BloomFilter 误判问题但是概率小可以接受不能从布隆过滤器删除 - 布隆过滤器可能会错误地判断某个元素存在于集合中称为误报但不会错误地判断一个存在的元素不存在全部合法的key都需要放入 Guava布隆过滤器redis里面不然数据就是返回null
案例
dependencygroupIdcom.google.guava/groupIdartifactIdguava/artifactIdversion31.1-jre/version
/dependencyService
Slf4j
public class GuavaBloomFilterService {// 1.定义一个常量public static final int _1W 10000;// 2.定义我们guava布隆过滤器初始容量public static final int SIZE 100 * _1W;// 3.误判率它越小误判的个数也越少思考是否可以无限小 没有误判岂不是更好public static double fpp 0.0000000000003; // 这个数越小所用的hash函数越多bitmap占用的位越多 默认的就是0.035个hash函数 0.017个函数// 4.创建guava布隆过滤器private static BloomFilterInteger bloomFilter BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);public void guavaBloomFilter() {// 1. 往 bloomFilter 中添加数据for (int i 0; i SIZE; i) {bloomFilter.put(i);}// 2. 故意取10w个不在范围内的数据进行测试来进行误判率演示ListInteger list new ArrayList(10 * _1W);// 3. 验证for (int i SIZE; i SIZE (10 * _1W); i) {if (bloomFilter.mightContain(i)) {
// log.info(被误判了:{}, i);list.add(i);}}log.info(误判总数量:{}, list.size());log.info(误判率:{}, list.size() / (10 * _1W));}
}
SpringBootTest
public class GuavaTest {ResourceGuavaBloomFilterService guavaBloomFilterService;/*** guava版本布隆过滤器helloworld 入门级演示*/Testpublic void testGuavaWithBloomFilter() {System.out.println(testGuavaWithBloomFilter);// 1. 创建 guava版布隆过滤器BloomFilterInteger bloomFilter BloomFilter.create(Funnels.integerFunnel(), 100);//2. 判断指定的元素是否存在System.out.println(bloomFilter.mightContain(1));System.out.println(bloomFilter.mightContain(2));// 2. 添加数据bloomFilter.put(1);bloomFilter.put(2);System.out.println(bloomFilter.mightContain(1));System.out.println(bloomFilter.mightContain(2));}Testpublic void testGuavaWithBloomFilter2() {guavaBloomFilterService.guavaBloomFilter();}}fpp 默认 0.03 fpp要求越高bit位数越多hash函数越多 guava 黑名单使用 缓存击穿 对比穿透和击穿 互斥更新-对于更新的方法
聚划算案例 功能分析
数据结构使用 list
代码
ApiModel(value 聚划算活动product信息)
AllArgsConstructor
NoArgsConstructor
Data
public class Product {// 产品idprivate Long id;// 产品名称private String name;// 产品价格private Integer price;// 产品详情private String detail;
}Service
Slf4j
public class JHSTaskService {private static final String JHS_KEY jhs;private static final String JHS_KEY_A jhs:a;private static final String JHS_KEY_B jhs:b;AutowiredRedisTemplate redisTemplate;/*** 模拟从数据库读取20件特价商品* return 商品列表*/private ListProduct getProductsFromMysql() {ListProduct list new ArrayList();for (int i 0; i 20; i) {Random random new Random();int id random.nextInt(1000);Product product new Product((long) id, product i, i, detail);list.add(product);}log.info(模拟从数据库读取20件特价商品完成{}, list);return list;}PostConstructpublic void initJHSAB() {log.info(启动AB的定时器 天猫聚划算模拟开始);new Thread(() - {while (true) {// 2.模拟从mysql查到数据加到 redis 并返回给页面ListProduct list getProductsFromMysql();redisTemplate.delete(JHS_KEY);redisTemplate.opsForList().leftPushAll(JHS_KEY, list);redisTemplate.expire(JHS_KEY, 86410L, TimeUnit.SECONDS);// 5.暂停一分钟间隔1分钟执行一次模拟聚划算一天执行的参加活动的品牌try {Thread.sleep(1000* 60);} catch (InterruptedException e) {e.printStackTrace();}}}, t1).start();}}测试类
SpringBootTest
Slf4j
public class JhsTest {private static final String JHS_KEY jhs;private static final String JHS_KEY_A jhs:a;private static final String JHS_KEY_B jhs:b;Autowiredprivate RedisTemplate redisTemplate;Testpublic void find() {int page 1;int size 10;ListProduct list null;long start (page - 1) * size;long end start size - 1;try {list redisTemplate.opsForList().range(JHS_KEY, start, end);if (CollectionUtils.isEmpty(list)) {// TODO 走 mysql 查询}log.info(参加活动的商家{}, list);} catch (Exception e) {// 出异常了一般 redis 宕机了或者redis网络抖动导致timeoutlog.error(jhs exception{}, e);e.printStackTrace();// ..... 重试机制 再次查询 mysql}log.info(list.toString());}}测试方法先跑主启动类后台更新聚划算商品信息然后手动执行测试类测试查询
问题分析 delete 执行间隙这一瞬间缓存击穿打到mysql
解决 PostConstructpublic void initJHSAB() {log.info(启动AB的定时器 天猫聚划算模拟开始);new Thread(() - {while (true) {// 2.模拟从mysql查到数据加到 redis 并返回给页面ListProduct list getProductsFromMysql();// redisTemplate.delete(JHS_KEY);
// redisTemplate.opsForList().leftPushAll(JHS_KEY, list);
// redisTemplate.expire(JHS_KEY, 86410L, TimeUnit.SECONDS);// 3.先更新B缓存并且让B缓存过期时间超过A时间如果A突然失效了还有B兜底防止击穿redisTemplate.delete(JHS_KEY_B);redisTemplate.opsForList().leftPushAll(JHS_KEY_B, list);redisTemplate.expire(JHS_KEY_B, 86410L, TimeUnit.SECONDS);// 4.再更新A缓存redisTemplate.delete(JHS_KEY_A);redisTemplate.opsForList().leftPushAll(JHS_KEY_A, list);redisTemplate.expire(JHS_KEY_A, 86400L, TimeUnit.SECONDS);// 5.暂停一分钟间隔1分钟执行一次模拟聚划算一天执行的参加活动的品牌try {Thread.sleep(1000* 60);} catch (InterruptedException e) {e.printStackTrace();}}}, t1).start();}Testpublic void findAB() {int page 1;int size 10;ListProduct list null;long start (page - 1) * size;long end start size - 1;try {list redisTemplate.opsForList().range(JHS_KEY_A, start, end);if (CollectionUtils.isEmpty(list)) {log.info(---------A缓存已经过期或活动结束了记得人工修补B缓存继续顶着);// A 没有来找 Blist redisTemplate.opsForList().range(JHS_KEY_B, start, end);if (CollectionUtils.isEmpty(list)) {// TODO 走 mysql 查询}}log.info(参加活动的商家{}, list);} catch (Exception e) {// 出异常了一般 redis 宕机了或者redis网络抖动导致timeoutlog.error(jhs exception{}, e);e.printStackTrace();// ..... 重试机制 再次查询 mysql}log.info(list.toString());}小总结