Sentinel-Go 源碼之一開(kāi)篇之作
本文轉(zhuǎn)載自微信公眾號(hào)「捉蟲大師」,作者捉蟲大師。轉(zhuǎn)載本文請(qǐng)聯(lián)系捉蟲大師公眾號(hào)。
大家好呀,打算寫一個(gè) Go 語(yǔ)言組件源碼分析系列,一是為了能學(xué)習(xí)下 Go 語(yǔ)言,看下別人是怎么寫 Go 的,二是也掌握一個(gè)組件。
本次選擇了 Sentinel-Go,一是對(duì) Java 版本的 Sentinel 算是有一些了解,也在生產(chǎn)上落地過(guò),二是感覺(jué)他的代碼應(yīng)該不會(huì)太復(fù)雜(僅僅是感覺(jué)),三是在云原生越來(lái)越熱的趨勢(shì)下,用 Go 實(shí)現(xiàn)的限流降級(jí)容錯(cuò)應(yīng)該是比較通用的。
源碼閱讀本身是枯燥的,我盡量用容易理解的語(yǔ)言來(lái)描述,希望大家也多支持我的文章,點(diǎn)個(gè)贊、在看和關(guān)注就是對(duì)我最大的支持。
背景
Sentinel 簡(jiǎn)介
隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來(lái)越重要。Sentinel 是面向分布式服務(wù)架構(gòu)的流量控制組件,主要以流量為切入點(diǎn),從流量控制、熔斷降級(jí)、系統(tǒng)自適應(yīng)保護(hù)等多個(gè)維度來(lái)幫助您保障微服務(wù)的穩(wěn)定性。
Sentinel 是阿里2018年開(kāi)源的項(xiàng)目,最初是 Java 版本,截止目前有 17.6k 的star,項(xiàng)目地址為
https://github.com/alibaba/Sentinel/
2020年又開(kāi)源了 Go 的版本,目的是朝云原生方向演進(jìn),截止目前 1.7k star,項(xiàng)目地址為
https://github.com/alibaba/sentinel-golang
Sentinel 的作用
在上面簡(jiǎn)介中也說(shuō)了,Sentinel 是微服務(wù)時(shí)代保障穩(wěn)定的神兵利器
舉個(gè)例子:電商系統(tǒng)中用戶瀏覽商品詳情頁(yè),通常會(huì)通過(guò) RPC 調(diào)用多個(gè)微服務(wù),查詢商品信息的同時(shí)還會(huì)查詢用戶的信息,也會(huì)展示優(yōu)惠信息,通常下拉列表還會(huì)展示推薦,廣告等信息,如下圖
如果流量較大時(shí),CouponService 容量不足,或者某種原因?qū)е?RecomService 不可用,此時(shí) AggrService 會(huì)被拖死,導(dǎo)致商品詳情服務(wù)不可用,但仔細(xì)想想這些服務(wù)不是那么重要,可以進(jìn)行限流或者直接降級(jí)(不再調(diào)用),總比直接服務(wù)不用要好吧
又或者流量實(shí)在太高,ProductService 也頂不住了,那是否可以采取限流措施,保住部分用戶的請(qǐng)求是正常的,也比全部不可用要好
這些問(wèn)題,Sentinel 都能解決
Sentinel 提供的能力
Sentinel 將要保護(hù)的對(duì)象(可以是某個(gè)服務(wù)或一段代碼)抽象為資源,通過(guò)動(dòng)態(tài)下發(fā)的規(guī)則,對(duì)資源進(jìn)行
- 流量控制
- 熔斷降級(jí)
針對(duì)這兩個(gè)主要功能又有很多的玩法,比如限流是針對(duì)QPS還是并發(fā)數(shù),控制的效果是直接拒絕還是排隊(duì)等等。
當(dāng)然 Sentinel 也提供一個(gè)開(kāi)箱即用的 Dashboard,可擴(kuò)展配中心進(jìn)行下發(fā)規(guī)則,展示監(jiān)控指標(biāo),調(diào)用關(guān)系鏈等等
快速開(kāi)始
源碼閱讀環(huán)境準(zhǔn)備
- fork 源碼到自己倉(cāng)庫(kù),便于增加注釋
- 拉取源碼到本地
git clone git@github.com:lkxiaolou/sentinel-golang.git
- 導(dǎo)入 IDE,由于我既要寫 Java 又要寫 Go,所以用 IntelliJ IDEA 比較方便,只要裝一個(gè) Go plugin 就可以了
- 導(dǎo)入后,一般 IDE 會(huì)自動(dòng)下載依賴,如果沒(méi)有自動(dòng)下載,試試執(zhí)行( Go 安裝就不說(shuō)了)
go mod download
目錄結(jié)構(gòu)介紹
- sentinel-golang
- api:對(duì)外暴露的接口
- core:核心實(shí)現(xiàn)
- example:使用例子
- exporter:Prometheus的exporter
- ext:擴(kuò)展接口,主要是動(dòng)態(tài)規(guī)則配置中心擴(kuò)展接口
- logging:日志模塊
- pkg:第三方插件的實(shí)現(xiàn),比如各個(gè)組件適用 Sentinel 的 adapter,以及 Sentinel 對(duì)接各種第三方配置中心的擴(kuò)展實(shí)現(xiàn)
- tests:測(cè)試類代碼,包括單元測(cè)試、benchmark
- util:工具類
樣例跑通
在 /example 目錄下新建 mytests 目錄,并創(chuàng)建一個(gè) quick_start.go 文件,按照官網(wǎng)給出的例子,先用最簡(jiǎn)單的默認(rèn)方式初始化
- if err := sentinel.InitDefault(); err != nil {
- // 初始化失敗
- panic(err.Error())
- }
再用寫死的方式加載規(guī)則
- // 資源名
- resource := "test-resource"
- // 加載流控規(guī)則,寫死
- _, err := flow.LoadRules([]*flow.Rule{
- {
- Resource: resource,
- // Threshold + StatIntervalInMs 可組合出多長(zhǎng)時(shí)間限制通過(guò)多少請(qǐng)求,這里相當(dāng)于限制為 10 qps
- Threshold: 10,
- StatIntervalInMs: 1000,
- // 暫時(shí)不用關(guān)注這些參數(shù)
- TokenCalculateStrategy: flow.Direct,
- ControlBehavior: flow.Reject,
- },
- })
最后寫測(cè)試代碼
- // 修改這個(gè)看看效果吧
- currency := 100
- for i := 0; i < currency; i++ {
- go func() {
- e, b := sentinel.Entry(resource, sentinel.WithTrafficType(base.Inbound))
- if b != nil {
- // 被流控
- fmt.Printf("blocked %s \n", b.BlockMsg())
- } else {
- // 通過(guò)
- fmt.Println("pass...")
- // 通過(guò)后必須調(diào)用Exit
- e.Exit()
- }
- }()
- }
這里限制了 10 qps,我們用 100 個(gè)協(xié)程并發(fā)測(cè)試跑一下,剛好通過(guò)10個(gè)請(qǐng)求
測(cè)試代碼已上傳到我的倉(cāng)庫(kù)
https://github.com/lkxiaolou/sentinel-golang/tree/master/example/mytests
總結(jié)
本文介紹了 Sentinel 的和它能解決的問(wèn)題,以及源碼閱讀的一些準(zhǔn)備工作,并跑通了一個(gè)最簡(jiǎn)單的例子,見(jiàn)識(shí)到了 Sentinel 限流的效果,本文先到這里,我們下一節(jié)見(jiàn)。