微服务实践:服务治理
微服务实践:服务治理
在微服务的演进过程中,为了最大化利用微服务的优势,保障系统的高可用性,需要通过一些类的服务支撑组件来协助服务间有效的协作,这便是服务治理的范畴。
注册发现
为什么需要服务注册发现
在微服务系统中,服务的消费者需要知道服务提供者的网络地址,才能与之通信。比较简单的实现方式是直接在消费者端或者负载均衡器上进行注册,在发生变化时手动更新。随着服务数量的增多,这种方式会面领如下挑战:
- 手动注册实例地址的成本高
- 无法识别服务重启后的网络地址的变化
服务注册发现——客户端发现
当服务发现的逻辑位于服务消费者端时,称为客户端发现。服务发现简单来说,服务注册发现的过程(客户端发现),共分为以下3个步骤:
1、 服务提供者将实例信息注册到注册中心。
2、服务调用者根据服务标识,从注册中心查询服务,获取包含网络地址的服务实例列表。
3、与服务实现通信。
客户端发现的缺点是实现起来较为复杂,因为在各个服务消费者中需要完成以下功能:首先需要维护服务提供者的列表,并且需要不断与注册中心同步以获取服务最新信息;其次,如果服务部署多实例,服务消费者需要实现路由逻辑,即实现负载均衡器。
服务注册发现——服务端发现
1、 服务提供者实例向注册中心注册地址信息。
2、调用者向服务发送请求,请求被送到负载均衡器。
3、负载均衡器从服务注册中心查找服务体用这注册的信息。
4、负载均衡器将请求转发给具体的服务提供者实例。
服务端发现的好处是服务消费者的实现复杂度会降低。服务消费者只需要发送请求,不需要关心如何与注册中心交互。缺点是由于多个请求多了一次网络跳转,整体性能会有所损失,需要保证它的高可用性。
负载均衡
什么是负载均衡
为了提高可用性、降低延迟,同一个服务可能会部署多个实例,负载均衡就是为了在服务的多个实例之间进行分配负载,已达到优化资源使用、最大化吞吐率,同时避免过载。
服务端负载均衡
优点是负载均衡对于服务消费者来说是透明的,服务消费者完全感知不到负载均衡的存在,也不需要关心具体被转发至哪个实例。但是当服务数量或调用了增大时,一旦负载均衡器发生故障就导致整个系统不可用。常见的复杂均衡器有如下:
还有一些商用的负载均衡器,如F5、NetScaler、Array、AWD的ELB、华为云的ELB等。
客户端负载均衡
将负载均衡的功能以库的形式集成到服务消费中。服务消费者需要访问某服务时,需要通过内置的负载均衡组件向服务注册中心查询,得到可用的服务提供者列表,然后按照某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。
服务端负载均衡将负载均衡能力实现在服务内部,因此服务消费者与提供者之间是直接调动,没有额外开销,性能较好。目前客户端负载均衡在很多开源框架中都有实现,如Spring Cloud、Dubbo、ServiceComb等。
负载均衡策略
- 随机策略
- 轮询策略
- 权重策略
- 响应事件策略
配置管理
服务在运行过程中,需要和其他服务协作,同时他也会依赖基础设施或其他服务完成某项业务功能。在这个过程中,就需要多样化的配置信息。
- 基础设施的连接信息
- 协作服务的地址信息
- 业务行为的配置参数
- 与特性相关的信息
源码中硬编码配置信息,虽然实现成本低,但是这种方式不仅缺乏灵活性,而且容易造成信息泄露。因此,较好的方式是将配置与代码分离。采用独立于代码的外部机制存储配置信息。
微服务的配置管理策略
下图为集中化的配置管理示意图:
其配置变更流程如下:
多实例的配置信息变更
对于服务多实例的场景,可以引入轻量级的消息代理,通过广播事件或者消息的方式通知各个实例更新配置。
容错机制
生产环境中的每个微服务并不是具有百分百的可靠性。一方面,线性系统的可靠性等于其所包含的每个组件的可靠性之乘积,而各个微服务之间存在错综复杂的关系,让它比线性系统更复杂。另一方面,服务之间跨网络调用,增加了调用失败的可能性。因此,如何保证微服务系统的可靠性,也变得更为复杂和困难。所以,微服务系统在设计之初就需要考虑容错机制,当系统负载过高时,可以确保核心业务不被破坏,以及当某个服务出错时,把影响范围降低到最小,避免整个系统不可用。下面介绍一下常见的容错模式。
限流
服务的流量可能是动态的,如果流量增加,超过服务承载范围,就会影响用户掩。通过限制服务能使用的资源,当监控到流量超过设定的阈值时,服务拒绝处理新的用户请求。当系统压力过大时,对系统的非核心业务进行限流,避免因压力过大导致整个系统奔溃。
超时和重试
超时时指当前消费者依赖的服务出现响应延迟时,消费者不用无限等待,而是根据事先设计的超时时间中断调用,及时释放Web容器、数据库等的连接资源。重试通常与超时结合起来,当出现超时时重新发起调用,常用于因网络抖动等导致服务调用出现超时的场景。
服务雪崩现象如下:
服务提供者不可用——>重试加大流量——>服务消费者不可用
对于服务提供者来说,可通过自动扩容和限流来应对。对于服务消费者来说需要引入服务降级来避免服务雪崩,具体措施包括隔离、熔断和回退。
服务隔离
微服务架构下系统会包含多个服务,每个服务拥有一个或多个消费者,服务负载过多或故障将影响所有消费者。消费者可以同时向多个服务发送请求,每个请求都消耗资源。当消费者向错误配置或未响应的服务发送请求时,客户端请求使用的资源可能无法及时释放,继续对服务请求会耗尽资源,如耗尽客户端的连接池,导致消费者对其他服务的请求也受到影响,进而不能再向其他服务发送请求。
在软件行业中,可以考虑通过资源隔离来防止有限的资源被耗尽:
服务A依赖于服务B、C、D,假设运行服务A的容器有120个线程,当服务B不可用时,服务A重试或外部流量增加,服务A的120个线程会因为服务B的不可用而耗尽。
如果采用线程隔离的机制,对于服务B、C、D的调用使用不同的连接池,每个服务各分配40个线程。当服务B不可用时,为服务B分配的线程会被耗尽,而为服务C、D分配的80个线程不受影响,服务A仍然可用。
使用隔离机制的好处在于:
- 防止引发服务级联故障
- 在发生服务故障的时保留一些功能,系统的其他服务和功能将继续运行。
熔断和回退
当电路发生短路时,断路器能够主动熔断电路,以避免灾难发生。借用断路器的原理,引入熔断机制,在服务出现非临时性的故障时,先通过回退机制(直接返回错误、返回空值/缺省值、返回缓存/备份数据)防止重复尝试执行可能失败的操作,同时检测故障是否持续,是否已解决。如果问题已经修复,则重新发起请求。
熔断机制可以通过「代理 → 断路器」统计最近发生的故障数,来决定是否继续操作或者返回异常。如图 3-40 所示,断路器的状态包括关闭状态、打开状态和半开状态。
● 关闭状态:在默认情况下,断路器处于关闭状态,如果调用持续出错,失败计数器在给定时间段内超过了阈值,断路器进入打开状态。
● 打开状态:在指定时间段内,不再向服务提供者发送请求,而是直接回退到失败的结果,此时断路器进入打开状态,并且启动超时计时器。
● 半开状态:计时器超时后,断路器进入半开状态,即允许发送少量请求进行尝试,并且通过成功计数器计算成功的请求数。如果调用仍然失败,则返回到打开状态,如果成功计数器超过阈值,则断路器回到关闭状态。
熔断机制提供稳定性,让服务从故障中恢复,并最大限度地减少性能的影响。这种机制可定制性较强,可以根据故障类型进行调整。例如,可以将超时计时器的超时时间逐步增加。最初可以将断路器置于打开状态几秒钟,然后如果故障没有解决,将超时时间增加到几分钟。