您好,登錄后才能下訂單哦!
這篇文章主要講解了“Sentinel限流熔斷降級怎么使用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Sentinel限流熔斷降級怎么使用”吧!
什么是限流 \ 熔斷 \ 降級
限流:在我們的后天系統中,如果那一天突然進入大量流量,我們服務原本最高只能處理同時 2k 的請求,突然一
下就來來了 5k 的請求,這對服務器的壓力是不是很要命,這很可能直接導致服務器宕機,崩潰,導致原本 2K 的處
理量都不能處理了,這時候我們需要限流,限流的作用就是保持訪問量到達服務器最高的情況下,對多余的請求
不做處理,相比之下,比服務器直接掛掉是好很多的。例如在雙十一的時候,我們要下單就會看到類似” 請求繁
忙,請稍后重試!”。
熔斷: 相信大家對斷路器并不陌生,它就相當于一個開關,打開后可以阻止流量通過。比如保險絲,當電流過大
時,就會熔斷,從而避免元器件損壞。
服務熔斷是指調用方訪問服務時通過斷路器做代理進行訪問,斷路器會持續觀察服務返回的成功、失敗的狀態,
當失敗超過設置的閾值時斷路器打開,請求就不能真正地訪問到服務了。
使用場景
服務故障或者升級時,讓客戶端快速失敗
失敗處理邏輯容易定義
響應耗時較長,客戶端設置的 read timeout 會比較長,防止客戶端大量重試請求導致的連接、線程資源不能釋放
* 降級 *: 服務降級是從整個系統的負荷情況出發和考慮的,對某些負荷會比較高的情況,為了預防某些功能(業務
場景)出現負荷過載或者響應慢的情況,在其內部暫時舍棄對一些非核心的接口和數據的請求,而直接返回一個
提前準備好的 fallback(退路)錯誤處理信息。這樣,雖然提供的是一個有損的服務,但卻保證了整個系統的穩
定性和可用性。
什么是 Sentinel
Sentinel 是阿里開源的項目,提供了流量控制、熔斷降級、系統負載保護等多個維度來保障服務之間的穩定性。
官網:github.com/alibaba/Sentinel/wiki
2012 年,Sentinel 誕生于阿里巴巴,其主要目標是流量控制。2013-2017 年,Sentinel 迅速發展,并成為阿里巴巴所有微服務的基本組成部分。 它已在 6000 多個應用程序中使用,涵蓋了幾乎所有核心電子商務場景。2018 年,Sentinel 演變為一個開源項目。2020 年,Sentinel Golang 發布。
特點 :
豐富的應用場景 :Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即
突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
完備的實時監控 :Sentinel 同時提供實時的監控功能。您可以在控制臺中看到接入應用的單臺機
器秒級數據,甚至 500 臺以下規模的集群的匯總運行情況。
* 生態廣廣泛 *
Sentinel 的歷史
2012 年,Sentinel 誕生,主要功能為入口流量控制。
2013-2017 年,Sentinel 在阿里巴巴集團內部迅速發展,成為基礎技術模塊,覆蓋了所有的核心場景。Sentinel 也因此積累了大量的流量歸整場景以及生產實踐。
2018 年,Sentinel 開源,并持續演進。
2019 年,Sentinel 朝著多語言擴展的方向不斷探索,推出 C++ 原生版本,同時針對 Service Mesh 場景也推出了 Envoy 集群流量控制支持,以解決 Service Mesh 架構下多語言限流的問題。
2020 年,推出 Sentinel Go 版本,繼續朝著云原生方向演進。
2021 年,Sentinel 正在朝著 2.0 云原生高可用決策中心組件進行演進;同時推出了 Sentinel Rust 原生版本。同時我們也在 Rust 社區進行了 Envoy WASM extension 及 eBPF extension 等場景探索。
2022 年,Sentinel 品牌升級為流量治理,領域涵蓋流量路由 / 調度、流量染色、流控降級、過載保護 / 實例摘除等;同時社區將流量治理相關標準抽出到 OpenSergo 標準中,Sentinel 作為流量治理標準實現。
Sentinel-go 的安裝
官網文檔
安裝:go get github.com/alibaba/sentinel-golang/api
Go 限流實戰
qps 限流
package main
import (
"fmt"
"log"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/flow"
)
func main() {
//基于sentinel的qps限流
//必須初始化
err := sentinel.InitDefault()
if err != nil {
log.Fatalf("Unexpected error: %+v", err)
}
//配置限流規則:1秒內通過10次
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "some_test",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Reject, //超過直接拒絕
Threshold: 10, //請求次數
StatIntervalInMs: 1000, //允許時間內
},
})
if err != nil {
log.Fatalf("Unexpected error: %+v", err)
return
}
for i := 0; i < 12; i++ {
e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound))
if b != nil {
fmt.Println("限流了")
} else {
fmt.Println("檢查通過")
e.Exit()
}
}
}
打印結果:
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
限流了
限流了
Thrnotting
package main
import (
"fmt"
"log"
"time"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/flow"
)
func main() {
//基于sentinel的qps限流
//必須初始化
err := sentinel.InitDefault()
if err != nil {
log.Fatalf("Unexpected error: %+v", err)
}
//配置限流規則
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "some_test",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Throttling, //勻速通過
Threshold: 10, //請求次數
StatIntervalInMs: 1000, //允許時間內
},
})
if err != nil {
log.Fatalf("Unexpected error: %+v", err)
return
}
for i := 0; i < 12; i++ {
e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound))
if b != nil {
fmt.Println("限流了")
} else {
fmt.Println("檢查通過")
e.Exit()
}
time.Sleep(time.Millisecond * 100)
}
}
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
檢查通過
Warrm_up
package main
import (
"fmt"
"log"
"math/rand"
"time"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/flow"
)
func main() {
//先初始化sentinel
err := sentinel.InitDefault()
if err != nil {
log.Fatalf("初始化sentinel 異常: %v", err)
}
var globalTotal int
var passTotal int
var blockTotal int
ch := make(chan struct{})
//配置限流規則
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "some-test",
TokenCalculateStrategy: flow.WarmUp, //冷啟動策略
ControlBehavior: flow.Reject, //直接拒絕
Threshold: 1000,
WarmUpPeriodSec: 30,
},
})
if err != nil {
log.Fatalf("加載規則失敗: %v", err)
}
//我會在每一秒統計一次,這一秒只能 你通過了多少,總共有多少, block了多少, 每一秒會產生很多的block
for i := 0; i < 100; i++ {
go func() {
for {
globalTotal++
e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
if b != nil {
//fmt.Println("限流了")
blockTotal++
time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
} else {
passTotal++
time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
e.Exit()
}
}
}()
}
go func() {
var oldTotal int //過去1s總共有多少個
var oldPass int //過去1s總共pass多少個
var oldBlock int //過去1s總共block多少個
for {
oneSecondTotal := globalTotal - oldTotal
oldTotal = globalTotal
oneSecondPass := passTotal - oldPass
oldPass = passTotal
oneSecondBlock := blockTotal - oldBlock
oldBlock = blockTotal
time.Sleep(time.Second)
fmt.Printf("total:%d, pass:%d, block:%d\n", oneSecondTotal, oneSecondPass, oneSecondBlock)
}
}()
<-ch
}
打印結果:逐漸到達 1k, 在 1k 位置上下波動
total:11, pass:9, block:0
total:21966, pass:488, block:21420
total:21793, pass:339, block:21414
total:21699, pass:390, block:21255
total:21104, pass:393, block:20654
total:21363, pass:453, block:20831
total:21619, pass:491, block:21052
total:21986, pass:533, block:21415
total:21789, pass:594, block:21123
total:21561, pass:685, block:20820
total:21663, pass:873, block:20717
total:20904, pass:988, block:19831
total:21500, pass:996, block:20423
total:21769, pass:1014, block:20682
total:20893, pass:1019, block:19837
total:21561, pass:973, block:20524
total:21601, pass:1014, block:20517
total:21475, pass:993, block:20420
total:21457, pass:983, block:20418
total:21397, pass:1024, block:20320
total:21690, pass:996, block:20641
total:21526, pass:991, block:20457
total:21779, pass:1036, block:20677
Go 熔斷實戰
這里我們介紹一個錯誤數量的,查看詳細熔斷機制
error_count
package main
import (
"errors"
"fmt"
"log"
"math/rand"
"time"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/circuitbreaker"
"github.com/alibaba/sentinel-golang/core/config"
"github.com/alibaba/sentinel-golang/logging"
"github.com/alibaba/sentinel-golang/util"
)
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() {
//基于連接數的降級模式
total := 0
totalPass := 0
totalBlock := 0
totalErr := 0
conf := config.NewDefaultConfig()
// for testing, logging output to console
conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
err := sentinel.InitWithConfig(conf)
if err != nil {
log.Fatal(err)
}
ch := make(chan struct{})
// Register a state change listener so that we could observer the state change of the internal circuit breaker.
circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
_, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
// Statistic time span=10s, recoveryTimeout=3s, maxErrorCount=50
{
Resource: "abc",
Strategy: circuitbreaker.ErrorCount,
RetryTimeoutMs: 3000, //3s只有嘗試回復
MinRequestAmount: 10, //靜默數
StatIntervalMs: 5000,
Threshold: 50,
},
})
if err != nil {
log.Fatal(err)
}
logging.Info("[CircuitBreaker ErrorCount] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.")
go func() {
for {
total++
e, b := sentinel.Entry("abc")
if b != nil {
// g1 blocked
totalBlock++
fmt.Println("協程熔斷了")
time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
} else {
totalPass++
if rand.Uint64()%20 > 9 {
totalErr++
// Record current invocation as error.
sentinel.TraceError(e, errors.New("biz error"))
}
// g1 passed
time.Sleep(time.Duration(rand.Uint64()%20+10) * time.Millisecond)
e.Exit()
}
}
}()
go func() {
for {
total++
e, b := sentinel.Entry("abc")
if b != nil {
// g2 blocked
totalBlock++
time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
} else {
// g2 passed
totalPass++
time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond)
e.Exit()
}
}
}()
go func() {
for {
time.Sleep(time.Second)
fmt.Println(totalErr)
}
}()
<-ch
}
感謝各位的閱讀,以上就是“Sentinel限流熔斷降級怎么使用”的內容了,經過本文的學習后,相信大家對Sentinel限流熔斷降級怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。