百度怎么自己做網(wǎng)站嗎發(fā)稿服務(wù)
緩存熱key一旦被擊穿,流量勢(shì)必會(huì)打到數(shù)據(jù)庫(kù),如果數(shù)據(jù)庫(kù)崩了,游戲直接結(jié)束。
從兩點(diǎn)來(lái)討論:如何監(jiān)控、如何解決。
如何監(jiān)控
- 通過(guò)業(yè)務(wù)評(píng)估:比如營(yíng)銷活動(dòng)推出的商品或者熱賣的商品。
- 基于LRU的命令,redis-cli --hotkeys,通過(guò)任務(wù)調(diào)度定時(shí)去獲取?
- 基于redis客戶端、或者代理層、或者redis監(jiān)控策略,利用大數(shù)據(jù)領(lǐng)域的流式計(jì)算技術(shù)(如Storm、Spark Streaming、Flink)進(jìn)行實(shí)時(shí)數(shù)據(jù)訪問(wèn)次數(shù)的統(tǒng)計(jì),一旦發(fā)現(xiàn)熱點(diǎn)數(shù)據(jù),即可進(jìn)行處理。
分析
為什么不直接訪問(wèn)數(shù)據(jù)庫(kù)獲取數(shù)據(jù)?
因?yàn)閿?shù)據(jù)庫(kù)主要是為了增量數(shù)據(jù)持久化,資源寶貴;庫(kù)的并發(fā)連接數(shù)也有瓶頸;不好抗啊。
為什么要使用緩存?
緩存可以抗住海量并發(fā);內(nèi)存操作,速度快;
怎么保證緩存性能?
緩存預(yù)熱;
緩存中間抗不住怎么辦?
采用多級(jí)緩存,先訪問(wèn)本地緩存,再訪問(wèn)Redis緩存,減輕壓力;增加Redis節(jié)點(diǎn);
本地緩存需要注意些什么?
緩存核心(最)熱點(diǎn)的數(shù)據(jù);控制好緩存數(shù)據(jù)量級(jí);堆內(nèi)存啊,別OOM了;
緩存失效怎么辦?
在訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候加鎖,控制流量,允許一個(gè)請(qǐng)求訪問(wèn)數(shù)據(jù)庫(kù),其他流量等待。
加什么鎖?jvm鎖還是分布式鎖?
加本地鎖就夠了,數(shù)據(jù)庫(kù)還沒(méi)那么不堪一擊,而且本地鎖無(wú)網(wǎng)絡(luò)開(kāi)銷、輕量快捷。
緩存哪些數(shù)據(jù)?
上面說(shuō)了如何監(jiān)控?zé)狳c(diǎn)數(shù)據(jù);關(guān)于動(dòng)態(tài)的熱點(diǎn)數(shù)據(jù)也需要實(shí)時(shí)監(jiān)控?
還有什么兜底方案嗎?
針對(duì)數(shù)據(jù)庫(kù)流量進(jìn)行限流,做最后的防護(hù);
怎么做流量預(yù)估?
業(yè)務(wù)評(píng)估;全鏈路壓測(cè);
怎么保證可用性?
止血方案(開(kāi)關(guān)、配置);監(jiān)控;降級(jí)策略;擴(kuò)容;
如何應(yīng)對(duì)RPC線程池溢出造成的QPS瓶頸問(wèn)題?
在客戶端做一層緩存,同服務(wù)端緩存的邏輯一樣。
如何解決
- 評(píng)估流量(redis和mysql是否能扛得住)
- 熱key進(jìn)行拆分,分散到不同的redis節(jié)點(diǎn);增加redis節(jié)點(diǎn)
- 多級(jí)緩存,本地緩存 -》 redis緩存
- 如下策略:加鎖+限流
偽代碼
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;}
}