如何設(shè)計(jì)服務(wù)接口API限流功能?
1 限流目的限流目的是對(duì)系統(tǒng)進(jìn)行保護(hù)。當(dāng)訪問量激增,超過系統(tǒng)可以承受的流量,則需要把超出的流量擋住,不進(jìn)行業(yè)務(wù)邏輯直接返回。
2 預(yù)估系統(tǒng)流量上限采用壓測(cè)方法。對(duì)某個(gè)接口進(jìn)行壓測(cè),逐步調(diào)高并發(fā)量和持續(xù)時(shí)間,達(dá)到系統(tǒng)瓶頸時(shí)(錯(cuò)誤率高,響應(yīng)時(shí)間長(zhǎng))記錄下并發(fā)量,這個(gè)值就是當(dāng)前系統(tǒng)流量上限。
3 限流方案3.1 系統(tǒng)維度從系統(tǒng)維度來看可以分為單機(jī)限流和集群限流兩種方式。
單機(jī)限流是對(duì)每一臺(tái)機(jī)器限流,假設(shè)每臺(tái)機(jī)器限流100QPS,集群有10臺(tái)機(jī)器,那么整個(gè)集群有1000QPS能力。可以使用Guava RateLimiter、Java并發(fā)包Semaphore實(shí)現(xiàn)單機(jī)限流。
集群限流是對(duì)整個(gè)集群進(jìn)行限流,比如預(yù)估整個(gè)集群能力有1000QPS,還有一種場(chǎng)景是限次,比如整個(gè)集群只能調(diào)用第三方接口多少次。可以使用Redis實(shí)現(xiàn)全局限流。
3.2 方法維度限流常用方法有以下三種:
計(jì)數(shù)器法維護(hù)一個(gè)計(jì)數(shù)器,這個(gè)計(jì)數(shù)器有一個(gè)時(shí)間窗口,在當(dāng)前時(shí)間窗口,每當(dāng)一個(gè)新請(qǐng)求到來時(shí),計(jì)數(shù)器自增,當(dāng)計(jì)數(shù)器自增達(dá)到設(shè)置的上限時(shí),不再提供服務(wù)。滑動(dòng)到下一個(gè)時(shí)間窗口時(shí),計(jì)數(shù)器重置。這種方法的特點(diǎn)是簡(jiǎn)單,但是在時(shí)間窗口臨界點(diǎn),可能會(huì)出現(xiàn)超出流量的問題。
漏桶算法漏桶算法強(qiáng)制一個(gè)常量的輸出速率而不管輸入數(shù)據(jù)流的突發(fā)性。當(dāng)輸入空閑時(shí),該算法不執(zhí)行任何動(dòng)作,就像用一個(gè)底部開了個(gè)洞的漏桶接水一樣,水進(jìn)入到漏桶里,桶里的水通過下面的孔以固定的速率流出。當(dāng)水流入速度過大會(huì)直接溢出。
令牌桶算法我推薦這種方法。一個(gè)容量固定的桶,以一個(gè)恒定的速率產(chǎn)生令牌,如果桶內(nèi)的令牌滿了則多余的令牌會(huì)被丟棄。每當(dāng)請(qǐng)求進(jìn)來時(shí),先去桶內(nèi)拿一個(gè)令牌,桶內(nèi)的令牌拿完了,則必須等待桶內(nèi)產(chǎn)生令牌才能允許后續(xù)的請(qǐng)求(或者直接拒絕)。由于桶內(nèi)可以堆積一定的令牌(一般為桶容量),所以令牌桶算法優(yōu)點(diǎn)是可以允許一定量的流量高峰。
Guava提供了限流工具RateLimiter基于令牌桶完成限流。也可以通過編寫Lua腳本通過Redis實(shí)現(xiàn)全局令牌桶。