golang高效实现断路器模式的插件库circuit的使用
Golang高效实现断路器模式的插件库circuit的使用
Circuit是一个高效的、功能完整的Golang断路器模式实现,类似于Netflix的Hystrix。下面我将介绍如何使用这个库。
主要特性
- 无需强制使用goroutines
- 可恢复的panic()
- 与context.Context集成
- 全面的指标跟踪
- 高效的实现和基准测试
- 低/零内存分配成本
- 支持Netflix Hystrix仪表板
- 多种错误处理功能
- 通过expvar公开电路健康和配置
- SLO跟踪
- 可自定义的状态转换逻辑
- 实时配置更改
- 丰富的测试和示例
基本使用示例
1. 创建简单电路
// 管理所有电路
h := circuit.Manager{}
// 创建具有唯一名称的电路
c := h.MustCreateCircuit("hello-world")
// 调用电路
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
return nil
}, nil)
fmt.Println("Result of execution:", errResult)
// Output: Result of execution: <nil>
2. 使用回退逻辑
// 可以不使用管理器创建电路
c := circuit.NewCircuitFromConfig("hello-world-fallback", circuit.Config{})
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
return errors.New("this will fail")
}, func(ctx context.Context, err error) error {
fmt.Println("Circuit failed with error, but fallback returns nil")
return nil
})
fmt.Println("Execution result:", errResult)
// Output: Circuit failed with error, but fallback returns nil
// Execution result: <nil>
3. 在goroutine中运行
h := circuit.Manager{}
c := h.MustCreateCircuit("untrusting-circuit", circuit.Config{
Execution: circuit.ExecutionConfig{
// 在几毫秒后超时
Timeout: time.Millisecond * 30,
},
})
errResult := c.Go(context.Background(), func(ctx context.Context) error {
// 睡眠30秒,远超过我们的超时时间
time.Sleep(time.Second * 30)
return nil
}, nil)
fmt.Printf("err=%v", errResult)
// Output: err=context deadline exceeded
Hystrix配置示例
configuration := hystrix.Factory{
// Hystrix打开逻辑是在错误百分比后打开电路
ConfigureOpener: hystrix.ConfigureOpener{
// 我们改为等待10个请求,而不是20个,然后检查关闭
RequestVolumeThreshold: 10,
// 默认值匹配hystrix的默认值
},
// Hystrix关闭逻辑是先睡眠然后检查
ConfigureCloser: hystrix.ConfigureCloser{
// 默认值匹配hystrix的默认值
},
}
h := circuit.Manager{
// 告诉管理器在创建新电路时使用此配置工厂
DefaultCircuitProperties: []circuit.CommandPropertiesConstructor{configuration.Configure},
}
// 此电路将从示例继承配置
c := h.MustCreateCircuit("hystrix-circuit")
fmt.Println("This is a hystrix configured circuit", c.Name())
// Output: This is a hystrix configured circuit hystrix-circuit
启用仪表板指标
// metriceventstream使用滚动统计报告电路信息
sf := rolling.StatFactory{}
h := circuit.Manager{
DefaultCircuitProperties: []circuit.CommandPropertiesConstructor{sf.CreateConfig},
}
es := metriceventstream.MetricEventStream{
Manager: &h,
}
go func() {
if err := es.Start(); err != nil {
log.Fatal(err)
}
}()
// ES是一个http.Handler,所以可以直接传递给你的mux
http.Handle("/hystrix.stream", &es)
// ...
if err := es.Close(); err != nil {
log.Fatal(err)
}
// Output:
运行时配置更改
// 从默认值开始
configuration := hystrix.ConfigFactory{}
h := circuit.Manager{
// 告诉管理器在创建新电路时使用此配置工厂
DefaultCircuitProperties: []circuit.CommandPropertiesConstructor{configuration.Configure},
}
c := h.MustCreateCircuit("hystrix-circuit")
fmt.Println("The default sleep window", c.OpenToClose.(*hystrix.Closer).Config().SleepWindow)
// 此配置更新函数是线程安全的。我们可以在电路活动时在运行时修改此配置
c.OpenToClose.(*hystrix.Closer).SetConfigThreadSafe(hystrix.ConfigureCloser{
SleepWindow: time.Second * 3,
})
fmt.Println("The new sleep window", c.OpenToClose.(*hystrix.Closer).Config().SleepWindow)
// Output:
// The default sleep window 5s
// The new sleep window 3s
不将用户错误计为故障
c := circuit.NewCircuitFromConfig("divider", circuit.Config{})
divideInCircuit := func(numerator, denominator int) (int, error) {
var result int
err := c.Run(context.Background(), func(ctx context.Context) error {
if denominator == 0 {
// 此错误类型不计为电路故障
return &circuit.SimpleBadRequest{
Err: errors.New("someone tried to divide by zero"),
}
}
result = numerator / denominator
return nil
})
return result, err
}
_, err := divideInCircuit(10, 0)
fmt.Println("Result of 10/0 is", err)
// Output: Result of 10/0 is someone tried to divide by zero
性能基准
这个实现在每种配置下都比go-hystrix更高效。与其他实现相比,在高并发运行时对大多数情况来说更快。
仅限高并发通过电路(常见情况)的基准:
BenchmarkCiruits/cep21-circuit/Minimal/passing/75-8 20000000 87.7 ns/op 0 B/op 0 allocs/op
BenchmarkCiruits/GoHystrix/DefaultConfig/passing/75-8 500000 2498 ns/op 990 B/op 20 allocs/op
BenchmarkCiruits/rubyist/Threshold-10/passing/75-8 2000000 849 ns/op 309 B/op 4 allocs/op
BenchmarkCiruits/gobreaker/Default/passing/75-8 2000000 698 ns/op 0 B/op 0 allocs/op
BenchmarkCiruits/handy/Default/passing/75-8 1000000 1795 ns/op 0 B/op 0 allocs/op
BenchmarkCiruits/iand_circuit/Default/passing/75-8 5000000 349 ns/op 0 B/op 0 allocs/op
开发
确保你的测试通过go test
并且你的lint通过golangci-lint run
。
示例
你可以在/example目录中运行一组示例电路
go run example/main.go
输出看起来像这样:
go run example/main.go
2017/12/19 15:24:42 Serving on socket :8123
2017/12/19 15:24:42 To view the stream, execute:
2017/12/19 15:24:42 curl http://localhost:8123/hystrix.stream
2017/12/19 15:24:42
2017/12/19 15:24:42 To view expvar metrics, visit expvar in your browser
2017/12/19 15:24:42 http://localhost:8123/debug/vars
2017/12/19 15:24:42
2017/12/19 15:24:42 To view a dashboard, follow the instructions at https://github.com/Netflix/Hystrix/wiki/Dashboard#run-via-gradle
2017/12/19 15:24:42 git clone git@github.com:Netflix/Hystrix.git
2017/12/19 15:24:42 cd Hystrix/hystrix-dashboard
2017/12/19 15:24:42 ../gradlew jettyRun
2017/12/19 15:24:42
2017/12/19 15:24:42 Then, add the stream http://localhost:8123/hystrix.stream
如果你加载Hystrix仪表板(按照上面的说明),你应该能看到所有示例电路的指标。
更多关于golang高效实现断路器模式的插件库circuit的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高效实现断路器模式的插件库circuit的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang断路器模式实现:circuit库使用指南
断路器模式(Circuit Breaker)是分布式系统中提高稳定性的重要模式,circuit是一个高效的Golang断路器实现库。下面我将详细介绍其使用方法。
circuit库简介
circuit是一个轻量级但功能强大的断路器实现,具有以下特点:
- 基于时间窗口的错误率统计
- 可配置的阈值和超时
- 支持半开状态
- 低开销
安装
go get github.com/cep21/circuit
基本使用
1. 创建断路器
import (
"github.com/cep21/circuit"
"github.com/cep21/circuit/closers/hystrix"
"time"
)
func createCircuit() *circuit.Circuit {
hystrixConfig := hystrix.Factory{
// 当错误率超过50%时触发断路器
ErrorPercentThreshold: 50,
// 10秒统计窗口
WindowLength: time.Second * 10,
// 最小请求数阈值,10秒内至少5个请求才统计
NumBuckets: 10,
// 断路器开启后5秒后进入半开状态
SleepWindow: time.Second * 5,
// 半开状态最大允许请求数
MaxConcurrentRequests: 100,
}
return circuit.NewCircuitFromConfig("my-service", circuit.Config{
General: circuit.GeneralConfig{
OpenToClosedFactory: hystrixConfig.ConfigureOpener,
ClosedToOpenFactory: hystrixConfig.ConfigureCloser,
},
})
}
2. 使用断路器保护函数调用
func protectedCall(c *circuit.Circuit) (interface{}, error) {
return c.Execute(context.Background(), func(ctx context.Context) (interface{}, error) {
// 这里是被保护的业务逻辑
resp, err := http.Get("http://example.com/api")
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 处理响应...
return resp, nil
}, nil)
}
高级功能
自定义失败判断
c.Execute(context.Background(), func(ctx context.Context) (interface{}, error) {
resp, err := http.Get("http://example.com/api")
if err != nil {
return nil, circuit.SimpleBadRequest{Err: err}
}
if resp.StatusCode >= 500 {
// 服务端错误计入断路器统计
return nil, circuit.SimpleBadRequest{Err: fmt.Errorf("server error: %d", resp.StatusCode)}
}
// 4xx错误不计入断路器统计
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
return nil, nil
}
return resp, nil
}, nil)
配置熔断器行为
circuit.NewCircuitFromConfig("custom-circuit", circuit.Config{
Execution: circuit.ExecutionConfig{
// 超时设置
Timeout: time.Second * 2,
// 最大并发请求数
MaxConcurrentRequests: 100,
},
Fallback: circuit.FallbackConfig{
// 熔断时执行的降级函数
Config: circuit.FallbackFunc(func(ctx context.Context, err error) error {
log.Printf("Fallback triggered due to: %v", err)
return nil
}),
},
})
监控和指标
// 注册指标收集器
c := circuit.NewCircuitFromConfig("monitored-circuit", circuit.Config{
Metrics: circuit.MetricsCollectors{
// Prometheus指标
&circuit.PrometheusCollector{},
// 自定义日志收集
circuit.MetricsCollectorFunc(func(r circuit.Metrics) {
log.Printf("Circuit state: %s, requests: %d, errors: %d",
r.State, r.Requests, r.Errors)
}),
},
})
最佳实践
- 合理设置阈值:根据服务特点调整错误率和最小请求数阈值
- 区分错误类型:客户端错误(4xx)通常不应触发熔断
- 设置适当的超时:避免过长的超时导致资源耗尽
- 实现降级逻辑:熔断时返回缓存数据或默认值
- 监控熔断器状态:及时发现和解决系统问题
完整示例
package main
import (
"context"
"fmt"
"github.com/cep21/circuit"
"github.com/cep21/circuit/closers/hystrix"
"log"
"net/http"
"time"
)
func main() {
// 创建断路器
circuitBreaker := createCircuit()
// 模拟连续调用
for i := 0; i < 20; i++ {
res, err := protectedCall(circuitBreaker)
if err != nil {
log.Printf("Call failed: %v", err)
continue
}
if res != nil {
log.Printf("Call succeeded: %v", res)
}
time.Sleep(500 * time.Millisecond)
}
}
func createCircuit() *circuit.Circuit {
hystrixConfig := hystrix.Factory{
ErrorPercentThreshold: 50,
WindowLength: time.Second * 10,
NumBuckets: 10,
SleepWindow: time.Second * 3,
MaxConcurrentRequests: 100,
}
return circuit.NewCircuitFromConfig("example-api", circuit.Config{
General: circuit.GeneralConfig{
OpenToClosedFactory: hystrixConfig.ConfigureOpener,
ClosedToOpenFactory: hystrixConfig.ConfigureCloser,
},
Execution: circuit.ExecutionConfig{
Timeout: time.Second * 1,
},
Fallback: circuit.FallbackConfig{
Config: circuit.FallbackFunc(func(ctx context.Context, err error) error {
log.Printf("Using fallback due to: %v", err)
return nil
}),
},
})
}
func protectedCall(c *circuit.Circuit) (interface{}, error) {
return c.Execute(context.Background(), func(ctx context.Context) (interface{}, error) {
// 模拟50%的失败率
if time.Now().UnixNano()%2 == 0 {
return nil, fmt.Errorf("simulated error")
}
return "success", nil
}, nil)
}
这个示例展示了circuit库的核心功能,你可以根据实际需求调整配置参数。断路器模式能有效防止故障扩散,是构建弹性分布式系统的重要组件。