商品中心关于缓存热key的解决方案

avatar
作者
筋斗云
阅读量:0

缓存热key一旦被击穿,流量势必会打到数据库,如果数据库崩了,游戏直接结束。

从两点来讨论:如何监控、如何解决。

如何监控

  1. 通过业务评估:比如营销活动推出的商品或者热卖的商品。
  2. 基于LRU的命令,redis-cli --hotkeys,通过任务调度定时去获取?
  3. 基于redis客户端、或者代理层、或者redis监控策略,利用大数据领域的流式计算技术(如Storm、Spark Streaming、Flink)进行实时数据访问次数的统计,一旦发现热点数据,即可进行处理。

分析

为什么不直接访问数据库获取数据?
因为数据库主要是为了增量数据持久化,资源宝贵;库的并发连接数也有瓶颈;不好抗啊。

为什么要使用缓存?
缓存可以抗住海量并发;内存操作,速度快;

怎么保证缓存性能?
缓存预热;

缓存中间抗不住怎么办?
采用多级缓存,先访问本地缓存,再访问Redis缓存,减轻压力;增加Redis节点;

本地缓存需要注意些什么?
缓存核心(最)热点的数据;控制好缓存数据量级;堆内存啊,别OOM了;

缓存失效怎么办?
在访问数据库的时候加锁,控制流量,允许一个请求访问数据库,其他流量等待。

加什么锁?jvm锁还是分布式锁?
加本地锁就够了,数据库还没那么不堪一击,而且本地锁无网络开销、轻量快捷。

缓存哪些数据?
上面说了如何监控热点数据;关于动态的热点数据也需要实时监控?

还有什么兜底方案吗?
针对数据库流量进行限流,做最后的防护;

怎么做流量预估?
业务评估;全链路压测;

怎么保证可用性?
止血方案(开关、配置);监控;降级策略;扩容;

如何应对RPC线程池溢出造成的QPS瓶颈问题?
在客户端做一层缓存,同服务端缓存的逻辑一样。

如何解决

  1. 评估流量(redis和mysql是否能扛得住)
  2. 热key进行拆分,分散到不同的redis节点;增加redis节点
  3. 多级缓存,本地缓存 -》 redis缓存
  4. 如下策略:加锁+限流

伪代码

public class Main {      private static final ReentrantLock lock = new ReentrantLock();      private static final  AtomicInteger retryCount = new AtomicInteger(0);      public String getCacheValue(String key) throws Exception {  		try{ 	        String result = cache.get(key); 	 	        if (result == null) { 	            boolean b = lock.tryLock(200, TimeUnit.MILLISECONDS); 	            if (b || retryCount.get() > 10) { 	                String limit = limit.get(key); 	                if (!limit.equals("限流")) { 	                    result = db.get(key); 	                } 	            } else { 	                Thread.sleep(200); 	                retryCount.incrementAndGet(); 	                result = this.getCacheValue(key); 	            } 	        }         }finally{         	lock.unlock();         }          return result;     } } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!