使用緩存降低數據庫并發(fā)讀寫

前言

隨著系統(tǒng)的并發(fā)量增加亮蒋,數據庫的并發(fā)讀寫最終將成為整個提供的瓶頸献幔,甚至壓垮整個數據庫,導致系統(tǒng)卡死等嚴重問題虹蓄。通過緩存是緩解數據庫壓力的重要手段犀呼,通過緩存把絕大多數請求在讀寫數據庫前攔截掉,大大降低數據庫壓力薇组。

緩存設計思想及方案

緩存設計最核心的原則就是讓數據離用戶更近外臂。優(yōu)秀的緩存設計直接影響到系統(tǒng)的高并發(fā)性能和響應速度,甚至影響客戶體驗律胀。
緩存有三個作用范圍:

  • 事務宋光、
  • 應用、
  • 集群

緩存設計方案

緩存按照存放位置不同可以分為客戶端緩存和服務端緩存炭菌。

緩存分層

客戶端緩存:

  • 瀏覽器緩存
  • 網關及代理服務器緩存:

服務器緩存:

  • 本地緩存:
  • 分布式緩存:
  • 數據庫緩存:

一個好的緩存設計方案需要綜合考慮緩存的存儲罪佳、使用時機、優(yōu)缺點黑低、以及分布式高并發(fā)下緩存一致性赘艳、緩存命中、緩存擊穿/雪崩等問題克握。

緩存詳細設計方案

客戶端緩存

客戶端緩存通常指web前端緩存蕾管,可以分為:瀏覽器緩存和代理服務器緩存。是目前網站前端加速的主要方式菩暗,其實現基本方式是:將制定的網站資源(整體頁面娇掏、靜態(tài)文件(js、css勋眯、圖片)等)周期性緩存起來婴梧,緩存時間可以從幾秒到幾天不等下梢,極大減少了網站應用服務器和數據庫負荷。

瀏覽器緩存
瀏覽器緩存是最靠近客戶的緩存機制塞蹭,當開啟瀏覽器緩存后孽江,客戶訪問同一個頁面將不從服務器下載頁面,也是從瀏覽器本地緩存目錄讀取頁面番电,然后在瀏覽器中展示岗屏。對于不常變化資源可以使用強制緩存策略,而精彩變動資源可以禁止瀏覽器緩存漱办。瀏覽器緩存更新問題解決:可以在資源的引用地址(路徑)后面增加hash这刷、版本號等動態(tài)字符,從而達到更新資源引用URL目的娩井,讓之前的緩存強制失效(PS:其實并未立即失效暇屋,而是不在使用)。
網關或代理服務器緩存
將網頁緩存到代理服務器上洞辣,多個用戶訪問同一個頁面時咐刨,將直接從代理服務器把頁面?zhèn)魉徒o用戶。常見實現如扬霜,Ngnix反向代理緩存定鸟。使用反向代理服務器緩存實現簡單,通常通過簡單配置便可以實現著瓶,而不需要外增加代碼開發(fā)联予。反向代理服務器緩存適合實時性要求不高或者經常不變的頁面,如果門戶首頁材原、商品詳情等頁面沸久。

服務端緩存

在服務端編程中,緩存主要是將數據庫中數據加載到內存中华糖,之后對該數據的讀寫都是在內存中完成麦向,減少對數據庫的訪問瘟裸,是解決高并發(fā)場景數據庫并發(fā)讀寫瓶頸的主要手段之一客叉。同時基于內存的讀寫處理速度高于磁盤I/O,緩存也是提高服務響應速度和性能重要手段话告。
根據緩存是否與應用在同一進程兼搏,可以將緩存分為本地緩存和分布式緩存:

  • 本地緩存:應用同一進程內存空間緩存數據,數據讀寫都在同一進程沙郭。
  • 分布式緩存:獨立部署的進程佛呻,通常與應用進行部署在不同機器,緩存的讀寫需要通過網絡來完成數據的傳輸病线。

本地緩存

本地緩存優(yōu)缺點

  • 訪問速度快吓著,但無法緩存大數據:本地緩存不需要跨網絡傳輸鲤嫡,性能更好,但是由于本地緩存使用應用進程的內存空間绑莺,不能進行大數據存儲暖眼。
  • 集群數據更新問題:本地緩存只支持本地進程應用訪問,其他進程應用無法訪問纺裁,因此需要額外的機制來保證數據的一致性诫肠,實現復雜度高且容易出錯。比如通過redis或zookeeper實現分布式同步欺缘。
  • 數據隨應用進程重啟而丟失栋豫。

適用場景
本地緩存適用于緩存只讀數據,如字典谚殊、統(tǒng)計類數據丧鸯,以及進程獨立數據,如本地長連接服務络凿。
本地緩存實現

  1. Java堆緩存
    使用Java堆內存來緩存數據骡送。沒有對象的序列化和反序列化,是最快的緩存絮记。在編程中常用HashMap和ConcurrentHashMap來實現本地緩存摔踱。Java堆緩存應該避免大數據量緩存(可能導致GC停頓時間過長),同時可以使用軟引用/弱引用來緩存對象怨愤,可以使當內存不足時派敷,強制回收這部分對象,釋放內存撰洗。Java堆內存一般用于緩存存儲較熱的數據篮愉。
  2. memcached/ecache
    ecache是基于java的開源高效的、進程內緩存解決方案差导。ecache輕量试躏、簡單,被廣泛應用于其他ORM框架數據緩存的底層實現(如Hinernate)设褐。
    memcached和ecache實現原理類似颠蕴,基于K-V將數據緩存到內存,memcached支持多線程操作助析。相比ecache犀被,memcached更加靈活。
  3. caffeine
    Caffeine是基于Java 8的高性能緩存庫外冀,可提供接近最佳的命中率寡键。Caffeine與ConcurrentMap類似,但是Caffeine與ConcurrentMap最根本的區(qū)別是雪隧,ConcurrentMap會保留添加到其中的所有元素西轩,直到將其明確刪除為止员舵,而Caffeine能自動的回收存儲的元素。
    通過caffeine基準測試藕畔,可以看到caffeine在讀寫方面明顯優(yōu)與其他框架固灵,在緩存命中率上Caffeine也不同于Guava,采用了更為優(yōu)秀的Window TinyLfu算法劫流,該算法是在LRU的基礎上改進的版本巫玻。

分布式緩存

分布式緩存也叫進程外緩存,通常是獨立于應用部署祠汇,通過網絡進行緩存讀寫的數據傳輸仍秤。
分布式緩存優(yōu)缺點

  • 支持大量數據存儲,不受應用進行重啟影響:分布式緩存是獨立部署的進程可很,擁有獨立的內存空間诗力,并且一般以集群的方式拓展,故而可以進行大數據儲存我抠。
  • 數據集中存儲苇本,保證數據一致性:當應用采用集群部署時,集群每個節(jié)點通過統(tǒng)一的分布式緩存服務進行數據的讀寫操作菜拓,不存在本地緩存中數據更新問題瓣窄,保證不同節(jié)點應用進行的數據一致性問題。
  • 數據讀寫分離纳鼎、高性能俺夕、高可用:分布式緩存一般支持數據副本機制,可以實現讀寫分離贱鄙,可以解決高并發(fā)場景中數據讀寫性能問題劝贸。并且由于在多節(jié)點緩存冗余數據,提高了存儲數據的可用性逗宁,避免某個節(jié)點宕機導致數據不可用映九。
  • 數據基于網絡傳輸,性能低于本地緩存瞎颗。

分布式緩存實現
redis/memcached
分布式緩存一致性方案
緩存一致性問題主要是數據庫和緩存的讀寫一致性問題件甥。

首先給緩存設置過期時間是保證緩存最終一致性解決方案,所有數據的寫操作以數據庫為準言缤,對緩存盡最大努力嚼蚀。

緩存更新策略:
先更新數據庫再失效緩存

  • 失效:應用先從緩存獲取數據禁灼,如果沒有從數據庫讀取管挟,成功后放入緩存。
  • 命中:應用從緩存讀取數據弄捕,命中后返回
  • 更新:先更新數據庫僻孝,然后失效緩存(延時雙刪)

緩存穿透及解決方案

緩存穿透是指key對應的數據源不存在导帝,導致每次針對key的請求都無法從存儲層獲取數據并寫入到緩存,從而每次請求都落到數據庫穿铆,失去了緩存意義您单。流量大時可能就拖垮了DB。

解決方案

  • 方案一:對于查詢返回為空的數據荞雏,仍存儲到緩存(需要設置緩存過期時間盡可能短)
  • 方案二:使用布隆過濾器虐秦,將可能存在的數據hash到足夠大bitmap中,一個一定不存在的數據可以通過布隆過濾器攔截掉凤优。

緩存擊穿及解決方案

緩存擊穿主要出現在高并發(fā)的熱點數據訪問場景悦陋。導致緩存擊穿原因主要是同一時間發(fā)生消除讀寫(刪),導致并發(fā)下緩存失效筑辨“呈唬或者是并發(fā)讀取緩存時,恰巧達到緩存失效還來不及從數據庫讀取并寫入緩存棍辕。

解決方案

  1. 比較常見的方法是使用使用互斥鎖(mutex)機制暮现,當緩存失效時,不是立即去load DB楚昭,而是先執(zhí)行set mutex(比如redis的setnx)栖袋,如果操作成功,則load DB并寫入緩存抚太,如果操作失敗則重試get緩存栋荸。
  2. 另外可以對某些靜態(tài)熱點數據使用永不過期策略。

緩存雪崩及解決方案

是指設置緩存相同的過期時間凭舶,如果一些應用初始加載緩存晌块,采用并發(fā)寫策略(多線程),導致了某一時間緩存全部失效帅霜,請求全部轉發(fā)到DB匆背,DB瞬時壓力過大雪崩。高并發(fā)應用的緩存雪崩對于底層系統(tǒng)沖擊非成砑剑可怕钝尸。

解決方案

  • 考慮加鎖或者隊列方式寫緩存,避免緩存過期時間一致
  • 在設置緩存是在原有緩存失效時間基礎加上一個隨機值搂根,降低過期時間的重復率珍促。
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市剩愧,隨后出現的幾起案子猪叙,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件穴翩,死亡現場離奇詭異犬第,居然都是意外死亡,警方通過查閱死者的電腦和手機芒帕,發(fā)現死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門歉嗓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人背蟆,你說我怎么就攤上這事鉴分。” “怎么了带膀?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵冠场,是天一觀的道長。 經常有香客問我本砰,道長碴裙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任点额,我火速辦了婚禮舔株,結果婚禮上,老公的妹妹穿的比我還像新娘还棱。我一直安慰自己载慈,他們只是感情好,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布珍手。 她就那樣靜靜地躺著办铡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琳要。 梳的紋絲不亂的頭發(fā)上寡具,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音稚补,去河邊找鬼童叠。 笑死,一個胖子當著我的面吹牛课幕,可吹牛的內容都是我干的厦坛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乍惊,長吁一口氣:“原來是場噩夢啊……” “哼杜秸!你這毒婦竟也來了?” 一聲冷哼從身側響起润绎,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤撬碟,失蹤者是張志新(化名)和其女友劉穎诞挨,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體小作,經...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年稼钩,在試婚紗的時候發(fā)現自己被綠了顾稀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡坝撑,死狀恐怖静秆,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情巡李,我是刑警寧澤抚笔,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站侨拦,受9級特大地震影響殊橙,放射性物質發(fā)生泄漏。R本人自食惡果不足惜狱从,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一膨蛮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧季研,春花似錦敞葛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驼卖,卻和暖如春氨肌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酌畜。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工儒飒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人檩奠。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓桩了,卻偏偏與公主長得像,于是被迫代替她去往敵國和親埠戳。 傳聞我的和親對象是個殘疾皇子井誉,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內容