国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn)

這篇具有很好參考價值的文章主要介紹了聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

我們知道,對于一個項(xiàng)目之初,我們不可能上來就按幾千的并發(fā)去配置,為什么?兩個方面,第一個是成本高。第二個是維護(hù)難度大。即便是天貓?zhí)詫氝@種,也是采用的動態(tài)擴(kuò)容的方式來應(yīng)對雙十一。那么一個項(xiàng)目如何應(yīng)對突然的高并發(fā),我們有哪些常用的措施和處理呢?我們接下來就來看看 限流熔斷和降級

限流

比如系統(tǒng)本來可以處理1000個請求,忽然一下子來了2000個,為了不讓系統(tǒng)崩潰,最簡單的方式,就是限流,我只接1000個,超出1000個的不提供服務(wù)。
那么限流的方法有哪些呢?我們繼續(xù)看。

流量計數(shù)器

看名字就知道了,比如限制每秒的請求數(shù),比如我們每秒限1000。但是這樣有一個問題,就是這種流量計數(shù)在某個時間點(diǎn)可能是失效的。因?yàn)檫@種計數(shù)的前提是在1s內(nèi)我們假定了請求是勻速的。但是如果是這種情況,就可能起不到限流的效果。
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

滑動時間窗口

既然以時間為界限不行的話,我們就以時間窗口為界限,保證每個時間段內(nèi)都不能超過1000qps

漏桶算法

一個請求在被系統(tǒng)處理之前,先找一個漏桶存起來,然后再以固定速率流出,比如這個漏桶可以存1000個請求,如果漏桶中有超出1000個未被處理的請求,那么這部分請求就會溢出,也就是被丟棄,比如我們常用的消息隊(duì)列。

令牌桶算法

令牌桶就是以固定的速率產(chǎn)生,并緩存到令牌桶中,每個請求必選先獲取令牌才能系統(tǒng)處理,令牌桶存滿的時候,多余的令牌被丟棄。

nginx的限流

我們以nginx為例,看一下nginx是怎么限流的。
nginx的限流主要有兩種方式,一種是限制訪問頻率,一種是限制并發(fā)連接數(shù)。

  • limit_req_zone:用來限制單位時間內(nèi)的請求數(shù),即速率限制 , 采用的漏桶算法 “l(fā)eaky bucket”。例如下面的配置
http {
	 # 定義限流策略  $binary_remote_addr代表限流對象,表示基于客戶端ip限流  
	 # zone:定義內(nèi)存區(qū)大小,表示用10m的空間來存儲ip  
	 # rate 1r/s表示每秒處理一個請求,nginx實(shí)際的管理單位時間是毫秒,其實(shí)就是 1000ms處理一個請求
	 limit_req_zone $binary_remote_addr zone=rateLimit:10m rate=1r/s ;
	 # 搜索服務(wù)的虛擬主機(jī)
	 server {
		 location / {
		 # 使用限流策略,burst=5,重點(diǎn)說明一下這個配置,burst 爆發(fā)的意思,這個配置的意思是設(shè)置一個大小為 5 的緩沖區(qū)(隊(duì)列)當(dāng)有大量請求(爆發(fā))過來時,
		 # 超過了訪問頻次限制的請求可以先放到這個緩沖區(qū)內(nèi)。nodelay,如果設(shè)置,超過訪問頻次而且緩沖區(qū)也滿了的時候就會直接返回 503,如果沒有設(shè)置,則所
		 # 有請求會等待排隊(duì)。
		 limit_req zone=rateLimit burst=5 nodelay;
	 	}
	 } 
}

我們1s內(nèi)發(fā)起200個請求看一下,6個請求成功了,也就是每秒1個的請求和5個緩沖區(qū)請求成功,其他的返回503

聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

  • limit_conn_zone:用來限制同一時間連接數(shù),即并發(fā)限制。
http {
	 # 定義限流策略
	 limit_conn_zone $binary_remote_addr zone=perip:10m;
	 limit_conn_zone $server_name zone=perserver:10m;
	 # 搜索服務(wù)的虛擬主機(jī)
	 server {
		 location / {
			 # 對應(yīng)的 key 是 $binary_remote_addr,表示限制單個 IP 同時最多能持有 1 個連接。
			 limit_conn perip 1;
			 # 對應(yīng)的 key 是 $server_name,表示虛擬主機(jī)(server) 同時能處理并發(fā)連接的總數(shù)。注意,只有當(dāng) request header 被
			后端 server 處理后,這個連接才進(jìn)行計數(shù)。
			 limit_conn perserver 10 ;
			 proxy_pass http://train-manager-search ;
		 }
	 } 
}

降級

我們前面看到了,限流之后有一部分的請求直接返回的503,這樣對用戶體驗(yàn)非常不好,但是我們可能有時候會看到這樣的頁面,比如 xx活動異?;鸨?,請稍后再試等提示頁?;蛘呤悄硞€商品詳情頁,優(yōu)先推送緩存數(shù)據(jù)而非實(shí)時數(shù)據(jù),這就是服務(wù)降級。服務(wù)降級的核心是對非核心的,非關(guān)鍵的業(yè)務(wù)進(jìn)行降級。

熔斷

熔斷這個詞大家應(yīng)該是熟悉的,比如家里的保險絲,當(dāng)電流過大或者發(fā)生短路的時候,就會熔斷,從而避免發(fā)生更大的危害。服務(wù)熔斷也類似,當(dāng)被調(diào)用方出現(xiàn)故障。調(diào)用方出于自我保護(hù)的目的,主動停止調(diào)用。為什么要主動停止調(diào)用?我之前就有過這樣的經(jīng)歷,由于某個MySQL服務(wù)器性能的問題,執(zhí)行一個SQL要好幾秒。MySQL的請求越來越多,最終導(dǎo)致MySQL宕機(jī),接著php的請求也越來越多,php進(jìn)程打滿,最終php也跟著報錯。最終整個服務(wù)掛掉。

技術(shù)選型

前面我們講了限流 熔斷 和降級 ,并且用nginx演示了限流的示例。我們接下來就來看看go中,有哪些組件可以實(shí)現(xiàn)流量控制呢,這里我們挑出來兩個常見的sentinel和hystrix來對比一下,基于功能性,我們選擇了sentinel。
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

sentinel

Sentinel 是阿里中間件團(tuán)隊(duì)開源的,面向分布式服務(wù)架構(gòu)的輕量級高可用流量控制組件,主要以流量為切入點(diǎn),從流量控制、熔斷降級、系統(tǒng)負(fù)載保護(hù)等多個維度來幫助用戶保護(hù)服務(wù)的穩(wěn)定性??梢钥吹剑瑂entinel是2020年推出了go版本。

聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

sentinel-golang實(shí)現(xiàn)限流

  • 首先,文檔地址先找到
流控的配置規(guī)則

一條流控規(guī)則主要由下面幾個因素組成,我們可以組合這些元素來實(shí)現(xiàn)不同的限流效果:

  • Resource:資源名,即規(guī)則的作用目標(biāo)。
  • TokenCalculateStrategy: 當(dāng)前流量控制器的Token計算策略。Direct表示直接使用字段 Threshold 作為閾值;WarmUp表示使用預(yù)熱方式計算Token的閾值。
  • ControlBehavior: 表示流量控制器的控制策略;Reject表示超過閾值直接拒絕,Throttling表示勻速排隊(duì)。
  • Threshold: 表示流控閾值;如果字段 StatIntervalInMs 是1000(也就是1秒),那么Threshold就表示QPS,流量控制器也就會依據(jù)資源的QPS來做流控。
  • RelationStrategy: 調(diào)用關(guān)系限流策略,CurrentResource表示使用當(dāng)前規(guī)則的resource做流控;AssociatedResource表示使用關(guān)聯(lián)的resource做流控,關(guān)聯(lián)的resource在字段 RefResource 定義;
  • RefResource: 關(guān)聯(lián)的resource;
  • WarmUpPeriodSec: 預(yù)熱的時間長度,該字段僅僅對 WarmUp 的TokenCalculateStrategy生效;
  • WarmUpColdFactor: 預(yù)熱的因子,默認(rèn)是3,該值的設(shè)置會影響預(yù)熱的速度,該字段僅僅對 - WarmUp 的TokenCalculateStrategy生效;
  • MaxQueueingTimeMs: 勻速排隊(duì)的最大等待時間,該字段僅僅對 Throttling ControlBehavior生效;
  • StatIntervalInMs: 規(guī)則對應(yīng)的流量控制器的獨(dú)立統(tǒng)計結(jié)構(gòu)的統(tǒng)計周期。如果StatIntervalInMs是1000,也就是統(tǒng)計QPS。

這里特別強(qiáng)調(diào)一下 StatIntervalInMs 和 Threshold 這兩個字段,這兩個字段決定了流量控制器的靈敏度。以 Direct + Reject 的流控策略為例,流量控制器的行為就是在 StatIntervalInMs 周期內(nèi),允許的最大請求數(shù)量是Threshold。比如如果 StatIntervalInMs 是 10000,Threshold 是10000,那么流量控制器的行為就是控制該資源10s內(nèi)運(yùn)行最多10000次訪問。

接下來我們參照官方的demo,寫一個更簡單易懂的一段代碼來解釋

  • 先來看一下最簡潔的丐版
package main

import (
	sentinel "github.com/alibaba/sentinel-golang/api"
	"github.com/alibaba/sentinel-golang/core/base"
	"github.com/alibaba/sentinel-golang/core/flow"
	"log"
)

func main() {
	//初始化sentinel
	err := sentinel.InitDefault()
	if err != nil {
		log.Fatalf("初始化sentinel失敗:%v", err)
	}
	//配置限流規(guī)則 可以根據(jù)resource配置多個規(guī)則
	_, err = flow.LoadRules([]*flow.Rule{

		//rule1規(guī)則:1000ms內(nèi)最多處理10個請求,多余的直接拒絕
		{
			Resource:               "rule1",     //規(guī)則的名稱
			TokenCalculateStrategy: flow.Direct, //當(dāng)前流量控制器的Token計算策略。Direct表示直接使用字段 Threshold 作為閾值;WarmUp表示使用預(yù)熱方式計算Token的閾值。
			ControlBehavior:        flow.Reject, //表示流量控制器的控制策略;Reject表示超過閾值直接拒絕,Throttling表示勻速排隊(duì)。
			Threshold:              10,          //表示流控閾值;如果字段 StatIntervalInMs 是1000(也就是1秒),那么Threshold就表示QPS,流量控制器也就會依據(jù)資源的QPS來做流控。
			StatIntervalInMs:       1000,        //StatIntervalInMs 和 Threshold 這兩個字段,這兩個字段決定了流量控制器的靈敏度。以 Direct + Reject 的流控策略為例,流量控制器的行為就是在 StatIntervalInMs 周期內(nèi),允許的最大請求數(shù)量是Threshold。比如如果 StatIntervalInMs 是 10000,Threshold 是10000,那么流量控制器的行為就是控制該資源10s內(nèi)運(yùn)行最多10000次訪問。
		},
	})
	if err != nil {
		log.Fatalf("初始化sentinel加載限流規(guī)則失敗:%v", err)
	}

	//最終的限流實(shí)現(xiàn)通過這個方法實(shí)現(xiàn)
	e, b := sentinel.Entry("rule1", sentinel.WithTrafficType(base.Inbound))
	if b != nil {
		log.Println("限流了")
	} else {
		log.Println("未限流")
		e.Exit()
	}
}

  • 上面我們看到,是通過Entry來計數(shù)的,接下來我們通過for循環(huán)來,一秒內(nèi)發(fā)送20個計數(shù)看看什么樣
	for i := 0; i < 20; i++ {
		//最終的限流實(shí)現(xiàn)通過這個方法實(shí)現(xiàn)
		e, b := sentinel.Entry("rule1", sentinel.WithTrafficType(base.Inbound))
		if b != nil {
			log.Printf("限流了%d\n", i)
		} else {
			log.Printf("未限流%d\n", i)
			e.Exit()
		}
	}
  • 我們看到結(jié)果,前10個通過,后10個限流了
    聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
預(yù)熱

當(dāng)前流量控制器的Token計算策略。Direct表示直接使用字段 Threshold 作為閾值;WarmUp表示使用預(yù)熱方式計算Token的閾值。

  • WarmUp
    Direct我知道了,但是預(yù)熱是什么意思呢?我們舉個例子,比如我們的流量一直是低水位的,限流配置的顆粒度也比較大,5s內(nèi)控制2000個流量,但是我們前面說過,流量計數(shù)的話,你配置了5s內(nèi)2000個,很可能在100ms內(nèi)就打進(jìn)來2000個請求,那系統(tǒng)可能就奔潰了。所以sentinel提供了這種WarmUp 方式,即預(yù)熱/冷啟動方式。通過"冷啟動",讓通過的流量緩慢增加,在一定時間內(nèi)逐漸增加到閾值上限,給冷系統(tǒng)一個預(yù)熱的時間,避免冷系統(tǒng)被壓垮。
    聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
  • 相關(guān)代碼如下
func main() {
	//初始化sentinel
	err := sentinel.InitDefault()
	if err != nil {
		log.Fatalf("初始化sentinel失敗:%v", err)
	}
	//配置限流規(guī)則 可以根據(jù)resource配置多個規(guī)則
	_, err = flow.LoadRules([]*flow.Rule{

		//rule1規(guī)則:1000ms內(nèi)最多處理10個請求,多余的直接拒絕
		{
			Resource:               "rule1",         //規(guī)則的名稱
			TokenCalculateStrategy: flow.WarmUp,     //冷啟動
			ControlBehavior:        flow.Throttling, //表示流量控制器的控制策略;Reject表示超過閾值直接拒絕,Throttling表示勻速排隊(duì)。
			Threshold:              1000,            //表示流控閾值;如果字段 StatIntervalInMs 是1000(
			// 也就是1秒),那么Threshold就表示QPS,流量控制器也就會依據(jù)資源的QPS來做流控。
			//配置預(yù)熱時長
			WarmUpPeriodSec: 20, //30s內(nèi)達(dá)到1000
		},
	})
	if err != nil {
		log.Fatalf("初始化sentinel加載限流規(guī)則失敗:%v", err)
	}
	ch := make(chan int) //阻塞程序

	var globalTotal, passTotal, blockTotal int64
	var perGlobalTotal, perPassTotal, perBlockTotal int64
	var globalTotalOld, passTotalOld, blockTotalOld int64

	//在每一秒統(tǒng)計一次 一秒內(nèi)通過了多少,總共有多少,block了多少
	for i := 0; i < 100; i++ {
		go func() {
			for {
				//10ms執(zhí)行一次
				time.Sleep(1 * 10)
				globalTotal++
				//最終的限流實(shí)現(xiàn)通過這個方法實(shí)現(xiàn)
				e, b := sentinel.Entry("rule1", sentinel.WithTrafficType(base.Inbound))
				if b != nil {
					blockTotal++
				} else {
					passTotal++
					e.Exit()
				}
			}
		}()
	}

	//每秒打印一下統(tǒng)計數(shù)
	go func() {
		nowSec := 1
		for {
			time.Sleep(1 * time.Second)
			perGlobalTotal = globalTotal - globalTotalOld
			perPassTotal = passTotal - passTotalOld
			perBlockTotal = blockTotal - blockTotalOld
			log.Printf("第%d秒接收請求數(shù):%d,通過請求數(shù):%d,block請求數(shù):%d", nowSec, perGlobalTotal, perPassTotal, perBlockTotal)
			globalTotalOld = globalTotal
			passTotalOld = passTotal
			blockTotalOld = blockTotal
			nowSec++
		}
	}()

	<-ch

}
  • 20s內(nèi)逐漸提升至1000
    聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
Throttling勻速通過

字段 ControlBehavior 表示表示流量控制器的控制行為,目前 Sentinel 支持兩種控制行為:

Reject:表示如果當(dāng)前統(tǒng)計周期內(nèi),統(tǒng)計結(jié)構(gòu)統(tǒng)計的請求數(shù)超過了閾值,就直接拒絕。
Throttling:表示勻速排隊(duì)的統(tǒng)計策略。它的中心思想是,以固定的間隔時間讓請求通過。當(dāng)請求到來的時候,如果當(dāng)前請求距離上個通過的請求通過的時間間隔不小于預(yù)設(shè)值,則讓當(dāng)前請求通過;否則,計算當(dāng)前請求的預(yù)期通過時間,如果該請求的預(yù)期通過時間小于規(guī)則預(yù)設(shè)的 timeout 時間,則該請求會等待直到預(yù)設(shè)時間到來通過(排隊(duì)等待處理);若預(yù)期的通過時間超出最大排隊(duì)時長,則直接拒接這個請求。
勻速排隊(duì)方式會嚴(yán)格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應(yīng)的是漏桶算法。該方式的作用如下圖所示:
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

這種方式主要用于處理間隔性突發(fā)的流量,例如消息隊(duì)列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處于空閑狀態(tài),我們希望系統(tǒng)能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多余的請求。
比如我們設(shè)置一個1秒內(nèi)允許通過2個,來試一下,相關(guān)代碼如下

func main() {
	ch := make(chan int)
	//初始化sentinel
	err := sentinel.InitDefault()
	if err != nil {
		log.Fatalf("初始化sentinel失敗:%v", err)
	}
	//配置限流規(guī)則 可以根據(jù)resource配置多個規(guī)則
	_, err = flow.LoadRules([]*flow.Rule{

		//rule1規(guī)則:1000ms內(nèi)最多處理10個請求,多余的直接拒絕
		{
			Resource:               "rule1",         //規(guī)則的名稱
			TokenCalculateStrategy: flow.Direct,     //當(dāng)前流量控制器的Token計算策略。Direct表示直接使用字段 Threshold 作為閾值;WarmUp表示使用預(yù)熱方式計算Token的閾值。
			ControlBehavior:        flow.Throttling, //表示流量控制器的控制策略;Reject表示超過閾值直接拒絕,Throttling表示勻速排隊(duì)。
			Threshold:              2,               //表示流控閾值;如果字段 StatIntervalInMs 是1000(
			// 也就是1秒),那么Threshold就表示QPS,流量控制器也就會依據(jù)資源的QPS來做流控。
			StatIntervalInMs: 1000, //StatIntervalInMs 和 Threshold 這兩個字段,這兩個字段決定了流量控制器的靈敏度。以 Direct + Reject 的流控策略為例,流量控制器的行為就是在 StatIntervalInMs 周期內(nèi),允許的最大請求數(shù)量是Threshold。比如如果 StatIntervalInMs 是 10000,Threshold 是10000,那么流量控制器的行為就是控制該資源10s內(nèi)運(yùn)行最多10000次訪問。
		},
	})
	if err != nil {
		log.Fatalf("初始化sentinel加載限流規(guī)則失敗:%v", err)
	}

	go func() {
		for {
			stamp := time.Now().UnixMicro()
			//最終的限流實(shí)現(xiàn)通過這個方法實(shí)現(xiàn)
			e, b := sentinel.Entry("rule1", sentinel.WithTrafficType(base.Inbound))
			if b != nil {
				//log.Printf("限流了%d\n",stamp )
			} else {
				log.Printf("未限流%d\n", stamp)
				e.Exit()
			}
		}
	}()

	<-ch

}

聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

sentinel-golang實(shí)現(xiàn)熔斷

  • 熔斷器模型
    Sentinel 熔斷降級基于熔斷器模式 (circuit breaker pattern) 實(shí)現(xiàn)。熔斷器內(nèi)部維護(hù)了一個熔斷器的狀態(tài)機(jī),狀態(tài)機(jī)的轉(zhuǎn)換關(guān)系如下圖所示:

聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

  • 靜默期:熔斷器的靜默期是指在系統(tǒng)檢測到異常后的一段時間內(nèi),熔斷器暫時停止對該異常進(jìn)行處理或服務(wù)的響應(yīng)。這個時間段是為了讓系統(tǒng)有時間自我恢復(fù)或避免過度頻繁地觸發(fā)熔斷。

  • 靜默數(shù):在熔斷器的靜默期內(nèi),系統(tǒng)允許的異常發(fā)生次數(shù)。當(dāng)異常發(fā)生的次數(shù)超過了靜默數(shù),熔斷器可能會觸發(fā)并采取相應(yīng)的措施,例如暫時中止服務(wù)以防止進(jìn)一步的問題。這有助于保護(hù)系統(tǒng)免受潛在的破壞性異常的影響。

Sentinel 支持以下幾種熔斷策略:

  • 慢調(diào)用比例策略 (SlowRequestRatio):Sentinel 的熔斷器不在靜默期,并且慢調(diào)用的比例大于設(shè)置的閾值,則接下來的熔斷周期內(nèi)對資源的訪問會自動地被熔斷。該策略下需要設(shè)置允許的調(diào)用 RT 臨界值(即最大的響應(yīng)時間),對該資源訪問的響應(yīng)時間大于該閾值則統(tǒng)計為慢調(diào)用。
  • 錯誤比例策略 (ErrorRatio):Sentinel 的熔斷器不在靜默期,并且在統(tǒng)計周期內(nèi)資源請求訪問異常的比例大于設(shè)定的閾值,則接下來的熔斷周期內(nèi)對資源的訪問會自動地被熔斷。
  • 錯誤計數(shù)策略 (ErrorCount):Sentinel 的熔斷器不在靜默期,并且在統(tǒng)計周期內(nèi)資源請求訪問異常數(shù)大于設(shè)定的閾值,則接下來的熔斷周期內(nèi)對資源的訪問會自動地被熔斷。
  • 注意:這里的錯誤比例熔斷和錯誤計數(shù)熔斷指的業(yè)務(wù)返回錯誤的比例或則計數(shù)。也就是說,如果規(guī)則指定熔斷器策略采用錯誤比例或則錯誤計數(shù),那么為了統(tǒng)計錯誤比例或錯誤計數(shù),需要調(diào)用API: api.TraceError(entry, err) 埋點(diǎn)每個請求的業(yè)務(wù)異常。

我們先通過簡單的丐版代碼來看一下

package main

import (
	"errors"
	"fmt"
	"log"
	"math/rand"
	"time"

	sentinel "github.com/alibaba/sentinel-golang/api"
	"github.com/alibaba/sentinel-golang/core/circuitbreaker"
)

func main() {
	err := sentinel.InitDefault()
	if err != nil {
		log.Fatalf("初始化sentinel失敗:%v", err)
	}
	ch := make(chan int)

	//定制熔斷規(guī)則
	_, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
		{
			Resource:                     "abc",                     //熔斷器的名字
			Strategy:                     circuitbreaker.ErrorCount, //熔斷策略:錯誤計數(shù)策略
			RetryTimeoutMs:               3000,                      //3s內(nèi)嘗試恢復(fù)
			MinRequestAmount:             10,                        //靜默數(shù)
			StatIntervalMs:               5000,                      //5s內(nèi)統(tǒng)計
			StatSlidingWindowBucketCount: 10,
			Threshold:                    50, //50個錯誤數(shù)
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	var total, pass, block, errnum int64
	go func() {
		for {
			now := time.Now().Second()
			total++
			e, b := sentinel.Entry("abc")
			if b != nil {
				block++
				fmt.Printf("熔斷了,相關(guān)參數(shù) total:%d,pass:%d,block:%d,errnum:%d,time:%d\n", total, pass, block, errnum, now)
				time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
			} else {
				//假設(shè)這里我調(diào)用了redis服務(wù),如果返回錯誤,那么我將trace error
				if getRedis() != nil {
					errnum++
					sentinel.TraceError(e, errors.New("redis error"))
				}
				pass++
				time.Sleep(time.Duration(rand.Uint64()%80+10) * time.Millisecond)
				e.Exit()
			}
		}
	}()

	go func() {
		for {
			now := time.Now().Second()
			fmt.Printf("total:%d,pass:%d,block:%d,errnum:%d,time:%d\n", total, pass, block, errnum, now)
			time.Sleep(time.Second * 1)
		}
	}()

	<-ch
}

// 此方法模擬調(diào)用redis
func getRedis() error {
	if rand.Uint64()%20 > 9 {
		return errors.New("i am error")
	}
	return nil
}

我們來看一下執(zhí)行結(jié)果,5s內(nèi)鏈接失敗超過50個,開始熔斷
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
但是我們還看到如下圖的結(jié)果,說明熔斷之后服務(wù)嘗試去恢復(fù)了。這部分流量叫做探測流量。
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
我們前面說了,熔斷器有開啟狀態(tài),關(guān)閉狀態(tài)和半開狀態(tài),這種狀態(tài)我們怎么監(jiān)聽呢,我們接下來給熔斷器加上監(jiān)聽功能,主要代碼如下

type stateChangeTestListener struct {
}

func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
	fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
}

func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
	fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %d, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
}

func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
	fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
}


func main(){
	//.......
	//增加監(jiān)聽
	circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
	//.......
}

我們來看一下執(zhí)行結(jié)果,初始狀態(tài)closed到open
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
從open到halfopen到closed
聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-806034.html

在gin中使用sentinel

  • 我在middleware里面實(shí)現(xiàn)限流方法如下
func FlowControl(c *gin.Context) {
	//初始化sentinel
	err := sentinel.InitDefault()
	if err != nil {
		log.Fatalf("初始化sentinel失敗:%v", err)
	}
	//配置限流規(guī)則 可以根據(jù)resource配置多個規(guī)則
	_, err = flow.LoadRules([]*flow.Rule{

		//rule1規(guī)則:1000ms內(nèi)最多處理2個請求,多余的直接拒絕
		{
			Resource:               "rule1",     //規(guī)則的名稱
			TokenCalculateStrategy: flow.Direct, //當(dāng)前流量控制器的Token計算策略。Direct表示直接使用字段 Threshold 作為閾值;WarmUp表示使用預(yù)熱方式計算Token的閾值。
			ControlBehavior:        flow.Reject, //表示流量控制器的控制策略;Reject表示超過閾值直接拒絕,Throttling表示勻速排隊(duì)。
			Threshold:              2,           //表示流控閾值;如果字段 StatIntervalInMs 是1000(
			// 也就是1秒),那么Threshold就表示QPS,流量控制器也就會依據(jù)資源的QPS來做流控。
			StatIntervalInMs: 1000, //StatIntervalInMs 和 Threshold 這兩個字段,這兩個字段決定了流量控制器的靈敏度。以 Direct + Reject 的流控策略為例,流量控制器的行為就是在 StatIntervalInMs 周期內(nèi),允許的最大請求數(shù)量是Threshold。比如如果 StatIntervalInMs 是 10000,Threshold 是10000,那么流量控制器的行為就是控制該資源10s內(nèi)運(yùn)行最多10000次訪問。
		},
	})
	if err != nil {
		log.Fatalf("初始化sentinel加載限流規(guī)則失敗:%v", err)
	}
	//最終的限流實(shí)現(xiàn)通過這個方法實(shí)現(xiàn)
	e, b := sentinel.Entry("rule1", sentinel.WithTrafficType(base.Inbound))
	if b != nil {
		log.Println("被限流了\n")
		c.JSON(403, gin.H{"code": 403, "msg": "限流了"})
	} else {
		log.Println("未限流\n")
		c.Next()
		e.Exit()
	}
}
  • 在路由中指定使用中間件
// 簡單組: v1
	v1 := router.Group("/v1")
	v1.Use(middleware.TraceLog)
	v1.Use(middleware.FlowControl)
	{
		v1.GET("/blog/detail", handlers.BlogDetail)
	}
  • 通過jmeter發(fā)送20個請求,并查看結(jié)果
    聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言
  • 查看打印日志
    聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn),sentinel,java,開發(fā)語言

到了這里,關(guān)于聊一聊服務(wù)治理三板斧:限流、熔斷、降級和go-sentinel的實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux:進(jìn)度條(小程序)以及git三板斧

    Linux:進(jìn)度條(小程序)以及git三板斧

    在實(shí)現(xiàn)小程序前我們要弄清楚: ???????? 1.緩沖區(qū); ????????2.回車與換行。 分別用gcc來編譯下面兩個程序: 程序一: #include stdio.h int main() { ????????printf(\\\"hello Makefile!n\\\"); ????????sleep(3); ????????return 0; } 程序二: #include stdio.h int main() { ????????prin

    2024年02月05日
    瀏覽(21)
  • 【Linux】git三板斧教程(免密提交配置)

    【Linux】git三板斧教程(免密提交配置)

    ??博客主頁:小智_x0___0x_ ??歡迎關(guān)注:??點(diǎn)贊??收藏??留言 ??系列專欄:Linux入門到精通 ??代碼倉庫:小智的代碼倉庫 Git是一種分布式版本控制系統(tǒng),它可以記錄文件的改動歷史,并且可以多人協(xié)同開發(fā)。Git最初由LinusTorvalds開發(fā),用于管理Linux內(nèi)核的開發(fā)。Git的工作

    2024年02月12日
    瀏覽(18)
  • 【Linux】Linux中g(shù)it的基本使用(三板斧)

    【Linux】Linux中g(shù)it的基本使用(三板斧)

    ??個人主頁:Weraphael ???作者簡介:目前正在學(xué)習(xí) c++ 和 Linux 還有算法 ??專欄:Linux ?? 希望大家多多支持,咱一起進(jìn)步!?? 如果文章有啥瑕疵,希望大佬指點(diǎn)一二 如果文章對你有幫助的話 歡迎 評論?? 點(diǎn)贊???? 收藏 ?? 加關(guān)注?? 簡述什么是 git git 是一種分布式

    2024年02月03日
    瀏覽(26)
  • 阿里云進(jìn)攻“三板斧”:大降價、被集成和大模型

    4月26日上午,2023阿里云合作伙伴大會上,阿里巴巴集團(tuán)董事會主席兼CEO、阿里云智能集團(tuán)CEO張勇再度現(xiàn)身。 2022年底,張勇選擇親自擔(dān)任阿里云智能CEO后,曾在一封面向阿里集團(tuán)的全員信中指出,希望新的一年中阿里的是“進(jìn)”。他要求阿里堅(jiān)持做“好”自己,做“好

    2024年02月11日
    瀏覽(17)
  • [Linux 基礎(chǔ)] Linux使用git上傳gitee三板斧

    [Linux 基礎(chǔ)] Linux使用git上傳gitee三板斧

    Gitee官網(wǎng) 1.2.1 使用Gitee創(chuàng)建項(xiàng)目 1、注冊賬號 如果沒有Gitee的賬號先注冊一個。 注冊完成后登錄。 2、進(jìn)入主頁面,箭頭指向+號處點(diǎn)新建倉庫 3、設(shè)置倉庫信息 4、倉庫創(chuàng)建完成 1.2.2 上傳本地代碼到遠(yuǎn)端倉庫 1、先點(diǎn)擊克隆/下載,復(fù)制下來鏈接 2、下載項(xiàng)目到本地 使用下面的命

    2024年02月06日
    瀏覽(45)
  • [Docker] Portainer + nginx + AList 打造Docker操作三板斧

    [Docker] Portainer + nginx + AList 打造Docker操作三板斧

    Portainer : Docker容器圖形化管理系統(tǒng) nginx: 反向代理利器 AList: 文件管理系統(tǒng) 目的: 依托Portainer 的圖形管理界面,可視化的配置docker容器. AList再關(guān)聯(lián)Docker各容器內(nèi)部的配置文件,可視化配置,再配合Portainer重啟,日志查看,命令行操作等.對于中小企業(yè)對容器化操作簡化處理.nginx用于打

    2024年02月11日
    瀏覽(19)
  • Linux關(guān)于gittee的遠(yuǎn)端倉庫的連接和git三板斧

    Linux關(guān)于gittee的遠(yuǎn)端倉庫的連接和git三板斧

    目錄 1.網(wǎng)頁操作 2.Linux操作 查看Linux系統(tǒng)中是否安裝git指令 安裝git指令 鏈接遠(yuǎn)端倉庫 設(shè)置 .gitignore文件 3.git三板斧? 首先我們要在gittee建立一個倉庫 這是我自己的勾選方案,大家可以參考一下。 這個方案勾選最下面的三個選項(xiàng)才有,不過都能找到這個HTTP協(xié)議地址,復(fù)制一下

    2024年02月07日
    瀏覽(14)
  • Linux項(xiàng)目自動化構(gòu)建工具-make/Makefile以及git三板斧

    Linux項(xiàng)目自動化構(gòu)建工具-make/Makefile以及git三板斧

    是否會寫make/makefile,從側(cè)面反映了一個程序員是否具備完成大型工程的能力。一個工程中的源文件不計數(shù),其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更

    2024年02月16日
    瀏覽(27)
  • 【看表情包學(xué)Linux】緩沖區(qū)的概念 | Git 三板斧 | 實(shí)現(xiàn)簡易進(jìn)度條

    【看表情包學(xué)Linux】緩沖區(qū)的概念 | Git 三板斧 | 實(shí)現(xiàn)簡易進(jìn)度條

    ?? 爆笑教程,只送有緣人 ????《看表情包學(xué)Linux》 ?? 寫在前面: 本章我們先對緩沖區(qū)的概念進(jìn)行一個詳細(xì)的探究,之后會帶著大家一步步去編寫一個簡陋的?\\\"進(jìn)度條\\\" 小程序,過程還是挺有意思的,雖然實(shí)現(xiàn)的過程表現(xiàn)得非常沙雕,但它是本 Linux 專欄中第一個小程序。

    2024年02月02日
    瀏覽(18)
  • git commit之前,沒有pull最新代碼,導(dǎo)致無法push代碼如何解決?——git三板斧

    git commit之前,沒有pull最新代碼,導(dǎo)致無法push代碼如何解決?——git三板斧

    如果在 git commit 之前沒有 pull 最新代碼,再進(jìn)行 push 操作可能會出現(xiàn)沖突,導(dǎo)致無法 push 代碼。此時, git 會提示類似以下的錯誤信息: 這個錯誤提示說明了更新被拒絕,因?yàn)檫h(yuǎn)程倉庫包含了本地倉庫沒有的工作。這通常是由于其他人已經(jīng)推送了代碼,或者你在另一個地方進(jìn)

    2024年02月13日
    瀏覽(437)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包