Istio - CricuitBreaker - OutlierDetection

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(异常检测配置,传统意义上的熔断配置,即对规定时间内服务错误数的监测)

官方说明如下:

TrafficPolicy

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学习的简单总结,以后需再接再励!

 

你可能感兴趣的:(istio)