背景
过载
在分布式系统中,某个服务可能因为流量过多,导致请求处理不过来,最后服务崩溃,甚至引起依赖它的服务也一直等不到返回,导致连锁反应一起崩溃,这种情况被称为雪崩。
限流
很容易就想到需要对单个服务进行限流,常见的限流方式有
-
令牌桶算法 / 漏桶算法
优点是实现简单,缺点是难以设置合理的限流阈值。
-
自适应限流
根据服务器的状态来进行流量控制。
熔断
限流的策略又包括:
-
降级
提供有损服务。
-
熔断
快速拒绝请求。429.
Hystrix(豪猪)
Hystrix 是由 Netflex 开发的一款开源组件,提供了基础的熔断功能, 本身是用 java 写的。
而 hystrix-go 是基于hystrix 的 go 实现。
如何使用
import github.com/afex/hystrix-go/hystrix
// 1.配置config
configA := hystrix.CommandConfig{
Timeout: int(3 * time.Second),
MaxConcurrentRequests: 10,
SleepWindow: 5000,
RequestVolumeThreshold: 10,
ErrorPercentThreshold: 30,
}
// 2.配置command
hystrix.ConfigureCommand("visitBaidu", configA)
// 3.执行Do方法
var prodRes *models.ProdListResponse
err := hystrix.Do("visitBaidu", func() error {
_, err := http.Get("https://www.baidu.com/")
return err
}, func(e error) error {
fmt.Printf("handle error:%v\n", err)
return nil
})
Do方法:
Do 函数需要三个参数,
- 第一个参数 commmand 名称,你可以把每个名称当成一个独立当服务
- 第二个参数是处理正常的逻辑,比如 http 调用服务,返回参数是 err。
- 如果处理失败,那么就执行第三个参数逻辑, 我们称为保底操作。由于服务错误率过高导致熔断器开启,那么之后的请求也直接回调此函数
配置含义:
- Timeout 执行 command 的超时时间。
- MaxConcurrentRequests command 的最大并发量
- SleepWindow 当熔断器被打开后,SleepWindow 的时间就是控制过多久后去尝试服务是否可用了。
- RequestVolumeThreshold 一个统计窗口10秒内请求数量。达到这个请求数量后才去判断是否要开启熔断
- ErrorPercentThreshold:错误百分比,请求数量大于等于RequestVolumeThreshold并且错误率到达这个百分比后就会启动熔断
实现原理
设计模式
-
命令模式 command
将所有请求外部系统(或者叫依赖服务)的逻辑封装到 hystrix.Go 和 hystrix.Do 方法里
-
观察者模式
- Hystrix 通过观察者模式对服务进行状态监听
- 每个任务都包含有一个对应的 metricExchange,所有MetricCollector都由 Registry 来进行维护
- 在任务的不同阶段会往Metrics中写入不同的信息,Metrics会对统计到的历史信息进行统计汇总,供熔断器以及Dashboard监控时使用
具体实现
隔离
用 executorPool 来隔离不同 command 对应的操作
统计
使用滑动窗口 rolling 来统计数据。
流量控制
令牌算法
代码
大致过了一遍,
├─hystrix
│ │ circuit.go // CircuitBreaker 熔断器
│ │ circuit_test.go
│ │ doc.go
│ │ eventstream.go // StreamHandler 将每个请求的 metrics 发给 http 仪表盘
│ │ eventstream_test.go
│ │ hystrix.go // API入口,提供 Go, Do 方法给用户调用
│ │ hystrix_test.go
│ │ logger.go // logger 日志的抽象, 默认未实现
│ │ metrics.go // metricExchange 系统的执行情况
│ │ metrics_test.go
│ │ pool.go // executorPool command 对应的执行池
│ │ pool_metrics.go // poolMetrics 执行池的统计新信息
│ │ pool_test.go
│ │ settings.go // Settings command 的配置
│ │ settings_test.go
│ │
│ ├─metric_collector // Registry MetricCollector 收集器
│ │ default_metric_collector.go
│ │ metric_collector.go
│ │
│ └─rolling // Number, Timing滑动窗口
│ rolling.go
│ rolling_test.go
│ rolling_timing.go
│ rolling_timing_test.go
│
├─loadtest
│ │ README.md
│ │
│ └─service
│ main.go
│
├─plugins
│ datadog_collector.go
│ graphite_aggregator.go
│ statsd_collector.go
│ statsd_collector_test.go
│
└─scripts
vagrant.sh
主要看了一下 rolling 和 metric_collector。
具体分析可以参考大佬的文章: hystrix-go 源码分析,讲的非常详细。