springcloud微服务四:服务容错保护Hystrix断路器

2024-04-28 07:08

本文主要是介绍springcloud微服务四:服务容错保护Hystrix断路器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、使用

通过前边的学习,服务注册中心、服务提供者和服务消费者都成功建立并运行起来,而且通过默认的配置restTemplate及@loadbalanced注解开启了负载均衡。
在默认的情况下,负载均衡策略是线性轮询的方式,也就是说在客户端获取到的服务列表中依次交替,例如开启了三个服务server1、server2、server3,那么在线性轮询时,就会按这个顺序来调用。
我之前是开启了两个服务,一个端口是1001,另一个是2001,那么在之前的这种情况下,如果我关闭其中一个服务,就比如这里关闭1001端口的服务,当再次访问的时候,每访问两次,就会有一次是如下的error page:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri May 26 09:31:57 CST 2017
There was an unexpected error (type=Internal Server Error, status=500).
I/O error on GET request for "http://HELLO-SERVICE/hello": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect

同时后台也会打印出错误日志:

java.net.ConnectException: Connection refused: connectat java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_131]at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source) ~[na:1.8.0_131]at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source) ~[na:1.8.0_131]at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source) ~[na:1.8.0_131]at java.net.AbstractPlainSocketImpl.connect(Unknown Source) ~[na:1.8.0_131]at java.net.PlainSocketImpl.connect(Unknown Source) ~[na:1.8.0_131]at java.net.SocksSocketImpl.connect(Unknown Source) ~[na:1.8.0_131]at java.net.Socket.connect(Unknown Source) ~[na:1.8.0_131]

其实这个问题的原因就是,客户端的服务列表并不是在服务关闭的瞬间就会同步更新,而是根据它自己配置的更新服务列表间隔的时间每隔一段时间去注册中心获取一次。
因此,虽然这里我关闭了1001端口,但是实际上客户端并不知道,在它负载均衡进行线性轮询时,依旧会轮询之前保存的服务列表,但是发送请求后却发现这个服务实例并不存在,无法连接,于是就出现了上边的500错误。
这里为了演示,我是主动关闭了服务,但实际生产的过程中,难免会出现服务宕机或者网络故障等方面的问题,从而导致类似的无法连接到服务实例的情况。
那么这时候正常来说在这个故障恢复之前是不应该继续连接的,起码就算连接了也应该给用户展示更加友好的界面或其他信息,至于具体的情况就需要具体对待了。
而解决这个问题,就引出了服务容错保护机制Hystrix,也叫断路器
既然之前说了消费方保存的服务列表是自己主动获取的,并非被动推送来的,那么可想而知这个断路器的定义也应该是在服务消费方。
首先需要引入hystrix相应的依赖,在之前的消费端pom.xml的基础上加上如下的配置:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

同时在服务消费端的主类加上@@EnableCircuitBreaker注解,这个注解的作用就是开启断路器功能,所谓的主类就是具有main方法的那个类,修改之后这里的代码如下:

@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonClient1Application {@Bean@LoadBalancedRestTemplate restTemplate() {return new RestTemplate();}public static void main(String[] args) {SpringApplication.run(RibbonClient1Application.class, args);}
}

这里实际上有一点需要说明的是,这个类上边的三个注解其实是可以用一个注解代替的,这个注解是@SpringCloudApplication,通过源码可以知道这个注解包含了上述三个注解,也意味着一个标准的springcloud应用是应该包括服务的注册发现以及断路器功能的
那么除开主类加一个注解之外,原本的服务类也需要有一定的修改,首先是在原本调用的方法上加上@HystrixCommand(fallbackMethod = “helloError”),意思是当调用的服务出现故障的时候回调helloError方法,或者说当调用服务出现故障的时候回滚一步,然后转而调用helloError方法。
不管怎样,既然要调用helloError方法,很显然需要存在这个方法,因此还需要加入一个helloError方法,当然了这个方法名是自定义的,里边的逻辑也是要根据具体的业务需要定义的,我这里就很简单的返回一个字符串,修改之后的代码如下:

@RestController
public class ConsumerController {@AutowiredRestTemplate restTemplate;@RequestMapping(value="/hello",method=RequestMethod.GET)@HystrixCommand(fallbackMethod = "helloError")public String hello(){String string = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();System.out.println(string);return string;}public String helloError() {return "服务器出现故障";}
}

就这样,一个简单地断路器功能就实现了,为了证明确实有效,我在两个服务正常运行的情况下再次关闭其中一个,然后再在浏览器访问的时候就不会再出现之前的500提示,后台也同样不再有error的日志,证明成功的处理了的这种故障,浏览器访问结果如图:
这里写图片描述
当然了,我这里演示的时候,为了方便都是直接关掉了其中一台服务器,这相当于实际生产中的服务器突然宕机或者进程突然中断的情况,而实际上这种情况发生的几率还是比较少的。
由于在分布式高可用的系统中,一般不同的服务是部署在不同的服务器上,不同的服务器间就会涉及到网络通讯和数据传输,因此正常来说网络故障导致服务异常的情况会更多一些。
如果要演示这种情况,就可以在服务接收请求到返回数据之前加入线程休眠,从而模拟网络阻塞,只需要注意hystrix的默认超时时间是2000毫秒,也就是2秒就够了。

二、运行流程说明

流程图(来自网络)

这里写图片描述

流程说明

hystrix运行流程说明:
1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中.
2:执行execute()/queue做同步或异步调用.
3:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤.
4:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤.
5:调用HystrixCommand的run方法.运行依赖逻辑
    5a:依赖逻辑调用超时,进入步骤8.
6:判断逻辑是否调用成功
    6a:返回成功调用结果
    6b:调用出错,进入步骤8.
7:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态.
8:getFallback()降级逻辑.
    8a:没有实现getFallback的Command将直接抛出异常
    8b:fallback降级逻辑调用成功直接返回
    8c:降级逻辑调用失败抛出异常
9:返回执行成功结果

fallback触发场景

综合上边的流程可知,四种情况将触发getFallback调用:
(1):熔断器开启拦截调用
(2):线程池/队列/信号量是否跑满
(3):run()方法调用超时
(4):run()方法抛出非HystrixBadRequestException异常

如何判断熔断器是否打开:

(1):熔断器打开标示,为true为打开,否则查询度量指标(10s的时间窗)
(2):请求阀值是否超标,默认是20个请求,超标则为true
(3):请求错误百分比是否超标,默认是50,超标则为true
当2和3都超标时,熔断器标示会设为true,打开状态。

依赖隔离

默认是线程池隔离,可以改成信号量。
信号量开销比线程池小很多,但不支持异步访问和设置超时。

这篇关于springcloud微服务四:服务容错保护Hystrix断路器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/942595

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、