栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring cloud入门-11:服务降级-Hystrix

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring cloud入门-11:服务降级-Hystrix

Spring cloud入门-11:服务降级-Hystrix

1、Hystrix入门介绍

1.1 分布式系统面临的问题1.2 Introduction to Hystrix 2、构建服务提供模块8001

2.1 业务类新增异常返回 3、构建服务消费模块80

3.1 建module3.2 改pom3.3 写yml3.4 主启动3.5 业务类3.6 测试

3.6.1 测试查看订单接口:getPaymentById3.6.2 测试长时间业务处理接口:PaymentFeignTimeout

1、Hystrix入门介绍 1.1 分布式系统面临的问题

  前面已经构建了erureka集群(7001,7002)、服务提供模块集群(8001,8002)、和消费服务模块(80)的简单demo。
  但是在实际的分布式系统中,一般不是和demo这样简单的调用依赖关系,而是多级的服务调用关系,但是这些服务之间的相互调用在某些时候不可避免地会出现失败。
  比如微服务A调用微服务B和微服务C,微服务B又调用微服务D,微服务C又调用微服务E。如果微服务D的调用时间过长或者已经不可用了。此时,A调用C,C调用D,在D这里调用时间长或不可用的话,会导致该服务其实一致没有返回。但是在高流量的情况下,微服务A还会继续接收到流量,此时前面的服务都还没有处理完响应因此对微服务A的持续调用就会占用越来越多的系统资源,导致延迟增加,备份队列,线程和其他系统资源紧张,从而导致整个系统发生更多的级联故障,进而引起系统崩溃,发生所谓的“雪崩效应”

1.2 Introduction to Hystrix

  针对上面分布式系统中遇到的问题,本节介绍Hystrix。首先访问官网,看下介绍:https://github.com/Netflix/Hystrix。
  
  Hystrix 是一个用于处理分布式系统的延迟(latency)和容错(tolerance)的开源库,旨在隔离对远程系统、服务和第 3 方库的访问点,停止级联故障(cascading failure),使故障不可避免的复杂分布式系统具有弹性(enable resilience)。
  也就是当某个服务发生故障后,Hystrix可以向调用方返回一个预期的、可处理的备选响应(FallBack),而不是长时间等待或者抛出调用方法无法处理的异常,从而保证服务调用方的线程不会长时间地占用,从而避免故障在分布式系统中的蔓延,乃至雪崩。

2、构建服务提供模块8001

  还是和之前一样,构建注册进eureka集群的服务提供模块8001。
  服务降级主要在以下4种情况下会发生:

程序运行异常超时服务熔断触发服务降级线程池/信号量打满导致服务降级 2.1 业务类新增异常返回

  在服务提供模块(8001)中的查看订单的业务逻辑中,如果id为小于等于0,那么就抛出异常。
  

package com.example.springcloud.controller;

import com.example.springcloud.entities.CommonResult;
import com.example.springcloud.entities.Payment;
import com.example.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;

    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = paymentService.create(payment);
        log.info("插入结果" + result);

        if (result > 0) {
            return new CommonResult(200, "插入数据库成功, serverPort: " + serverPort, result);
        } else {
            return new CommonResult(500, "插入数据失败, serverPort: " + serverPort);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id) throws Exception{
        if (id<=0) {
            throw new Exception("订单编号必须大于0");
        }

        Payment payment = paymentService.getPaymentById(id);
        log.info("读取订单: " + payment);

        if (payment==null) {
            return new CommonResult(500, "未查询到该订单,查询id: " + id);
        } else {
            return new CommonResult(200, "查询成功, serverPort: " + serverPort, payment);
        }
    }

    @GetMapping(value = "/payment/feign/timeout")
    public String PaymentFeignTimeout() {
        // 模拟较长时间的业务处理,时间为3秒
        int timeOut = 3;
        try {
            TimeUnit.SECONDS.sleep(timeOut);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "长时间业务处理:" + serverPort;
    }
}
3、构建服务消费模块80 3.1 建module

  构建一个包含服务降级hystrix的服务消费模块:cloud-consumer-order-feign-hystrix-80。改模块的环境构建可参考cloud-consumer-order-feign-80工程。

3.2 改pom

依赖包新增hystrix:spring-cloud-starter-netflix-hystrix。



    
        cloud2021
        org.example.springcloud
        1.0-SNAPSHOT
    
    4.0.0

    cloud-consumer-order-feign-hystrix-80

    
        8
        8
    

    
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
            2.2.2.RELEASE
        
        
        
            org.example.springcloud
            cloud-api-commons
            1.0-SNAPSHOT
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        

        
            org.projectlombok
            lombok
            true
            1.14.0
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

3.3 写yml

在配置文件中开启feign-hystrix属性。

server.port=8080

spring.application.name=cloud-order-service

# 添加Eureka Client配置
# 表示是否将自己注册进Eureka Server,默认为true
eureka.client.register-with-eureka=true
# 表示是否从Eureka Server抓取已有的注册信息,默认为true。
# 该配置在单节点时无所谓,集群配置时必须设置为true,才能配合ribbon使用负载均衡
eureka.client.fetchRegistry=true
#eureka.client.service-url.defaultZone=http://localhost:7001/eureka  # 单机版
eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版

# 建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ribbon.CoonecTimeout=5000
# 建立连接后从服务器读取到可用资源所用的时间
ribbon.ReadTimeout=5000

# 指定feign日志以什么级别监控哪个接口
logging.level.com.example.springcloud.service.PaymentFeignService=debug

# 开启feign-hystrix属性
feign.hystrix.enabled=true
3.4 主启动

启动类上加上启动Hystrix的注解:@EnableHystrix

package com.example.springcloud;

import cn.hutool.db.sql.Order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderHystrixMain80.class, args);
    }
}
3.5 业务类

  构建openfeign支付服务接口,直接复制服务提供模块的controller即可。
  两个接口:
  1)getPaymentById:根据id查询订单
  2)PaymentFeignTimeout:长时间业务处理接口,业务处理时间为3秒

package com.example.springcloud.service;

import com.example.springcloud.entities.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@Component
@FeignClient(value = "cloud-payment-service")
public interface PaymentHystrixService {
    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feign/timeout")
    public String PaymentFeignTimeout();
}

  构建订单服务controller,复制PaymentHystrixService即可,接口路径上添加/consumer表示是服务消费接口。
  针对服务端可能出现的长时间调用或者服务异常的情况,给每个接口添加对应的服务降级方法。
  当服务2秒后未返回,或者服务发生异常,80服务接口直接调用备选方法(fallback method)返回。

package com.example.springcloud.controller;

import com.example.springcloud.entities.CommonResult;
import com.example.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@Slf4j
public class OrderHystrixController {
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping(value = "/consumer/payment/get/{id}")
    @HystrixCommand(
            fallbackMethod = "getPaymentByIdFallbackMethod",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
            }
    )
    public CommonResult getPaymentById(@PathVariable("id") Long id) {
        return paymentHystrixService.getPaymentById(id);
    }

    @GetMapping(value = "/consumer/payment/feign/timeout")
    @HystrixCommand(
            fallbackMethod = "PaymentFeignTimeoutFallbackMethod",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
            }
    )
    public String PaymentFeignTimeout() {
        return paymentHystrixService.PaymentFeignTimeout();
    }

    // getPaymentById接口的服务降级方法
    public CommonResult getPaymentByIdFallbackMethod(@PathVariable("id") Long id) {
        String msg = "getPaymentById接口繁忙,请稍后再试,当前处理线程:" + Thread.currentThread().getName();
        return new CommonResult(500, msg);
    }

    // PaymentFeignTimeout接口的服务降级方法
    public String PaymentFeignTimeoutFallbackMethod() {
        return "PaymentFeignTimeout接口繁忙,请稍后再试,当前处理线程:" + Thread.currentThread().getName();
    }
}
3.6 测试 3.6.1 测试查看订单接口:getPaymentById

首先测试没有异常的情况,也就是id大于0的情况:http://localhost:8080/consumer/payment/get/3

  然后测试有异常的情况,也就是id小于等于0的情况:http://localhost:8080/consumer/payment/get/-3。
  可以看到当服务提供接口发生异常的时候,80接口直接返回备选方法的返回结果,而不会返回服务提供接口的异常返回信息。

3.6.2 测试长时间业务处理接口:PaymentFeignTimeout

  由于在8001接口中,我们设置的长时间业务处理有3秒。而在服务消费模块80的controller这里设置的超时时间为2s。因此调用消费服务模块的接口一定会返回备选方法的返回值。
  服务消费接口:http://localhost:8080/consumer/payment/feign/timeout
  
  根据上面的测试,我们可以得到,当服务异常或者超时的情况下,可以发生服务降级,也就是返回该服务的备选方法的结果,避免程序发生级故障,导致系统崩溃。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737119.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号