高并發(fā)系統(tǒng)中鎖策略,緩存策略等解決思路
本文一共分析了三個案例,分別介紹并發(fā)系統(tǒng)中的共享資源并發(fā)訪問、計算型密集型任務(wù)緩存訪問 、單一熱點(diǎn)資源峰值流量問題和解決方案。
Q1:訂票系統(tǒng),某車次只有一張火車票,假定有1w個人同時打開12306網(wǎng)站來訂票,如何解決并發(fā)問題?
A1: 首先介紹數(shù)據(jù)庫層面的并發(fā)訪問,解決的辦法主要是樂觀鎖和悲觀鎖。
樂觀鎖
假設(shè)不會發(fā)生并發(fā)沖突,只在提交操作時檢查是否違反數(shù)據(jù)完整性。
樂觀鎖使用一個自增的字段表示數(shù)據(jù)的版本號(或者timestamp),更新的時候檢查版本號是否一致,比如數(shù)據(jù)庫中版本號為4,更新時版本號使用版本號version=5,與數(shù)據(jù)庫中的版本號version+1=(5)做比較,如果相等,則可以更新,如果不相等,其他程序已更新該記錄,返回錯誤。
悲觀鎖
假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整行的操作。
一般需要使用數(shù)據(jù)庫的鎖機(jī)制,比如MysqlInnoDB引擎的行級鎖。
結(jié)論:在實(shí)際生產(chǎn)環(huán)境中,如果并發(fā)量不大且不允許臟讀(原始數(shù)據(jù)為***B兩個事務(wù),B其他事務(wù)更新數(shù)據(jù)為2,事務(wù)未提交時,A讀取到的仍然為5),可以使用悲觀鎖。并發(fā)訪問量大時,使用悲觀鎖有非常大的性能問題,可以選擇樂觀鎖。
其次,介紹一下Memcached的CAS機(jī)制
CAS,又稱Compare-and-Swap,代表一種原子操作。
Memcached的CAS機(jī)制解決的問題及其原理:
1. 實(shí)現(xiàn)了Check-and-Set原子操作功能;
2. 其使用方式為:首先使用gets指令一個key-value及key對應(yīng)value的版本號;其次操作產(chǎn)生新的value值;***使用cas指令重新提交key-value,并附帶剛剛獲得到的版本號;
3. 當(dāng)服務(wù)端判斷cas操作中的版本號不是***的時,則認(rèn)為改key的值已經(jīng)被修改,本次cas操作失敗。程序設(shè)計人員通過CAS機(jī)制可實(shí)現(xiàn)自增和自減的原子操作;
可以看到MemCache的CAS機(jī)制和數(shù)據(jù)庫的樂觀鎖實(shí)現(xiàn)原理非常類似。
Q2:假設(shè)系統(tǒng)中圖片存儲在TFS(Taobao File System)中,接口提供縮略圖服務(wù),首先在緩存中查找是否有縮略圖,如果沒有,則從TFS加載原圖片,然后請求縮略圖服務(wù),縮略圖計算完成后,設(shè)置回緩存服務(wù)中。
遇到的問題:當(dāng)一張圖片分享給100w個人以后,同一時間有1w個并發(fā)請求,由于縮略圖計算耗時較長(假設(shè)1s), 在這1s內(nèi),每個請求查詢緩存都沒有找到然后申請計算縮略圖,導(dǎo)致重復(fù)的縮略圖計算量和資源消耗。
A2:對于縮略圖這種耗時的服務(wù),非常適合使用緩存,不過在使用的時候,對于同一個圖片,原則上只需要計算一次縮略圖,在縮略圖未計算完成時,可以對每張圖片做額外的標(biāo)記表示其正在Processing,并發(fā)請求遇到縮略圖Processing時,可以等待縮略圖計算完成(這是建議的方式)后從緩存直接讀取,也可以是直接返回錯誤,通過客戶端重試來解決。
本案例中,如果縮略圖請求在上傳圖片1分鐘后才發(fā)生,則可以在后臺預(yù)先計算縮略圖并存儲到緩存。另外就是在上傳圖片的時候計算縮略圖,不過會增加上傳圖片的時間。
Q3:單點(diǎn)峰值流量,在并發(fā)系統(tǒng)中,除了請求整體的并發(fā)量高,還常見單一熱點(diǎn)資源的并發(fā)請求量很高。例如,1萬個人每人分享了一張圖片,其中9999張圖片的縮略圖請求在10 QPS以內(nèi),剩下的一張圖片為新聞熱點(diǎn)圖片,峰值請求在10萬QPS左右, 系統(tǒng)會遇到的容量問題包括:1)接口前端機(jī)容量不夠;2)緩存資源單實(shí)例遇到瓶頸。
A3:針對單點(diǎn)峰值流量可能遇到的性能瓶頸,解決方案如下。
1)接口層容量不夠:這個問題比較簡單,只要接口層設(shè)計是無狀態(tài)的,當(dāng)容量達(dá)到預(yù)警線,可以通過快速水平擴(kuò)容解決。
2)緩存資源單實(shí)例遇到性能瓶頸:如果使用的是分布式緩存,當(dāng)希望突破單一key的訪問瓶頸時(這個瓶頸既有可能是CPU資源緊張,也有可能是單機(jī)網(wǎng)絡(luò)帶寬跑滿,還有可能是磁盤IO吞吐不夠),一個辦法是分布式緩存做多副本(x3)冗余設(shè)計,這樣系統(tǒng)的吞吐量(x3)可以提高3倍,不過成本也提高3倍。另外一個辦法是針對極熱點(diǎn)數(shù)據(jù),除了分布式緩存,同時在前端機(jī)上打開localCache,依靠數(shù)量眾多的前端機(jī)來抗極熱點(diǎn)請求。