原文連接:https://mp.weixin.qq.com/s/KRGm26sjlMX8EXUzmN6XEA
在系統(tǒng)設(shè)計時,如果能預(yù)先看到一些問題,并在設(shè)計層面提前解決,就會給后期的開發(fā)帶來很大的便捷。
單系統(tǒng)中的Session對象可以直接保存在內(nèi)存中,但在分布式或集群環(huán)境下,多個不同的節(jié)點就要采取措施來共享Session對象,具體可以使用以下幾種方式。Session Replication 是指在客戶端第一次發(fā)出請求后,處理該請求的服務(wù)端就會創(chuàng)建一個與之對應(yīng)的Session對象,用于保存客戶端的狀態(tài)信息,之后為了讓其他服務(wù)端也能保存一份此Session對象,就需要將此Session對象在各個服務(wù)端節(jié)點之間進行同步,如圖1所示。
Session Sticky是通過Nginx等負載均衡工具對各個用戶進行標記(例如對Cookie標記),使每個用戶在經(jīng)過負載均衡工具后都請求固定的服務(wù)節(jié)點,如圖2所示。
可以將系統(tǒng)中所有的Session對象都存放到一個獨立的Session服務(wù)中,之后各個應(yīng)用服務(wù)再分別從這個Session服務(wù)中獲取需要的Session對象,如圖3所示。在大規(guī)模分布式系統(tǒng)中,就推薦使用這種獨立Session服務(wù)方式。并且這種方式在存儲Session對象時,既可以用數(shù)據(jù)庫,也可以使用各種分布式或集群存儲系統(tǒng)。緩存可以在一定程度上緩解高并發(fā)造成的性能問題,但在一些特定場景下緩存自身也會帶來一些問題,比較典型的就是緩存穿透與緩存雪崩問題。
緩存穿透是指大量查詢一些數(shù)據(jù)庫中不存在的數(shù)據(jù),從而影響數(shù)據(jù)庫的性能。例如Redis等KV存儲結(jié)構(gòu)的中間件可以作為MySQL等數(shù)據(jù)庫的緩存組件,但如果某些數(shù)據(jù)沒有被Redis緩存卻被大量的查詢,就會對MySQL帶來巨大壓力,如圖4所示。
理解了緩存穿透的原因后,解決思路就已經(jīng)明確了,舉例如下。
1)攔截非法的查詢請求,僅將合理的請求發(fā)送給MySQL。
如,可以使用驗證碼、IP限制等手段限制惡意攻擊,并用敏感詞過濾器等攔截不合理的非法查詢。
如,假設(shè)在iphone9上市后,可能會導(dǎo)致大量用戶搜索iphone9,但此時Redis和MySQL中還沒有iphone9這個詞。將數(shù)據(jù)庫中不存在的iphone9也緩存在Redis中,如Key=iphone9,value=””。之后當用戶再次搜索iphone9時,就可以直接從Redis中拿到結(jié)果,從而避免對MySQL的訪問,如圖5所示。
提示:為了減少Redis對大量空對象的緩存,可以適當減少空對象的過期時間。將MySQL中的所有數(shù)據(jù)的name值都映射成hash值,例如可以將“商品表”中的商品名“iphone8”映射成MD5計算出來的hash值,然后再將全部name的hash值放入Redis中,從而構(gòu)建出一個“數(shù)據(jù)庫中所有可查數(shù)據(jù)的hash倉庫”。之后,每次在查詢MySQL之前都會先查詢這個hash倉庫,如果要查詢數(shù)據(jù)的hash值存在于倉庫中,再進入MySQL做真實的查詢,如果不存在則直接返回。需要注意的是,由于不同數(shù)據(jù)的hash值在概率上時可能相同的,因此可能會漏掉對個別數(shù)據(jù)的攔截,如圖6中的“B”。
圖6 不同數(shù)據(jù)的Hash值相同而造成的問題
除了緩存穿透以外,在使用緩存時還需要考慮緩存雪崩的情況。緩存雪崩是指由于某種原因造成Redis突然失效,從而造成MySQL瞬間壓力驟增,進而嚴重影響MySQL性能甚至造成MySQL服務(wù)宕機。?
2)避免大量緩存對象的key集中失效,盡力讓過期時間分配均勻一些,例如,可以給各個緩存的過期時間乘一個隨機數(shù);3)通過隊列、鎖機制等控制并發(fā)訪問MySQL的線程數(shù)。
最近面試BAT,整理一份面試資料《Java面試BAT通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點“在看”,關(guān)注公眾號并回復(fù)?666?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。