Istio中关于CircuitBreaker(断路器)的定义在DestiantionRule中,
关于Istio中CircuitBreaker官方文档如下:
https://istio.io/docs/tasks/traffic-management/circuit-breaking/
https://istio.io/docs/reference/config/networking/v1alpha3/destination-rule/
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/circuit_breaking
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/outlier
首先介绍下对CircuitBreaker(断路器 OR 熔断)的理解,CircuitBreaker来自于电路中保险装置,就是我们常说的保险丝,当电流大小超过一定阈值,电路保险丝就会熔断,切断电流以防止电流过大对电路以及用电设备造成损害。而在微服务中熔断就可以类比上面电路保险丝的描述,如果在一定时间内服务累计发生错误的次数操作了预先定义的阈值,就会将该错误的服务从负载均衡池中移除,当超过一段时间后,又会将服务再移回到服务负载均衡池。在互联网系统中,服务提供方(upstream)因访问压力过大而响应变慢或失败,服务调用方(downstream)为了保护系统整体的可用性,可以暂时切断对服务提供方的调用,这种牺牲局部,保全整体的措施就叫做熔断。
在Istio中,关于CircuitBreaker在DestinationRule->TrafficPolicy中提供了2个方面的配置:
(1)connectionPool(连接池(TCP | HTTP)配置,例如:连接数、并发请求等)
(2)outlierDetection(异常检测配置,传统意义上的熔断配置,即对规定时间内服务错误数的监测)
官方说明如下:
Traffic policies to apply for a specific destination, across all destination ports. See DestinationRule for examples.
Field | Type | Description |
---|---|---|
connectionPool |
ConnectionPoolSettings |
Settings controlling the volume of connections to an upstream service |
outlierDetection |
OutlierDetection |
Settings controlling eviction of unhealthy hosts from the load balancing pool |
关于connectionPool的配置与测试,可参照官方文档:
https://istio.io/docs/tasks/traffic-management/circuit-breaking/
关于outlierDetection官网上并没有找到具体实例,所以自己在实践的过程中也遇到了很多问题,
主要问题说明如下:
(1)在Istio中关于Http错误的定义为:502 - BadGateway, 503 - ServiceUnavailable, 504 - GatewayTimeout,起初在构建测试Docker 镜像的时候仅返回500 - Internal Server Error导致一直没有触发熔断;在Github Istio社区中也有很多相关Issue,很多用户(包括我)希望支持500 - Internal Server Error(Envoy底层本就支持5xx),Istio社区成员给出他们如此设计的原因:502-504更通用(外部服务通常返回503以告知调用者卸载服务)、同时支持TCP和HTTP、异常检测更关注的是服务过载(overload)而500不是服务过载的标识(内部错误,可由程序自己避免),并提出会在日后版本中支持自定义Http错误码,具体可参见:https://github.com/istio/api/issues/909
(2)PanicThreshold(minHealthPercent,默认50%),在envoy中存在panic threshold的定义,即存在惊慌模式,在服务的负载均衡池中,健康的服务实例(host)的百分比小于panic threshold时,则evnoy(istio sidecar -> istio-proxy)将会忽略服务的健康状态并将流量路由到全部的服务实例(满足惊慌模式则异常检测不生效)。在Istio中1.0版本是不支持对panic threshold的修改(默认50%),而在1.1版本中支持了对该阈值的配置,通过destinationRule->trafficPolicy->outerDetection->minHealthPercent进行修改。起初在进行outlierDetection测试时,启动了2个服务副本,并且两个服务都返回503,若2个服务均返回503,则不健康的实例百分比100%, 即健康的实例百分比0%<50%(默认的panic threshold),则服务负载均衡池直接进入惊慌模式,导致异常检测失效(没有错误服务实例被从服务负载均衡池中移除)。
(3)关于DestinationRule中的trafficPolicy(connectionPool, outlierDetection)均是对应到具体subset(每个subset可继承全局的trafficPolicy配置,亦可自定义单独的配置),并且各自subset独自进行统计(该处还需继续探索,实际测试过程中有时配置生效逻辑有些混乱);
实际测试用例说明:
方案一(未生效):
subset-v1中包括2个实例:subset-v1(pod-v1-1, pod-v1-2),且所有实例均返回503;
destinationRule配置如下:
baseEjectionTime: 10m(基本驱逐时间10分钟,实际驱逐时间为baseEjectionTime*驱逐次数)
consecutiveErrors: 1(连续错误数1,即连续返回502-504状态码的Http请求错误数)
interval: 1s(错误异常的扫描间隔1s,即在interval(1s)内连续发生consecutiveErrors(1)个错误,则触发服务熔断)
maxEjectionPercent: 50(最大驱逐百分比50%)
minHealthPercent: 50(最小健康服务百分比50%(panic threshold),通常minHealthPercent+maxEjectionPercent <= 100%)
kind: DestinationRule
apiVersion: networking.istio.io/v1alpha3
metadata:
name: luohq-springboot
namespace: cq
spec:
host: luohq-springboot.cq.svc.cluster.local
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 1024
http2MaxRequests: 1024
outlierDetection:
baseEjectionTime: 10m
consecutiveErrors: 1
interval: 1s
maxEjectionPercent: 50
minHealthPercent: 50
subsets:
- labels:
version: v1
name: v1
上述配置没有问题,但是由于两个服务实例pod-v1-1, pod-v1-2都返回503(不健康),
健康实例百分比:
0/(pod-v1-1 + pod-v1-2) = 0/2 = 0% < minHealthPercent=50%,
不健康实例百分比:
(pod-v1-1 + pod-v1-2)/(pod-v1-1 + pod-v1-2) = 2/2 = 100%>= maxEjectionPercent=50%,
则健康的实例百分比0%<50%(minHealthPercent),则服务负载均衡池直接进入惊慌模式,导致异常检测失效(没有错误服务实例被从服务负载均衡池中移除),实际观察到的现象就是2个服务实例继续提供服务(继续接收请求并打印日志)。
方案2(生效):
实验中应使用3个实例,subset-v1(pod-v1-1, pod-v1-2), subset-v2(pod-v2-1),且健康实例:pod-v1-2, pod-v2-1, 不健康实例(返回503):pod-v1-1;
destinationRule配置如下:
(outlierDetection配置与方案1相同,仅增加了subset-v2的定义,理论上可以仅定义subset-v1实现同样效果)
kind: DestinationRule
apiVersion: networking.istio.io/v1alpha3
metadata:
name: luohq-springboot
namespace: cq
spec:
host: luohq-springboot.cq.svc.cluster.local
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 1024
http2MaxRequests: 1024
outlierDetection:
baseEjectionTime: 10m
consecutiveErrors: 1
interval: 1s
maxEjectionPercent: 50
minHealthPercent: 50
subsets:
- labels:
version: v1
name: v1
- labels:
version: v2
name: v2
上述配置在实际测试中生效,subset-v1中pod-v1-2、subset-v2中pod-v2-1返回200(健康),subset-v1中pod-v1-1返回503(不健康),
subset-v1健康实例百分比:
pod-v1-2/(pod-v1-1 + pod-v1-2) = 1/2 = 50% >= minHealthPercent=50%,
subset-v1不健康实例百分比:
pod-v1-1/(pod-v1-1 + pod-v1-2) = 1/2 = 50% <= maxEjectionPercent=50%,
则subset-v1中健康的实例百分比50%>=50%(minHealthPercent)且不健康的实例百分比50%<=50%(maxEjectionPercent),则服务熔断触发,异常检测生效,pod-v1-1(返回503)服务实例被从服务负载均衡池中移除,实际观察到的现象就是subset-v1中pod-v1-2继续提供服务(继续接收请求并打印日志)而pod-v1-1在接受1-2个请求之后便不再接收请求(不在打印日志),而subset-v2中pod-v2-1未受到影响,继续提供服务(继续接收请求并打印日志)。
以上是对Istio中CircuitBreaker学习的简单总结,以后需再接再励!