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

ConnectTimeOut是ribbon和eureka两端建立连接所用的时间,在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. 12.7 linux学习第十四天

    今天老刘开始讲第10章,主要讲Ahache服务和SELinux安全子系统 10.1 网站服务程序 1970年,作为互联网前身的ARPANET(阿帕网)已初具雏形,并开始向非军用部门开放,许多大学和商业 ...

  2. Linux系列---【内存占用过高问题排查思路】

    内存占用过高问题排查思路 1.使用top命令查看后台任务 按shift+M使应用按内存使用率排序,定位到第一个使用内存最高的应用,并找到对应的PID. 2.使用ps命令查看对应的pid对应哪个应用 p ...

  3. 1js 高级

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 百度自定义底图(瓦片图)升级 HTTPS

    本文地址:https://www.cnblogs.com/veinyin/p/14338414.html 记录一下开发中遇到的问题与解决方案 使用 Leaflet 开发,设计为了美观采用百度自定义底图 ...

  5. bigNumber.js的简单使用

    sum 计算传入的参数和,参数类型可以是 String,Number // 两数之和 var x = BigNumber.sum('11', 23) x.toNumber() // 34 // 多个参 ...

  6. centos虚拟机yum update报错Another app is currently holding the yum lock; waiting for it to exit...

    1.运行yum update报错 [root@localhost ~]# yum update已加载插件:fastestmirror, langpacks/var/run/yum.pid 已被锁定,P ...

  7. 记一次Centos7上安装VNC服务

    需要部署oracle数据库,操作系统为Centos7.5,oracle数据库在linux上面部署必须要安装一些依赖包,安装好,当然可以通过静默化安装,时间紧任务重,就通过vnc服务来进行安装,桌面化操 ...

  8. Web部署

    1.项目配置的理解 IDEA 中最重要的各种设置项,就是这个 Project Structre 了,关乎你的项目运行,缺胳膊少腿都不行.最近公司正好也是用之前自己比较熟悉的IDEA而不是Eclipse ...

  9. 116、商城业务---分布式事务---seata的AT模式存在的问题&&最终一致性库存解锁逻辑

    seata的AT模式不适合高并发的项目,因为它需要加锁来保证回滚.因此我们的订单服务方法中就尽量不能使用@GlobalTransactional来管理分布式事务. 因此在订单服务中,我们使用下面这种方 ...

  10. WSL安装Ubuntu 22.04 (2)

    1.安装系统环境 1.1.设置软件包源为国内镜像 参考:Ubuntu更换国内镜像源 - 知乎 1.2.更新系统软件包 sudo apt-get update && sudo apt-g ...