分布式系统对高可用比较讲究,本文来探讨探讨。

一、zookeeper高可用

通过实验可以发现,在正常调用服务之后,注册中心突然挂了,也不影响继续消费dubbo暴露出来的服务。

注册中心不是挂了吗,为什么还能继续调用服务呢?

原因是dubbo中做了健壮性处理,简单来说就是每个dubbo的消费方自己会缓存通讯的信息,即使注册中心挂了,通过这个缓存也可以找到对应的Provider继续消费。具体机制如下:

  • 监控中心宕掉不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

并且之前也提过,dubbo支持直连,在消费方的注解中形如@Reference(url="ip:port")即可绕过注册中心直接连接到对应的服务去消费。 因此如果没有注册中心的情况下,也可以调用服务。

二、负载均衡

策略名称 策略描述
Random 随机,按权重设置随机概率
RoundRobin 轮询,按公约后的权重设置轮询比率
LeastActive 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差
ConsistentHash 一致性hash,相同参数的请求总是发到同一个提供者

对于Random,在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

对于RoundRobin,存在慢的提供者累积请求的问题,比如某一台服务器比较慢,请求卡在这一台服务器上。

对于LeastActive,使慢的提供者收到更少请求,因为越慢的提供者的调用前后奇数差越大

配置:

  • 服务端服务级别
1
<dubbo:service interface="..." loadbalance="roundrobin" />
  • 客户端服务级别
1
<dubbo:reference interface="..." loadbalance="roundrobin" />
  • 服务端方法级别
1
2
3
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
  • 客户端方法级别
1
2
3
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

一般场景下,配置Provider端的负载均衡。值得注意的是,如果我们需要对随机或者轮询增加权重,则可以直接在控制台上实现,非常方便,如图:

image

三、服务降级

什么是服务降级?

当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。

比如某一台服务器上,有三个服务:用户服务、订单服务以及广告服务。当遇到流量激增的情况时,CPU百分百,内存百分百,整个服务器处于要崩溃的边缘,处理请求及其缓慢,此时我们必须要牺牲某些服务,释放出资源,比如我们可以选择将不是太核心的广告服务先停掉,保全其他核心的用户服务以及订单服务。广告服务降级后,可以直接返回一个简单的内容。(这里其实是指:消费方不再去远程调用这个广告服务了,直接返回一个结果给客户即可,这样,广告服务可以暂时将服务器资源让出来)

当然,还有另一种场景,也是类似,即服务调用失败,要么抛出异常要么超时,总之不能正常拿到结果了,此时我们也应该制定一个策略,使其不要返回错误,可以直接在消费方返回null或者默认的结果。这样就可以达到不重要的服务不可稳定时不会对调用方产生影响。

dubbo如何实现的呢?其实操作起来非常简单,就是在dubbo的控制台就可以完成设置了。我们来到消费者页面,

image

图中是第一个服务是订单服务,它要调用用户服务。那么如果我选择是的屏蔽,那么这个订单服务将停止调用所有其他的服务,直接返回空。

image

如果选择的是容错,那么订单服务在调用其他服务的时候发现其他服务报错或者超时,就返回空。

image

四、服务容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

  • Failover Cluster

失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。

重试次数配置如下:

1
<dubbo:service retries="2" />

1
<dubbo:reference retries="2" />

1
2
3
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
  • Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

  • Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

  • Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

  • Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。

  • Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

集群模式配置按照以下示例在服务提供方和消费方配置集群模式

1
<dubbo:service cluster="failsafe" />

1
<dubbo:reference cluster="failsafe" />

五、Hystrix

由于dubbo对于服务降级和容错等做的比较简单,因此在实际开发中,是用Hystrix来实现服务容错的。也是spring cloud中默认的服务容错组件。在11.天气预报系统-熔断机制中对其进行了介绍和简单实用。核心就是@HystrixCommand这个注解,添加这个注解之后这个方法就被hystrix代理了,从而实现对这个方法的一个监控。基本的使用就不再赘述了,比较简单,就是添加依赖-开启hystrix-HystrixCommand这个即可。