為什么限流會出現?
在開發高并發系統時有三把利器用來保護系統:緩存、降級和限流。緩存的目的是提升系統訪問速度和增大系統能處理的容量,可謂是抗高并發流量的銀彈;而降級是當服務出問題或者影響到核心流程的性能則需要暫時屏蔽掉,待高峰或者問題解決后再打開;而有些場景并不能用緩存和降級來解決,比如稀缺資源(秒殺、搶購)、寫服務(如評論、下單)、頻繁的復雜查詢(評論的最后幾頁),因此需有一種手段來限制這些場景的并發/請求量,即限流。
限流的目的?
限流的目的是通過對并發訪問/請求進行限速或者一個時間窗口內的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊或等待(比如秒殺、評論、下單)、降級(返回兜底數據或默認數據,如商品詳情頁庫存默認有貨)
限流的方式
一般開發高并發系統常見的限流有:限制總并發數(比如數據庫連接池、線程池)、限制瞬時并發數(如nginx的limit_conn模塊,用來限制瞬時并發連接數)、限制時間窗口內的平均速率(如Guava的RateLimiter、nginx的limit_req模塊,限制每秒的平均速率);其他還有如限制遠程接口調用速率、限制MQ的消費速率。另外還可以根據網絡連接數、網絡流量、CPU或內存負載等來限流。
限流算法
常見的限流算法有:令牌桶、漏桶。計數器也可以進行粗暴限流實現。
漏桶(Leaky Bucket)算法
水(請求)先進入到漏桶里,漏桶以一定的速度出水(接口有響應速率),當水流入速度過大會直接溢出(訪問頻率超過接口響應速率),然后就拒絕請求,可以看出漏桶算法能強行限制數據的傳輸速率.
令牌桶算法(Token Bucket)
和 Leaky Bucket 效果一樣但方向相反的算法,更加容易理解.隨著時間流逝,系統會按恒定1/QPS時間間隔(如果QPS=100,則間隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有個水龍頭在不斷的加水),如果桶已經滿了就不再加了.新請求來臨時,會各自拿走一個Token,如果沒有Token可拿了就阻塞或者拒絕服務.
令牌桶的另外一個好處是可以方便的改變速度. 一旦需要提高速率,則按需提高放入桶中的令牌的速率. 一般會定時(比如100毫秒)往桶中增加一定數量的令牌, 有些變種算法則實時的計算應該增加的令牌的數量.
算法在限流方式中的應用
應用級限流
對于一個應用系統來說一定會有極限并發/請求數,即總有一個TPS/QPS閥值,如果超了閥值則系統就會不響應用戶請求或響應的非常慢,因此我們最好進行過載保護,防止大量請求涌入擊垮系統。
如果你使用過Tomcat,其Connector其中一種配置有如下幾個參數:
acceptCount:如果Tomcat的線程都忙于響應,新來的連接會進入隊列排隊,如果超出排隊大小,則拒絕連接;
maxConnections:瞬時最大連接數,超出的會排隊等待;
maxThreads:Tomcat能啟動用來處理請求的最大線程數,如果請求處理量一直遠遠大于最大線程數則可能會僵死。
詳細的配置請參考官方文檔。另外如MySQL(如max_connections)、Redis(如tcp-backlog)都會有類似的限制連接數的配置。
池化技術
如果有的資源是稀缺資源(如數據庫連接、線程),而且可能有多個系統都會去使用它,那么需要限制應用;可以使用池化技術來限制總資源數:連接池、線程池。比如分配給每個應用的數據庫連接是100,那么本應用最多可以使用100個資源,超出了可以等待或者拋異常。
限流某個接口的總并發/請求數:如果接口可能會有突發訪問情況,但又擔心訪問量太大造成崩潰,如搶購業務;這個時候就需要限制這個接口的總并發/請求數總請求數了;因為粒度比較細,可以為每個接口都設置相應的閥值。可以使用Java中的AtomicLong進行限流:
分布式限流
對于分布式限流目前遇到的場景是業務上的限流,而不是流量入口的限流;流量入口限流應該在接入層完成,而接入層筆者一般使用Nginx。
分布式限流最關鍵的是要將限流服務做成原子化,而解決方案可以使使用redis+lua或者nginx+lua技術進行實現,通過這兩種技術可以實現的高并發和高性能。
本站文章版權歸原作者及原出處所有 。內容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網站上部分文章為轉載,并不用于任何商業目的,我們已經盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯系我們,我們將根據著作權人的要求,立即更正或者刪除有關內容。本站擁有對此聲明的最終解釋權。