5 Hystrix

Hystrix:一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖会不可避免得调用失败,比如超时、异常等,Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

扇出:后面调用失败导致前面一串失败的情况。

服务雪崩

5.1 服务熔断机制

熔断机制是应对服务雪崩效应的一种微服务链路保护机制

5.2 Hystrix熔断代码实现

代码实现则是出现异常的时候去执行另一部分方法调用,但是远程方法调用是要求返回类型相同的,所以这里使用ResultEntity既能返回成功也能返回失败的信息。

① 在provider引入依赖
        <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
② 在provider主启动类启用断路器功能
@EnableCircuitBreaker
@SpringBootApplication
public class HikaruMainType {
public static void main(String[] args) {
SpringApplication.run(HikaruMainType.class);
}
}

Circuit为环路的意思

这里也可以使用最新的注解 @EnableHystrix

③ 封装一个ResultEntity作为Ajax请求或者远程方法调用的数据格式
public class ResultEntity<T> {
public static final String SUCCESS = "SUCCESS";
public static final String FAILURE = "FAILURE";
public static final String NO_MESSAGE = "NO_MESSAGE";
public static final String NO_DATA = "NO_DATA"; private String result;
private T data;
private String message; public ResultEntity() {
} public ResultEntity(String result, T data, String message) {
this.result = result;
this.data = data;
this.message = message;
} public String getResult() {
return result;
} public void setResult(String result) {
this.result = result;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
} public static ResultEntity<String> SuccessWithoutData() {
return new ResultEntity<String>(SUCCESS, NO_DATA, NO_MESSAGE);
} public static <E> ResultEntity<E> SuccessWithData(E data) {
return new ResultEntity<E>(SUCCESS, data, NO_MESSAGE);
} /**
* 失败返回错误消息
* @param Message
* @param <E>
* @return
*/
public static <E> ResultEntity<E> Failure(String Message) {
return new ResultEntity<E>(FAILURE, null, Message);
}
}
④ 编写Provider的handler方法:指定服务熔断降级方案
    @HystrixCommand(fallbackMethod = "getEmpBackUp")
@RequestMapping("/provider/circuit/breaker/get/employee")
public ResultEntity<Employee> getEmp(@RequestParam("signal") String signal) throws InterruptedException {
if("quick-bang".equals(signal)) {
throw new RuntimeException();
} else if("slow-bang".equals(signal)) {
Thread.sleep(1000);
}
return ResultEntity.SuccessWithData(new Employee(6, "66", 666));
} public ResultEntity<Employee> getEmpBackUp(@RequestParam("signal") String signal) {
return ResultEntity.Failure("Circuit works with signal" + signal);
}
⑤ 超时熔断不生效的情况:Feign里面Ribbon的超时时间小于了Hystrix超时熔断时间

使用上面的配置,在Consumer端口访问http://localhost:7000/consumer/get/emp/with/ciruit/breaker?signal=slow-bang会发现直接抛出异常而不是我们期待的封装的失败返回体,这里的原因是Feign里面Ribbon的超时时间小于Hystrix超时熔断时间 ,简单来说就是Ribbon带着服务名去Eureka注册中心调用远程方法迟迟没有响应而达到了它的最大值,于是在Hystrix熔断的超时时间之前就返回了异常信息。

修改也很简单,只需要改一下Feign里面的Ribbon的ConnectTimeOut和ReadTimeOut即可:

feign:
client:
config:
default:
ConnectTimeOut: 5000
ReadTimeOut: 5000
Ribbon的 ConnectTimeOut 和 ReadTimeOut

ConnectTimeOutribboneureka两端建立连接所用的时间,在java中,网络状况正常的情况下,例如使用HttpClient或者HttpURLConnetion连接时设置参数connectTimeout=5000即5秒,如果连接用时超过5秒就是抛出java.net.SocketException: connetct time out的异常。

ReadTimeOut则是读取数据花费的时间,如果在指定时间读不到数据,则会抛出Java.net.SocketException: read time out的异常,这也正是我们这里控制台日志中的异常。

一般来说前者设置得很小而后者设置得很大,原因是一般很少有连接超时的情况,但是经常有由于网络波动下载读取的情况。

5.3 Hystrix降级

服务降级处理是在客户端(Consumer) 实现的,与服务端(Provider)没有关系。当某个Consumer访问一个Provider迟迟得不到响应的时候,会去执行一个预先设定好的方案,而不是一直等待。

降级是consumer得不到回应采取的补救措施

熔断是provider响应不了实例采取的补救措施

① 在common模块创建FallBack工厂类

实现Consumer服务降级功能时要传入 @FeinClient 注解标记的类型,然后在create()返回一个 @FeignClient 注解标记的接口类型的对象,当Provider调用失败之后就会调用这个对象中的方法

/**
* 实现Consumer服务降级功能时要传入 @FeinClient 注解标记的类型
* 然后在create()返回一个 @FeignClient 注解标记的接口类型的对象,当Provider调用失败之后就会调用这个对象中的方法
*/
@Component
public class MyFallBackFactory implements FallbackFactory<EmployeeRemoteService> { @Override
public EmployeeRemoteService create(Throwable throwable) { return new EmployeeRemoteService() {
@Override
public Employee getEmployeeRemote() {
return null;
} @Override
public ResultEntity<Employee> getEmp(String signal) {
return ResultEntity.Failure(throwable.getMessage() + "降级机制生效");
}
};
}
}

别忘了在工厂类上面添加@Component注解,否则无法加入IOC容器

② 在common模块的远程方法调用接口上指明降级使用的工厂类
@FeignClient(value = "hikaru-provider", fallbackFactory = MyFallBackFactory.class)
public interface EmployeeRemoteService {
/**
* 远程调用的接口方法
* 要求:
* ① @RequestMapping地址一致
* ② 方法声明一致
* ③ 用来获取请求参数的@RequestParam、@PathVariable、@RequestBody一致
* @return
*/
@RequestMapping("/provider/get/employee/remote")
public Employee getEmployeeRemote(); @RequestMapping("/provider/circuit/breaker/get/employee")
public ResultEntity<Employee> getEmp(@RequestParam("signal") String signal);
}

可以看到这里是在注解上指定的工厂类,所以也解释了上面为什么要将工厂类添加到IOC容器

③ 在consumer端开启服务降级
eureka:
client:
service-url:
defaultZone: http://localhost:5000/eureka server:
port: 7000
tomcat:
connection-timeout: 5000 feign:
hystrix:
enabled: true
client:
config:
default:
ConnectTimeOut: 5000
ReadTimeOut: 5000
⑤ 测试:http://localhost:7000/consumer/get/emp/with/ciruit/breaker?signal=123
{"result":"FAILURE","data":null,"message":"null降级机制生效"}

5.4 Hystrix仪表盘:监控服务的各种信息

在Provider引入依赖并配置application.yml
        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
endpoints:
web:
exposure:
include: hystrix.stream
创建监控工程spring-cloud-dashboard

① 引入依赖

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

② 在主启动类开启仪表盘功能

@EnableHystrixDashboard
@SpringBootApplication
public class HikaruMainType {
public static void main(String[] args) {
SpringApplication.run(HikaruMainType.class);
}
}

③ 设置访问端口号和配置代理地址

server:
port: 8000
spring:
application:
name: hikaru-dashboard hystrix:
dashboard:
proxy-stream-allow-list: "localhost"
访问监控工程

输入监控工程地址\http://localhost:8000/hystrix,然后输入 http://localhost:3000/actuator/hystrix.stream 以及Delay(默认2000)监控延迟时间

监控延迟时间是为了防止给Provider造成压力

6 Zuul 网关

zuul为整个项目中的微服务模块提供一个统一的入口,请求经过网关再去访问微服务模块,不同微服务一般有不同地址,而外部的客户端可能会调用多个微服务的接口才能完成一个业务需求,如果让客户端和服务端直接进行通信:

  • 客户端会多次请求不同的服务端,增加了客户端的复杂性

  • 存在跨域问题

  • 认证复杂,每一个微服务模块需要单独认证

  • 难以重构:客户端和服务端之间的通信错综复杂

  • 某些微服务可能使用了其他协议,直接访问可能有困难

zuul最主要的j几个功能:

路由:将外部请求转发到具体的微服务实例上,是实现外部统一入口的基础

过滤:负责对请求过程进行干预

代理:Zuul自身会注册为eureka的应用,并获取eureka中其他微服务的信息,也即以后的微服务的访问都是通过Zuul代理跳转的。

6.1 代码实现

① 创建zuul工程并导入zuul依赖和eureka客户端依赖
    <dependencies>

        <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> </dependencies>
② 配置
server:
port: 9000 spring:
application:
name: hikaru-zuul eureka:
client:
service-url:
defaultZone: http://localhost:5000/eureka
③ 在主启动类开启zuul代理服务
@EnableZuulProxy
@SpringBootApplication
public class HikaruMainType {
public static void main(String[] args) {
SpringApplication.run(HikaruMainType.class);
}
}

6.2 zuul配置路由规则

自定义访问

在zuul工程中配置:

server:
port: 9000 spring:
application:
name: hikaru-zuul eureka:
client:
service-url:
defaultZone: http://localhost:5000/eureka zuul:
routes:
employee:
service-id: hikaru-consumer
path: /zuul-emp/**

重启之后访问http://localhost:9000/zuul-emp/consumer/get/emp/with/ciruit/breaker?signal=123可以访问,原来的地址通过微服务的名称也可以访问:localhost:9000/hikaru-consumer/consumer/get/emp/with/ciruit/breaker?signal=123

ignored-services: '*' 禁止微服务名称访问
server:
port: 9000 spring:
application:
name: hikaru-zuul eureka:
client:
service-url:
defaultZone: http://localhost:5000/eureka zuul:
ignored-services: '*'
routes:
employee:
service-id: hikaru-consumer
path: /zuul-emp/**
prefix: 添加访问前缀

这里zuul的路由规则只适用于localhost:9000,zuul无法拦截其他微服务端口号的

6.3 zuul Filter

package com.hikaru.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.protocol.RequestContent;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Slf4j
@Component
public class MyZuulFilter extends ZuulFilter {
/**
* 过滤器什么时候执行
* @return
*/
@Override
public String filterType() {
String filterType = "pre";
return filterType;
} @Override
public int filterOrder() {
return 0;
} /**
* 判读是否过滤
* @return
*/
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String signal = request.getParameter("signal");
return "hello".equals(signal);
} /**
* 过滤执行的操作
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
log.info("当前请求需要执行过滤,run方法执行了"); return null;
}
}

【SpringCloud】(三)Hystrix 与 Zuul的更多相关文章

  1. 一文读懂SpringCloud与Eureka,Feign,Ribbon,Hystrix,Zuul核心组件间的关系

    概述 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓 ...

  2. 高并发场景-请求合并(一)SpringCloud中Hystrix请求合并

    背景 在互联网的高并发场景下,请求会非常多,但是数据库连接池比较少,或者说需要减少CPU压力,减少处理逻辑的,需要把单个查询,用某些手段,改为批量查询多个后返回. 如:支付宝中,查询"个人信 ...

  3. Spring Cloud正式移除Hystrix、Zuul等Netflix OSS组件

    1. 前言 2020-12-22日Spring官方博客宣布,Spring Cloud 2020.0.0正式发布.2020.0.0是第一个使用新的版本号命名方案的Spring Cloud发行版本.在此之 ...

  4. springcloud核心组件Eureka、Ribbon、Feign、Hystrix、Zuul

    各个组件角色扮演:    Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取 ...

  5. SpringCloud与Eureka,Feign,Ribbon,Hystrix,Zuul核心组件间的关系

    Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取注册表,从而知道其他服务在 ...

  6. SpringCloud(三) Zuul

    Zuul 有了eureka . feign 和 hystrix 后,基本上就搭建了简易版的分布式项目,但仍存在一些问题,比如: 1.如果我们的微服务中有很多个独立服务都要对外提供服务,那么我们要如何去 ...

  7. springcloud(十六)、feign+hystrix+ribbon+zuul应用案例

    在 基于 " sringcloud(十四).ribbon负载均衡策略应用案例 "所有工程的基础上,进行如下操作进行网关设置 1.创建eureka-client-consumer-z ...

  8. 微服务SpringCloud之服务网关zuul一

    前面学习了Eureka.Feign.Hystrix.Config,本篇来学习下API网关zuul.在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服 ...

  9. springCloud学习4(Zuul服务路由)

    镇博图 springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 本篇中 Zuul 版本为 1.x,目前最新的是 2.x,二者 ...

  10. spring Cloud 之 Eureka、Feign、Hystrix、Zuul、Config、Bus

    一.服务发现——Netflix Eureka Eureka包含两个组件: Eureka Server和Eureka Client 1.创建Eureka Server服务端 (1).引入依赖 父工程po ...

随机推荐

  1. Linux中/etc目录下passwd和shadow文件

    /etc/passwd介绍 首先,通过cat /etc/passwd 来查看文件/etc/passwd中内容: root:x:0:0:root:/root:/bin/bash daemon:x:1:1 ...

  2. SQL Server之Cross apply

    1 --这样是不行的 2 select sys.dm_exec_sql_text(most_recent_sql_handle) from sys.dm_exec_connections 3 4 -- ...

  3. .Net5.0 上传图片、文件到服务器

    今天来看看.net上传图片到服务器的方式 public class ControlPresetUploadInput { /// <summary> /// 通道编号 /// </s ...

  4. 安装mysql8.0

    安装repo源 参考mysql官方文档 参考文章 redhat7通过yum安装mysql5.7.17教程:https://www.jb51.net/article/103676.htm mysql r ...

  5. 【帆吖】Java学习零基础17

    Java方法 1 package method; 2 3 public class Demo1 { 4 //main方法 5 public static void main(String[] args ...

  6. centos7所有用户循环登录

    1 使用快捷键Ctrl+Alt+F2进入命令终端 2 输入账号密码 3 输入 /usr/bin/sudo 4 输入 startx 那种单用户,改配置的试了没有用

  7. 网站下/.git/index查看

    遇见有些网站目录中存在 http://target.com/.git/index 由于index是二进制文件 下载回来本地查看 初始化 下载到.git目录 git checkout-index -a

  8. python list dict util (分割,分组)

    1.list数据分割为多个小列表  (java   lists.partition) 2. 分组 import itertools def partition(mylist, size): " ...

  9. Java日常

    学习Java第3天的小总结 一.感受总结 Java是目前市场上的主流语言,相对于C和C++语言来说,竞争更为激烈,而这一大特点也在激励着我不断去探索,去学习: 在下载相应编译环境的过程中,由于IDEA ...

  10. windows cmd基础命令

    cmd md 新建目录rd 删除目录(非空目录)rd 删除目录下所有文件cd 改变当前目录cd .. 返回上一级目录cd \ 返回根目录d: 切换盘符到D盘dir 显示当前目录下的文件del 1.tx ...