天天看點

高并發解決方案(緩存、降級、限流)---讀書筆記

       高并發系統時有三把利器用來保護系統:緩存、降級和限流。緩存的目的是提升系統通路速度和增大系統能處理的容量,可謂是抗高并發流量的銀彈;而降級是當服務出問題或者影響到核心流程的性能則需要暫時屏蔽掉,待高峰或者問題解決後再打開;而有些場景并不能用緩存和降級來解決,比如稀缺資源(秒殺、搶購)、寫服務(如評論、下單)、頻繁的複雜查詢(評論的最後幾頁),是以需有一種手段來限制這些場景的并發/請求量,即限流。

限流的目的是通過對并發通路/請求進行限速或者一個時間視窗内的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊或等待(比如秒殺、評論、下單)、降級(傳回兜底資料或預設資料,如商品詳情頁庫存預設有貨)。

一般開發高并發系統常見的限流有:限制總并發數(比如資料庫連接配接池、線程池)、限制瞬時并發數(如nginx的limit_conn子產品,用來限制瞬時并發連接配接數)、限制時間視窗内的平均速率(如Guava的RateLimiter、nginx的limit_req子產品,限制每秒的平均速率);其他還有如限制遠端接口調用速率、限制MQ的消費速率。另外還可以根據網絡連接配接數、網絡流量、CPU或記憶體負載等來限流。

先有緩存這個銀彈,後有限流來應對618、雙十一高并發流量,在處理高并發問題上可以說是如虎添翼,不用擔心瞬間流量導緻系統挂掉或雪崩,最終做到有損服務而不是不服務;限流需要評估好,不可亂用,否則會正常流量出現一些奇怪的問題而導緻使用者抱怨。

在實際應用時也不要太糾結算法問題,因為一些限流算法實作是一樣的隻是描述不一樣;具體使用哪種限流技術還是要根據實際場景來選擇,不要一味去找最佳模式,白貓黑貓能解決問題的就是好貓。

因在實際工作中遇到過許多人來問如何進行限流,是以本文會詳細介紹各種限流手段。那麼接下來我們從限流算法、應用級限流、分布式限流、接入層限流來詳細學習下限流技術手段。

限流算法

常見的限流算法有:令牌桶、漏桶。計數器也可以進行粗暴限流實作。

應用級限流

限流總并發/連接配接/請求數

對于一個應用系統來說一定會有極限并發/請求數,即總有一個TPS/QPS閥值,如果超了閥值則系統就會不響應使用者請求或響應的非常慢,是以我們最好進行過載保護,防止大量請求湧入擊垮系統。

如果你使用過Tomcat,其Connector 其中一種配置有如下幾個參數:

acceptCount:如果Tomcat的線程都忙于響應,新來的連接配接會進入隊列排隊,如果超出排隊大小,則拒絕連接配接;

maxConnections: 瞬時最大連接配接數,超出的會排隊等待;

maxThreads:Tomcat能啟動用來處理請求的最大線程數,如果請求處理量一直遠遠大于最大線程數則可能會僵死。

詳細的配置請參考官方文檔。另外如Mysql(如max_connections)、Redis(如tcp-backlog)都會有類似的限制連接配接數的配置。

限流總資源數

如果有的資源是稀缺資源(如資料庫連接配接、線程),而且可能有多個系統都會去使用它,那麼需要限制應用;可以使用池化技術來限制總資源數:連接配接池、線程池。比如配置設定給每個應用的資料庫連接配接是100,那麼本應用最多可以使用100個資源,超出了可以等待或者抛異常。

限流某個接口的總并發/請求數

如果接口可能會有突發通路情況,但又擔心通路量太大造成崩潰,如搶購業務;這個時候就需要限制這個接口的總并發/請求數總請求數了;因為粒度比較細,可以為每個接口都設定相應的閥值。可以使用Java中的AtomicLong進行限流:

try {
    if(atomic.incrementAndGet() > 限流數) {
        //拒絕請求
   }
    //處理請求
} finally {
    atomic.decrementAndGet();
}      

适合對業務無損的服務或者需要過載保護的服務進行限流,如搶購業務,超出了大小要麼讓使用者排隊,要麼告訴使用者沒貨了,對使用者來說是可以接受的。而一些開放平台也會限制使用者調用某個接口的試用請求量,也可以用這種計數器方式實作。這種方式也是簡單粗暴的限流,沒有平滑處理,需要根據實際情況選擇使用;

摘錄自:https://www.iteye.com/blog/jinnianshilongnian-2305117---- 聊聊高并發系統之限流特技