大家好,我叫黃博文,花名延枚,目前負責云效旗下產品Flow流水線的設計和開發,在微服務架構下,服務越來越多,服務之間的呼叫也會越來越復雜,如何保障服務的高可用性就成為了一個挑戰,之前我參與過的某個產品就曾出過故障,原因是某個API呼叫突然間增加了數十倍,導致服務負載過高,影響了用戶使用,如果當時能夠有一種機制能快速對這個例外的API進行限流或熔斷,就能避免服務陷入不穩定的狀況,云效自身使用阿里云 AHAS (Application High Availability Service)來保障應用的高可用,本文總結了一份AHAS限流實踐指南,如果你的系統有被惡意用戶攻擊的風險,或者系統中某個應用出現例外可能會造成雪崩效應,那么這篇文章會對你有所幫助,

一個完善的應用高可用解決方案,首先需要對應用的介面進行監控,能夠實時統計當前應用介面的QPS情況,其次要能夠針對不同API和場景配置各種限流和熔斷規則,比如如果某個API QPS超過300了就需要對超過的呼叫做限流處理,能夠提供限流的工具很多,流行的有guava RateLimiter、Hystrix等,但這些工具上手成本較高,搭建起整個體系并不簡單,
如何快速建立應用的限流體系?這就要介紹阿里云提供的應用高可用服務 AHAS (Application High Availability Service),AHAS 是經阿里巴巴內部多年高可用體系沉淀下來的云產品,基于阿里開源流控降級組件 Sentinel,以流量與容錯為切入點,從流量控制、不穩定呼叫隔離、熔斷降級、熱點流量防護、系統自適應過載保護、集群流控、服務防抖動等多個維度來幫助保障服務和網關的穩定性,同時提供秒級的流量監控分析功能,AHAS 不僅在阿里內部淘寶、天貓等電商領域有著廣泛的應用,在互聯網金融、在線教育、游戲、直播行業和其他大型政央企行業也有著大量的實踐,
限流限的是什么
限流的目的是為了避免系統承受過大的流量導致不可用,那么這些流量會來自哪里呢?
按照訪問的方式,可以分為:
- HTTP的同步呼叫,比如你在通過瀏覽器訪問一個站點的頁面時候,就會產生這種流量,
- 后臺任務呼叫,這個取決于業務形態,比如一個站點向用戶開放了定時執行任務的能力,那么用戶每多配置一個這種任務,就會對系統造成更多的流量,
按照訪問的意圖,可以分為:
- 正常業務增長,比如用戶增加了,做了運營活動等等,都會導致整體的業務量增加,
- 惡意用戶的惡意行為,比如某個用戶對站點進行DDOS攻擊,或者對于上面提到的那種提供定時執行任務能力的網站而言,惡意的配置大量的定時任務,從而間接對系統造成巨大的負載,等等,
按照訪問的來源,可以分為:
- 終端用戶,這些用戶是最終使用者,其總訪問量會隨著正常業務的增長而增長,
- 系統呼叫,比如有其他系統基于你的能力構建自己的產品,那么就要和這些系統進行約定,訪問的最大頻率是多少,并把這些頻率的值落地在限流策略中,
了解了流量的來源之后,我們就知道應該限制什么了,
- 限制整個系統的使用頻率,這個在實際的使用中,通常會換算成單機的使用頻率,保證單機不被壓垮,同時配合告警,出現瓶頸時候,通過緊急擴容來解決問題,
- 限制單個用戶(或者單個租戶,取決于你的業務形態)的使用頻率,
- 限制上游不同的系統呼叫的使用頻率,
- 針對上述的限制,都需要能夠支持HTTP的同步呼叫和后臺任務呼叫,
接下來我們從保證系統整體可用性、防止個別用戶濫用、隔離上游系統例外呼叫以及全方位限流4個方面,具體講解如何使用阿里云AHAS實作限流,
保證系統整體可用性
配置限流時,我們需要建立一個通用的限流規則保障核心介面的穩定性,避免單點瓶頸引發全域問題,
一個流控規則包含以下內容:
- 介面名稱:即對哪個介面進行流控,
- 來源應用:設定為default,即對所有呼叫方都一視同仁,對整個系統的呼叫進行限流,關于這個配置的用法,會在后面的“針對其他上游系統呼叫的限流”部分展開討論,
- 單機QPS閾值:單機的QPS容量,超過閾值后會被限流
- 流控效果:當介面呼叫超過QPS閾值后的處理措施

我們也可以配置觸發限流后的介面回傳值,對于Web介面而言,通常被限流的介面會回傳429 Too Many Requests錯誤碼,告知呼叫方請求太頻繁,

對一個介面進行限流時,難點是填寫具體的QPS閾值,我們可以在性能測驗環境對應用進行壓測,壓出單機下某個介面的QPS極限值,然后將閾值定為極限值的某個比例,比如極限值的90%,比如某個介面單機可承受極限為200QPS,那么閾值可定為200*90%= 180,
防止個別用戶濫用
這個場景下,需要先梳理出來系統的核心業務入口,通常是service層的一個入口函式,針對每個入口函式預設單個用戶合理的使用頻率,然后就可以利用AHAS的熱點引數流控能力,來并進行限制,
在入口函式上添加注解:
@SentinelResource(value = "https://www.cnblogs.com/yyds114/p/biz1")
public Result doBussinessLogic(String uid, int type) {
// uid引數索引為0,type引數索引為1,
// some logic here...
}
代碼中需要做兩件事情
- 從請求中提取出需要防護的維度,比如上面代碼中的uid,即用戶的標識,并保證該標識作為業務入口函式的入參傳入,
- 給該函式添加@SentinelResource注解,其中的value="https://www.cnblogs.com/yyds114/p/biz1"為這個資源的標識,會用在控制臺配置中進行參考,
然后在控制臺進行配置,假設我們希望,在服務級別每分鐘單用戶最多呼叫20次,服務共有5個實體,可以進行如下配置,意思是在第0個引數,也就是用戶,這個維度上進行限流,單機最多每60s進行4次呼叫,則集群維度就是每分鐘最多20次呼叫,

目前AHAS還不支持直接進行集群維度的配置,實際使用中需要簡單的換算下,
詳細說明,請參考:
https://help.aliyun.com/document_detail/147896.html ,
隔離上游系統例外呼叫
對于一個應用的介面來說,通常會被上游多個系統呼叫,上面雖然介紹了如何對單個介面進行整體限流,但實際場景中,我們會需要對不同的上游系統采用不同的限流閾值,比如上游呼叫方A是主鏈路,希望QPS閾值能高一些,上游呼叫方B為旁支鏈路,QPS閾值可以低一些,那么我們需要在Web容器啟動時注入抽取租戶特征值的攔截器,根據來源應用標識來對不同來源給予不同的閾值,
@Configuration
public class InterceptorConfiguration extends WebMvcConfigurerAdapter {
@PostConstruct
public void setOriginParser() {
WebCallbackManager.setRequestOriginParser(httpServletRequest -> httpServletRequest.getHeader("income"));
}
}
WebCallbackManager.setRequestOriginParser 接受一個引數為HttpServletRequest的回呼,我們需要通過HttpServletRquest物件中的內容來區分呼叫方A和B,比如應用A和B在呼叫介面時會傳入不同的header income,那么就可以通過該header來區分來源應用A和B,最后在流控規則中建立起對A和B不同限流閾值,如下圖所示,


全方位限流,不限于HTTP
AHAS可以快速的把Web介面納入到流控之中,但如果我們應用的一些代碼不屬于Web介面,但也想啟用流控,那么仍然可以使用AHAS提供的熱點規則的能力,以下是個示例,
@SentinelResource(blockHandler = "blockHandlerExecuteTask")
public Boolean executeTask(Long taskId) throws Exception {
return taskService.executeTask(taskId);
}
public Boolean blockHandlerExecuteTask(Long taskId, BlockException ex) {
throw new RuntimeException("execute task exceed");
}
重啟應用后,在介面詳情頁的自定義埋點tab中,就可以看到AHAS收集的自定義埋點介面資料,介面名稱組成為類名:方法名的格式,

接著可以給這個埋點介面配置限流規則,開啟防護,

以上就是我們使用AHAS服務時配置限流的常用實踐,希望對大家有所幫助,
點擊下方鏈接,免費體驗云效流水線Flow,
https://www.aliyun.com/product/yunxiao/flow?channel=yy_practice

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/449111.html
標籤:其他
