提高系統效能的2個常用手段---快取和非同步

小飛鶴發表於2017-09-14

快取

  1. 快取 
    1.1 快取重新整理機制,快取重新整理是指什麼時候把資料庫中的資料載入到快取 
    (1) 定期重新整理; 
    (2) 快取命中失敗時重新整理; 
    1.2 在有快取時的資料寫入方式: 
    (1) 同步寫入,即快取和資料庫同時被寫入,即在應用層進行雙寫操作,這種方式可以有效保證快取和DB中資料的一致性,由於這種方式即要更新快取同時還要更改資料庫,其訪問效率相對較低,適合讀多寫少的場景; 
    (2) 非同步更新機制,在寫操作時只寫入快取便返回,寫資料庫的操作交個另外一個非同步操作來完成,這樣可以加快使用者請求的處理速度,進而增強整個系統的併發量,但是這種方式會造成在一定時間內快取和資料庫中的資料不一致; 
    一般情況下,同時保證資料寫入快取和資料庫的事務性是非常困難的,因為這時涉及到寫入資料到兩種系統中,而且一般快取不提供回滾機制,如果系統的要求不嚴格,則可採用一些妥協措施,以提升系統的整體訪問效率。 
    1.3 快取使用的幾種方式: 
    (1) 全量快取,是指所有的資料在快取中都有,它不適合資料量較大、冷熱訪問極度不均勻的情況,這些情況下要麼快取放不下這麼多資料,要麼快取中載入的都是大量不用的資料,造成快取浪費,同時也會影響訪問效率;它適合資料量小並且全部資料都會經常被訪問的場景;例如,我們有一個業務是獲取系統中各子服務的地址,在每個客戶端上線時第一步操作就是獲取各子服務的地址,然後才能進行真正的業務操作,這些服務地址資訊資料量不大,但是全部都會經常被訪問,因此它們需要被全量快取,為保障快取和資料庫的一致性,我們採用雙寫策略,更新服務地址時要同時更新快取和資料庫; 
    (2) 只快取熱點資料,這種方式適合資料量大、冷熱訪問不均勻的場景,該方式涉及到資料何時被載入、何時被逐出的問題;載入時可以採用兩種方式:增量方式,服務啟動時不向快取中載入任何資料,等訪問時在快取找不到再去資料庫中取並將取出的結果載入到快取中,這樣隨著時間的推移,熱點資料將被載入到快取中;另一種方式是減量方式,服務啟動時載入全部的資料,一定時間內不被使用的資料將會被逐出,隨著時間的推移冷資料都被逐出,而留下來的都是熱點資料;例如:我們為一個IM系統設計賬號服務子系統時,就採用只快取熱點資料的方式,並且資料載入方式採用增量方式;只快取熱點資料的方式要特別注意快取的量,如果快取中沒有存下足夠的熱點資料,那麼將會有一定量的請求會穿透快取,將壓力施加到資料庫上; 
    1.4 架構設計時的三個層次的快取 
    (1)物件快取,例如Redis、Memched等,它以Key-Value的方式幫助我們快取一些物件資料,Redis提供的Value型別更多,使用時更加方便;但是這些快取通常不提供資料庫的事務性,即它不滿足ACID的四點要求,在分散式系統中我們更常提及的是CAP特性,即在分散式環境中無法同時滿足:一致性、可用性和分割槽容忍性,因此,在做分散式系統中要對業務進行更細粒度的分析,確定哪些資料需要事務性儲存,哪些只需CAP中的兩點即可滿足?按照這種思路,一般一個系統中只有極少數核心的資料要求事務性,絕大多數資料可能要求最終一致性等等。 
    (2)應用快取,例如代理快取和反向代理快取,應用快取的目的是加快使用者的訪問速度和儘量降低對資源的使用率;代理快取的例子,例如網際網路服務提供商(ISP)快取了一部分常用URL對於的資源,當使用者訪問這些URL時,ISP直接從快取中把結果返回給使用者,而不是將使用者請求轉交給URL所指向的真正伺服器;反向代理的例子,在服務前面部署一個nginx用於快取靜態頁面,當使用者訪問這些靜態頁面時,反向代理nginx直接將快取的靜態頁面返回給使用者,這些請求就不會落到後面的真正伺服器上,反向代理服務對訪問服務後臺的所有請求進行了過濾、攔截,大大降低了請求對後端的壓力; 
    (3)內容交付網路快取,最典型的例子就是CDN,在視訊點播網站中,如果我們點播的電影都在中央的資源伺服器中,那麼這個服務的效能再強大也難以為使用者提供流暢的視訊服務,採用CDN之後,就可以根據使用者的訪問情況,將熱點資料推送到距離使用者最近的邊緣資源伺服器上,這樣使用者在觀看視訊時就直接從邊緣資源伺服器上進行下載,這樣資源離使用者更近,下載速度更快; 
    1.5 個人理解,在進行高併發服務的設計時,應該採用逐級分流的策略,將使用者的請求呈樹狀分流到各個服務中,使用者經常訪問的請求被放在樹狀服務的上層,業務處理越複雜的請求被放在樹狀服務的下層;如下圖所示:

這裡寫圖片描述



非同步

  1. 同步與互斥,提到非同步必然要涉及到與之對應的另一個詞“同步”,而提到“同步”很多人也會聯想到另一個詞“互斥”,同步是指多個操作之間產生了依賴或者先後順序關係,互斥是指多個操作需要訪問同一個資源,而這個資源又不能讓多個操作同時進行,那麼這多個操作之間就是互斥關係;
  2. 同步呼叫與非同步呼叫,在服務設計時,同步呼叫是指呼叫方在發起呼叫之後必須一直等待直到呼叫結果返回才能進行後續的操作,非同步呼叫是指呼叫發起方在發起呼叫之後立即返回繼續執行後續的操作,而不需要等待呼叫的返回結果。舉個簡單的例子,同步就像打電話,非同步就像發郵件;
  3. 同步呼叫和非同步呼叫,二者各有其應用場景,如果相鄰兩個操作之間存在依賴關係,那麼就必須選擇同步呼叫,否則都可以採用非同步,但是同步呼叫更為簡單,如果在一個系統中濫用非同步會造成系統複雜度增加;從擴充套件性角度來看,同步容易造成呼叫阻塞,非同步呼叫更易於擴充套件,而且非同步呼叫方式天然具備故障的隔離性,因此,在合適的場景選擇同步能讓你的系統更為簡單,在合適的場景選擇非同步能讓你的系統更具備擴充套件性; 
    例如,我們要設計一個資料收集和處理系統,該系統分為兩個子服務:資料收集服務和資料處理服務,資料收集服務用於從客戶端收集各種上報資訊,客戶端上報的所有資料需符合系統的格式要求(上報的訊息必須為JSON格式字串,在字串中必須包含version、type、con三個欄位,上報的不同訊息的type的值不一樣,上報的訊息內容儲存在con欄位中),資料處理程式對收集服務傳入的資料進行分型別處理,並根據type欄位值存入資料庫的不同表中,如果系統被設計成同步的方式,那麼它會像像下圖所示: 
    這裡寫圖片描述 
    在同步的系統中,資料收集服務沒收到一個客戶端上報的訊息就呼叫資料分析服務對該訊息進行處理,資料分析服務將資料解析、轉換之後存入資料庫,然後將結果返回給資料收集服務,然後資料收集服務再將結果返回到客戶端,那麼在這個系統中資料收集服務呼叫資料分析服務是同步呼叫,因為它要等待資料分析服務返回的結果,而資料分析服務呼叫資料庫也是同步呼叫,因為資料分析服務也要等待資料庫的處理結果; 
    在上述設計的資料收集、分析系統中,有如下問題:(1)擴充套件性受影響,客戶端併發量受到資料分析服務、資料庫儲存速度的影響;(2)系統可用性受影響,一般資料分析服務所做的事情稍微複雜,一旦這個服務出現問題,整個資料收集、分析系統都無法正常工作; 
    為解決上述同步過程中出現的問題,將系統改造成如下圖所示: 
    這裡寫圖片描述 
    我們引入一個非同步佇列(例如RabbitMQ)用於對“資料收集服務”和“資料分析服務”的解耦,非同步佇列可以對資料進行快取並具備持久化能力,資料收集服務在受到客戶端上報的資料時,只檢查其格式是否符合要求(是否為JSON串?JSON中是否包含了version、type和con三個欄位),檢測通過的資料傳送到非同步佇列中,資料一旦放入非同步佇列就立即返回;資料分析服務從非同步佇列中拉取訊息,並對訊息進行分析、處理然後將資料儲存到資料庫的相應表中; 
    在這個非同步系統中,還存在很多同步呼叫,例如資料收集服務同步呼叫非同步佇列的介面來傳送資料(很多非同步佇列的客戶端也提供非同步傳送訊息的功能),這裡採用同步呼叫,是想告訴客戶端,它的資料已經安全抵達伺服器,而伺服器內部會保證你的資料被安全的處理,但是可能不會立即處理,如果這裡也採用了非同步,就會出現問題:非同步傳輸資料出現問題時,無法告知客戶端,客戶端就會抱怨明明已經把資料成功交給伺服器,伺服器卻實際上沒有成功處理它;資料分析從非同步佇列中拉取訊息也是同步呼叫,即資料分析服務從非同步佇列中拉取一條訊息進行處理,處理完畢之後再從非同步佇列中將該訊息刪除; 
    雖然系統中存在了同步呼叫,但是從整個系統而言,資料收集服務和資料分析的依賴性卻消失了,由於資料收集服務做的事情非常少,它能接受客戶端的更多的上報請求,而資料分析服務業務複雜還需要儲存資料庫,它可以慢慢地從非同步佇列中消費訊息,即便客戶端上報訊息的速度超過了“資料分析服務”,那麼整個系統也能正常執行,從故障隔離的角度來看,一旦資料分析服務出現故障,訊息會被非同步佇列快取,客戶端的資料上報功能依然不受影響。 
    從上面的例子可以看出,同步和非同步在架構設計時使用要非常靈活,沒有明確的方案來告訴我們什麼時候應該用同步什麼時候應該用非同步,我們只要保證整個系統滿足穩定性、擴充套件性等相關的要求即可。
  4. 同步轉非同步時,阻礙最大的地方就是呼叫之間產生了依賴、順序關係,從另一個角度來看就同步操作之間產生了狀態,這時如果要想將這些操作轉換為非同步,那就要去掉這些狀態,去掉狀態的辦法包括:(1)將狀態相關的操作整合到一個操作裡,這需要呼叫方來實現;(2)將狀態快取到一個第三方快取中,例如Redis、Memched等等,這需要被呼叫來實現;

關於正向代理和反向代理

  1. 正向代理,代理客戶端傳送請求,例如,我們區域網內的所有主機都不能上網,但是該區域網內有一臺雙網路卡主機A能訪問外網,這時可以在雙網路卡主機A上啟動代理服務,在區域網內其他想訪問外網的主機上配置代理服務,這樣它們就可以上網了;因為這些原本無法訪問外網的主機會先將上網請求傳送到代理伺服器A上,由代理服務A替它們訪問相應的外網資源,並將請求到的網路資源返回給請求使用者;對於服務端而言,它只能看到代理伺服器,並不知道實際的請求來自於該區域網內的哪個主機; 
    正向代理示意圖 
    正向代理的作用: 
    (1) 代替本機完成它本不能完成的任務,例如上面所舉的上網例子; 
    (2) 加速訪問速度,縮短響應時間,這有以下兩種實現方式: 
    [1] 代理服務快取常用的請求和結果,當客戶端有常用請求發過來時,代理服務直接將快取的結果返回給使用者,而不用再將請求傳送到服務端,從而可以提升使用者訪問速度,縮短訪問時間; 
    [2] 避免低效路由,當客戶端直接訪問服務端要經歷一個低速網段,而客戶端到代理服務、代理服務到伺服器端都是高速網路時,這種方法就起作用了,通常代理服務都是經過設計、優化,它訪問外網的速度一般都比較快;我們經常上網時(尤其是翻牆時)配置的不同的代理,訪問的速度就不一樣,也是類似道理; 
    (3) 隱藏訪問者行蹤,由於代理訪問代替其後面的實際使用者發起網路請求,因此,請求對應服務端只能看到代理伺服器,而看不到它背後的實際訪問者,從而達到隱藏訪問者行蹤的目的。
  2. 反向代理,主要用於代理服務端接收客戶端的訪問請求,它是服務端設計時採用的一種技術,它能幫助服務端提升訪問請求速度和系統整體擴充套件能力,並能隱藏業務伺服器,在一定程度上提升整個系統的安全性;例如:在網際網路服務端架構設計時採用的Nginx就是一個常用的反向代理服務。在反向代理服務中,所有的客戶端網路請求都先傳送到反向代理伺服器上,而反向代理服務再將請求轉交到實際的業務處理服務;對於客戶端而言,它只知道反向代理伺服器,並不知道反向代理服務後面的情況。 
    反向代理服務示意圖 
    反向代理服務可以有很多工作模式: 
    (1) 快取加速,反向代理服務快取常用的客戶端請求和結果,當客戶端有請求過來時,首先在快取中查詢結果,如果找到則將結果直接返回給客戶端,如果找不到再將請求轉交到相應業務伺服器;這樣一方面可以加快客戶端的訪問速度、縮短相應時間(快取命中時),同時還能減輕業務服務的處理壓力。 
    (2) 負載均衡方式,反向代理服務將請求按照負載均衡演算法分散到多個業務處理例項上,以減輕每個業務服務例項的壓力,這時要求業務服務必須是無狀態,這種方式能增加整個服務端的擴充套件能力



  參考:  http://blog.csdn.net/column/details/13917.html


相關文章