Spring-cloud微服务实战【七】:服务熔断与降级hystrix

  在之前的文章中,我们先后介绍了eureka,ribbon,feign,使用eureka集群的方式来保证注册中心的高可用,在eureka中使用ribbon进行负载均衡,使用feign接口替换手动编码请求接口的代码,整个微服务看似基本完成了,那是否有继续值得优化的地方呢?答案肯定是有的,并且是整个微服务最重要的一环,那就是服务的热熔断与降级,那为什么服务熔断与降级是最重要的一环呢?我们先来看一下服务雪崩的概念.

服务雪崩

  所谓服务雪崩,是微服务系统中特有的概念,不了解服务雪崩的概念的童鞋,初一听服务雪崩,肯定会联想到缓存雪崩,所谓缓存雪崩,即大量缓存在同一时间过期,导致大量请求不走缓存而进行数据库访问,数据库瞬时压力暴增,导致数据库宕机.一般我们的解决方案无非有几点:
1.为不同的缓存设置不同的过期时间.
2.热点数据永不过期.
3.缓存预热.
  我们之所以要预防缓存雪崩,从系统架构五个方面(高性能/高可用/伸缩性/扩展性/安全性)来讲,是保证系统的高性能以及保护数据库,而我们说要预防服务雪崩,是为了保证整个微服务系统的可用性,让我们用一张图来说说明:
file

  假设在一个电商微服务系统中,有用户服务,订单服务,产品服务,物流服务等服务,用户服务调用订单服务,订单服务调用产品服务,产品服务调用物流服务,如果没有考虑服务的熔断与降级,假如在产品服务调用物流服务的时候,物流服务本身出问题了返回了错误或者是网络波动导致请求超时,则产品服务会报错,从而影响订单服务跟着报错,层层返回,直到最顶层的服务,这样就导致了一个微服务自身的问题影响了整个微服务系统级联报错,这就是所谓的服务雪崩,极端情况下,可能导致几个甚至整个微服务系统全部宕机,这对于现代微服务系统来说,是无法忍受的,因此,我们需要进行服务的熔断与降级.
  需要注意的是,服务的熔断与降级是两个概念,一般而言,所谓服务熔断,是对服务提供方而言,当服务提供方无法调用的时候需要被熔断,而降级是对服务消费方而言,当服务提供方无法正常提供服务时,消费方需要降级处理.spring cloud中对服务的熔断和降级是使用hystrix,接下来,让我们详细了解一下hystrix.

服务熔断与降级hystrix

  spring cloud中使用hystrix进行服务的熔断和降级,hystrix翻译成中文是豪猪的意思,它是Netflix开源的一款针对分布式系统进行服务熔断与降级的框架.那么我们如何使用呢?让我们直接用代码来演示一下:
  把之前我们的项目dhp-micro-service-producer复制一份为dhp-micro-service-producer-hystrix:
file
  将之加入父项目:
file

  老规矩,三个步骤,首先新增maven依赖:
file

  然后修改代码:
file

  其中@HystrixCommand的作用是指定一个熔断方法,当有该注解的方法抛出异常的时候,会调用fallbackMethod指定的方法,该方法需要我们自己根据业务需要来完成.需要注意的是,方法的入参和返回值都必须要和原始方法保持一致.
  修改一下配置文件,注意eureka注册中心的地址和端口号,我这里修改端口号为7301:
file

  最后修改启动类,增加对hystrix的支持:
file

  然后启动来访问试一试,注意如果启动报错,看看是否eureka-server未启动,但这并不影响我们的测试,由于我们在producer项目中的product信息是使用代码方式来mock数据库操作:
file

  总计只有6条数据,因此ID>6均查不出数据,返回product=null,就会触发我们设置的降级方法,因此访问试一试:
file

  说明我们的服务提供方在服务出现异常时的熔断方法已经成功使用了,但这还不够,在某些情况下,服务的提供方并没有问题,但是可能由于网络原因导致消费方并不能成功调用到提供方的接口,此时服务提供方的任何处理都是毫无意义的,因此我们需要在消费者端进行服务降级.
  由于我们之前使用feign进行接口代理,而feign中已经集成了hystrix,因此我们需要改造consumer端代码:
  首先在feign代理接口中新增fallbackFactory指定降级服务的类:
file

  然后实现该类,该类需要实现FallbackFactory接口的create方法,返回一个泛型指定的服务,并且实现该指定接口中的所有方法的降级处理:
file

  然后我们可以验证一下:首先启动eureka-server,然后启动producer,将producer注册到eureka:
file
  可以看到,我们修改端口号为7301的producer[dhp-micro-service-producer-hystrix]已经成功注册到eureka,然后再启动consumer[dhp-micro-service-consumer-feign],我修改端口号为7005,并且还需要开启feign.hystrix.enabled=true,默认是false:
file

  启动成功后,访问一下试一试:
file

  当我们id=1时,可以成功获取结果,再试一试当ID>6时的情况:
file

  从描述可以看到,这是执行了producer[dhp-micro-service-producer-hystrix]的熔断方法,那我们如何来验证消费者端的降级方法呢?首先需要关闭eureka-server的自我保护功能,并且设置10秒自检一次,剔除无效的服务:
file

  那么如何算无效呢?这需要服务提供方进行设置,修改producer[dhp-micro-service-producer-hystrix]发送心跳时间以及服务过期时间,以便尽快让eureka-server剔除producer:
file

  这里我们为了快速让eureka-server剔除producer,设置5秒(默认值为30秒)发送1次心跳,并且告诉eureka-server,假如15秒(默认值为90秒,一般为心跳间隔时间的3倍)内没有发送任何心跳,则eureka-server将producer剔除,此时,eureka-server主动失效检测时间为10秒,则当我们停止producer后最多25秒eureka-server会将producer剔除,此时再访问consumer:
file

  可以看到,这是执行了我们consumer的降级方法,自此hystrix在服务提供方和消费方的配置都完成了,是不是很简单?接下来,让我们再了解一下hystrix的仪表盘dashboard.

HystrixDashboard

  Dashboard(仪表盘)是hystrix提供的一种用于服务监控的功能,可以利用它对某一个微服务进行监控,让我们来试一试,首先新建一个module[dhp-micro-service-hystrix-dashboard]:
file
  然后将之加入父项目:
file

  接下来新增maven依赖:
file

  然后配置文件修改服务端口号:
file

  然后启动类新增对dashboard的支持:
file

  启动起来看一下:
file

  那么该如何使用呢?首先,需要确保被监控的服务有健康检查的依赖,比如我们对producer[dhp-micro-service-producer-hystrix]进行监控,则需要确保producer的maven配置中有健康检查的相关依赖:
file

  并且还需要相关的配置:
file

  然后启动producer,并且在hystrix dashboard中输入对应的producer的地址,则就能监控到所有的对该地址的访问:
file

  此时再访问该producer的相关接口,就能看到相关统计信息了:
file

  至于其中每项数据的含义,我相信肯定难不倒各位广大童鞋,毕竟有问题找度娘,大家都知道,有条件就Google,没有任何问题能难倒我们.

Turbine

  细心的同学会发现,之前我们在hystrix-dashboard的首页上看到了这么一行提示:
file

  翻译一下,就是告诉我们如果是使用turbine的方式,监控地址的格式是turbine-hostname:port/turbine.stream,如果是单一的hystrix-app的方式,地址格式是hystrix-app:port/actuator/hystrix.stream,我们之前就是使用的单一的这种方式,那么turbine又是什么呢?

  我们在上面说到,dashboard只能对某一个微服务进行监控,但实际情况是一个微服务生产系统远远不止一个微服务,我们需要对所有的微服务都进行监控,而dashboard显然无法满足我们的需求,而turbine则可以,因此turbine的作用就是可以对多个微服务同时进行监控.为了方便演示turbine对多个微服务的监控,我们新建一个module[dhp-micro-service-user-hystrix]:
file

  然后加入父项目:
file

  然后老规矩,三个步骤,先配置maven依赖:
file

  然后再配置application.properties:
file

  相关配置具体的含义就不在多说了,之前的文章已经讲得很详细了,接着修改主类:
file

  然后进行编码:
file

  相关代码和producer类似,然后启动eureka-server,再启动user和producer:
file

  可以看到两个服务都已经注册到eureka了,然后使用dashboard测试一下:
file

  没有问题,说明可以,接下来,我们使用turbine同时监控producer和user服务,为了便于和之前的dashboard比较,我们新增一个turbine module[dhp-micro-service-turbine-dashboard]:
file

  将之加入父项目:
file

  然后老规矩,首先配置maven依赖:
file

  然后配置application.properties:
file

  其中最重要的就是需要配置turbine相关信息,app-config标识需要监控的服务,多个用逗号隔开,并且从名字我们可以看出就是eureka中注册的服务的服务名:
file

  新增主类配置:
file

  然后先启动eureka-server,再启动user[dhp-micro-service-user-hystrix]和producer[dhp-micro-service-producer-hystrix]两个服务,再启动dashboard[dhp-micro-service-hystrix-dashboard],最后启动turbine[dhp-micro-service-turbine-dashboard],然后访问dashboard[dhp-micro-service-hystrix-dashboard],并监控turbine的地址:
file

  然后分别请求user和producer:
file
file

  然后看一下hystrix-dashboard:
file

  发现只监控到了userController,但是并没有监控到ProducerController,这是为什么呢?是我们配置不对吗?别着急,我们来看一下控制台的信息:
file
file

  提示信息告诉我们,有一个连接被拒绝,因此放弃turbine对其的监控,失败的地址是192.168.1.13:7301,可以看出这是我们的producer服务的地址,另外提示信息中status401,error和message都提示我们,未授权的登录,回忆一下,之前我们的producer项目引入了dhp-micro-service-auth进行安全验证,需要用户名和密码,因此我们找到了原因:登录producer时未授权,导致监控失败,那这该如何解决呢?很遗憾,turbine既能监控所有服务都有密码的情形,也能监控所有服务都没有密码的情形,但是对于有些服务有密码,而有些服务没有密码的情形,turbine就无能为力了,如果实在因为生产需要要适配,我们只能通过修改dhp-micro-service-auth的方式,来让相应的服务取消对/actuator/hystrix.stream与/turbine.stream这两个地址的密码验证:
file

  此时再重启一下producer,然后再次访问user和producer,再看一下dashboard:
file

  此时producerController和UserController均成功被turbine监控了.

  回顾一下,在本文我们介绍了spring-cloud断路器hystrix以及对hystrix的单个服务监控hystrix-dashboard以及对多个服务监控的turbine,下一篇文章,我们继续介绍网关zuul,敬请期待!

  本文的github地址

本文由博客一文多发平台 OpenWrite 发布!

posted @ 2020-02-06 17:39  悟空不败  阅读(826)  评论(0编辑  收藏  举报