天天看點

一文搞定算法和架構,微服務接口限流不用愁!1、服務限流的概念2、單服務節點限流3、服務叢集限流4、限流的難點及注意事項5、作者簡介

目錄

1、服務限流的概念

2、單服務節點限流

2.1、漏桶算法

2.2、令牌桶算法

3、服務叢集限流

4、限流的難點及注意事項

5、作者簡介

線上系統遇到的一大風險就是流量的暴漲暴跌,尤其是在這個全民上網的時代,一條明星出軌的新聞帶來的通路流量暴漲可以把微網誌給壓趴。企業會優先通過擴容來盡量容納所有的流量,以保障業務不受損失。但通過資源擴容來提升系統容量也不是無限的,不僅技術實作上不現實,從成本投入角度看也不劃算。相對而言,更經濟可行的方式是限流或者降級。這就像一些城市在上班高峰期車流量增大時,臨時增調對行車道以增加通行容量;如果車流量再繼續增大,就隻能限行,控制進入車道的車輛數。

本文将重點介紹微服務接口的限流算法及架構實作。

1、服務限流的概念

所謂限流,是根據某個應用或基礎部件的某些核心名額,如總并發數、QPS或并發線程數,甚至是白名單,來決定是否将後續的請求進行攔截。比如我們設定1秒的QPS門檻值為1000,如果某一秒的QPS為1100,那超出的100個請求就會被攔截掉,直接傳回約定的錯誤碼或提示頁面。

服務限流是在高流量下保證服務叢集整體穩定,并提供一定可用性的有效辦法。比起系統整體被“壓趴”,所有使用者都無法獲得服務的狀況,拒絕一部分使用者,對另一部分使用者提供正常服務總是要好一些。

限流操作一定要前置,對于已經明确要被拒絕處理的流量,盡量不要放到後續環節。一方面可以避免不必要的資源浪費,另一方面也可以減少調用方無謂的等待。如圖1所示,如果在服務調用方限流,則在接口調用發起時就可以進行限流控制;如果在服務提供方限流,則在請求接入後、解碼前就可以進行限流控制。

一文搞定算法和架構,微服務接口限流不用愁!1、服務限流的概念2、單服務節點限流3、服務叢集限流4、限流的難點及注意事項5、作者簡介

                                                              圖1 服務流控架構

流控的模式也不僅僅局限于一種,可以采用多種流控模式的組合來應對複雜業務場景下的限流需求。比如,當發生熱點事件時,可以先基于IP白名單,隻允許聯通使用者的請求接入,在此基礎上再基于QPS進行限流。

對服務叢集而言,單個服務節點的限流是基礎,它是實作叢集整體限流的前提,下面,我們首先介紹單服務節點的限流實作。

2、單服務節點限流

限流的目的不僅是要控制通路的總并發量,還要盡量讓通路的流量來的更均衡,才不會讓系統的負載大起大落,是以又稱之為“流量整形”。在單點模式下有多種手段能達到“流量整形”式限流,也有很多元件可供選擇,例如Java自帶的信号量元件semaphore,Google Guava的RateLimiter元件等。那麼,這些元件的限流模式有什麼不同呢?

2.1、漏桶算法

很多受歡迎的餐廳在就餐高峰期都需要排隊,餐廳為客滿後再來的顧客發放排隊号,當有顧客用餐完畢離開,就按排号順序讓最早的顧客進入餐廳就餐。這實際上就是一種限流措施,嚴格控制客流量穩定在餐廳的招待能力範圍内。這種限流方式保證在餐廳内就餐的顧客總數(并發數)是一緻的,隻有出去一個顧客,才能放進來一個顧客。新來的顧客能不能吃上飯,完全取決于已就餐顧客是否“翻牌”。

一文搞定算法和架構,微服務接口限流不用愁!1、服務限流的概念2、單服務節點限流3、服務叢集限流4、限流的難點及注意事項5、作者簡介

                                                   圖2 漏桶算法&令牌桶算法

餐廳排号就餐的方式非常像一個漏桶,桶的容量是固定的,桶底的水不斷的流出,桶頂的水不斷流入,如果流入的水量(請求量)超出了流出的水量(最大并發量),桶滿後新流入的水會直接溢出,這就是限流應用中常用的漏桶算法,如圖2-1所示。漏桶算法可以很好的控制流量的通路速度,一旦超過該速度就拒絕服務。Java中自帶的信号量元件Semaphore就是典型的基于漏桶算法的元件,它可以有效控制服務的最大并發總數,防止服務過載。以下是Semaphore的典型用法:

01.         private Semaphore smp = new Semaphore(30);     //非公平政策

02.         ...

03.         if(smp.getQueueLength()>0){   //如果有排隊現象,則立刻拒絕服務

04.             return;

05.         }

06.         try{

07.             smp.acquire();                      //擷取一個信号量

08.             //處理具體的業務邏輯

09.         }catch(InterruptedException ex){

10.             ex.printStackTrace();

11.         }finally{

12.             smp.release();      //釋放信号量

13.         }

研究漏桶算法可以發現,它主要關注目前的并發總量(信号總量),隻有某個資源被釋放的信号發出(release操作),等待進入的請求才能獲得通行證,有“出”才有“進”,通過這種方式,來保證系統負載可控。

2.2、令牌桶算法

限流的另一種常用算法是令牌桶算法,它的原理如圖2-2所示,系統以恒定的速率往桶裡放令牌,請求需要從桶裡獲得令牌才能被處理,一旦桶裡無令牌可取,則拒絕服務。Google Guava的RateLimiter元件就是采用的令牌桶算法。下面是基于RateLimiter實作的簡單限流示例:

01.         RateLimiter limiter = RateLimiter.create(5);

02.         System.out.println(limiter.acquire());

03.         System.out.println(limiter.acquire());

04.         System.out.println(limiter.acquire());

05.         System.out.println(limiter.acquire());

06.         System.out.println(limiter.acquire());

代碼運作之後,可以獲得如下結果:

0.0

0.199013

0.195662

0.199781

0.200103

上面的代碼中,01行代碼建立了一個容量為5的“桶”,并且每秒投入5個令牌。第一次申請一個令牌時(02行),目前桶中有足夠的令牌,是以可以馬上擷取到,此時列印出來的等待時間是0。後面再請求令牌時,由于要達到“流量整形”的目标,RateLimiter會以固定周期,間歇性的往“桶”裡投入令牌,平均時間間隔是1000ms/5=200ms左右,是以03~07行的代碼運作就被阻塞了,從運作結果上看,基本符合理論計算的預期。可見,RateLimiter通過這種政策将突發請求速率平均為(整形成)固定請求速率。

在實際應用中,對無法擷取令牌,注定要被拒絕的請求可以快速抛棄,減少請求的等待時間,降低阻塞帶來的無謂資源損耗。是以,實際使用中會更多使用無阻塞的tryAcquire方法,盡量少用阻塞的acquire方法。如下代碼是常用的基于RateLimiter令牌桶的限流模式:

01.     RateLimiter rateLimiter = RateLimiter.create(100);    //控制每秒隻能有100個請求進來

02.     if(!rateLimiter.tryAcquire()){   //判斷是否能馬上擷取令牌,如不能則直接給用戶端傳回錯誤資訊

03.          //給用戶端傳回異常或者拒絕資訊

04.          return;

05.      }

06.      //下面是正常業務邏輯

07.      ...;

比較RateLimiter和Semaphore的限流,可以發現,RateLimiter并沒有一個後置的、類似Semaphore的release這樣顯式的信号釋放動作,其通過acquire和tryAcquire動作是否能夠擷取到令牌完全取決于時間,限流控制是在請求流入端進行。

3、服務叢集限流

單機限流下,各個服務節點負責各自機器的限流,不關注其它節點,更不關注服務叢集總調用量。因為背景總資源是有限的,有時雖然各個單節點的流量都沒有超,但總流量會超過背景資源的總承受量,是以必須控制服務在所有節點上的總流量,這就是叢集限流。

總流量控制可以在前台通過網關來實施。但P2P直連模式的服務叢集沒有網關一說。是以要控制總流量,就必須先彙總叢集各個服務節點的流量,并将這個總流量與預先設定的SLA門檻值相比較,如果超了就要進行限流。比如SLA設定1000,總流量算出來是1200,那就超了200,這時就必須将總流量降到(1-(200/1200)),大概0.85左右。每個服務節點都要将目前流量降低到這個比例。由于流量的傾斜,每台機器的流量都不一樣,需要将0.85這個限流比例推到各個服務節點,讓每個節點基于自己之前統計的流量結合0.85限流比率算出各自的限流門檻值。再根據各自的限流門檻值去調用semaphore或者RateLimiter做單機限流。是以叢集環境下的限流也要以單點的限流為基礎,但流量判定上有所不同,叢集環境下需要采集所有服務節點的流量資訊進行統一判定,圖3是典型的叢集限流架構圖。

一文搞定算法和架構,微服務接口限流不用愁!1、服務限流的概念2、單服務節點限流3、服務叢集限流4、限流的難點及注意事項5、作者簡介

圖3 叢集限流架構圖

服務叢集限流基本遵循如下步驟:

  1. 将時間分片,可以1分鐘,也可以30秒鐘、10秒鐘,具體時間長度根據業務實際需求,也與線上日志的采集及處理能力相關。每個服務節點記錄本節點的每次實際調用及調用延時,并統計本時間片内的總調用量及平均調用延時。
  2. 一個時間片結束後,這個時間片内的調用計數會以日志的形式被采集并彙總到日志中心(如圖3的步驟1),對日志的流式分析中會有專門的統計分析器對這些調用計數日志進行分析。當統計分析器确定所有的日志都已到位,會進行叢集調用量的彙總,并基于時間片算出這個時間片對應的此服務叢集的QPS(步驟2)。
  3. 分析器集合中的叢集限流分析器根據統計分析器的結果,并結合服務注冊中心中定義的限流配置來判斷是否需要進行限流控制。對于一些自動化程度高的系統,可能還要綜合平均調用延時及服務等級協定(SLA)來做綜合評判,如果實際流量超過了限流門檻值(或者綜合評判滿足限流條件),則計算出一個限流比例(步驟3)。不考慮其他因素的限流比例的計算公式如下:
限流比例=1-(實際QPS-限流QPS)/實際QPS
  1. 叢集限流分析器将“限流比例”名額寫入服務注冊中心(步驟4),并通過服務注冊中心的事件推送機制将此配置下發到各服務節點。服務節點基于擷取到的限流比例,根據對應時間片的調用量換算出限流調用量,再采用“單點限流”的限流政策進行限流控制。

從上述步驟可見,服務叢集的限流機制比較複雜,需要依賴監控、計數、分析、配置下發、節點流控等各個能力的協同配合,缺一不可。為了實作高效的叢集限流控制,必須實作各個環節的高效處理,要注意以下幾個方面:

  1. 時間片太長,會導緻限流操作滞後,可能限流指令還未下發,服務叢集就被壓垮了,是以要盡量縮短時間片的長度。但時間片也不是越小越好,由于流量的波動,太小的時間片計算出來的QPS可能會有較大偏差。是以,需要根據線上流量特點來評估時間片的長度設定。
  2. 日志采集一定要及時,時間片一結束,要盡快将計數日志發出,可以讓計數日志采用單獨的日志檔案,并配置獨立的采集器,優先保障其資訊采集。如果采用消息隊列對日志資料進行緩沖,可以給通路計數日志設定獨立的Topic,以提高其處理優先級。
  3. 對計數日志的分析一定要采用實時分析,不能是離線分析,否則不具有時效性。

4、限流的難點及注意事項

如果隻是單純的單點限流其實并不難,有很多現成的元件可以選擇。但如果要建構系統的限流體系又是一件極“難”的事情。它的難度在于,由于涉及服務節點的調用監控、日志采集發送、日志接收聚合、計算分析、限流決策判斷、指令下發、節點限流等許多環節,要實作各環節的高效銜接和緊密協作配合,需要整個技術棧的統一及協同排程。

是以說,要建構一套行之有效的限流體系,必須統一微服務架構、日志采集規範、日志分析規範、SLA的定義及節點限流的技術政策,這些都要有很明确的要求。如果某些環節使用的架構不同,那麼這套統一的技術體系就無法推廣落地。試想,如果企業内部同時存在基于Java和Go兩種語言建構的微服務架構,那麼針對它們的節點限流就必須要建立兩套不同語言的節點限流及對應計數、日志采集的能力,相應的開發及維護成本也會升高。

技術棧的統一,依賴于技術體系的标準化建設。如果在IT建設的初期就注重技術選型及建構的标準化,後續在建構新能力時,就可以有效減少業務代碼的改變和調整。不僅僅是限流體系,還有治理工作甚至運維自動化遇到的大部分困難往往都是标準化缺失導緻的。“沒有規矩,不成方圓”,這裡的規矩就是我們從各式各樣的IT運維對象及流程中提取出來的标準和規範,也是建構自動化及智能化運維能力的前提。是以,一定要重視标準化的建設,具體到限流體系的建構上也是如此,要“标準先行”。限流體系的标準涉及如下幾點:

  1. 節點限流政策的選擇及內建;
  2. 節點調用度量時間片的設定政策;
  3. 計數日志采集規範及度量規範;
  4. 限流配置規範;
  5. 限流指令規範。

本文節選自《微服務治理:體系、架構及實踐》一書

一文搞定算法和架構,微服務接口限流不用愁!1、服務限流的概念2、單服務節點限流3、服務叢集限流4、限流的難點及注意事項5、作者簡介

5、作者簡介

作者簡介: 著有《微服務治理:體系、架構及實踐》一書,目前在金融行業負責基金直銷平台的整體技術架構和技術團隊管理;在此之前,在華為的中間件技術團隊,任六級技術專家,主導了多款華為軟體的雲計算産品的規劃、設計、建構及落地工作,包括APaaS、ASPaaS、服務治理平台、分布式服務調測架構等幾款産品;更早之前,在當當網的運作産品中心做技術負責人,主要負責電商中背景的倉儲、物流、客服等系統的重構優化及技術管理工作。

個人從業十多年,在并行計算、大規模分布式服務及治理、中間件雲化及服務化(PaaS)、APM監控、基礎開發平台、資料內建及治理等領域都有技術積累,如果大家在這些領域有疑問或好的建議,歡迎共同探讨。

繼續閱讀