SpringCloud学习笔记7——初级篇之服务降级

19 篇文章 0 订阅
16 篇文章 0 订阅

六.Hystrix

Hystrix官方宣布,停止更新,进入维护阶段,但Hystrix非常优秀,属“业界标杆”

1.Hystrix断路器知识点

在这里插入图片描述
在这里插入图片描述

能做的事:服务降级、服务熔断、接近实时的监控等。

①服务降级fallback

服务器忙,稍后再试。不让客户端等待并立刻返回一个友好提示。

在这里插入图片描述

②服务熔断break

达到最大服务访问后,直接拒绝访问,调用服务降级的方法并返回友好提示。

③服务限流flowlimit

秒杀高并发等操作,严禁一窝蜂拥挤,大家排队,一秒钟限制N个,有序进行

2.构建项目

先确定7001为单机版。

①创建module

在这里插入图片描述

②编写pom文件
<dependencies>

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

        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--引入自定义的api通用包  可以使用公用的entities-->
        <dependency>
            <groupId>com.hry.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
③修改yml文件
server:
  port: 8001

spring:
  application:
    name: cloud-provider-hystrix-payment

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
④创建主启动类
package com.hry.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
}

⑤业务代码

service层

package com.hry.springcloud.service;

public interface PaymentService {
    public String paymentInfo_OK(Integer id);

    public String paymentInfo_TimeOut(Integer id);
}

package com.hry.springcloud.service.impl;

import com.hry.springcloud.service.PaymentService;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class PaymentServiceImpl implements PaymentService {
    /**
     * 正常访问
     * @param id
     * @return
     */
    @Override
    public String paymentInfo_OK(Integer id) {
        String s = "线程池:"+Thread.currentThread().getName()+ "  paymentInfo_OK,id:"+id+"\t";
        return s;
    }

    /**
     * 超时访问
     * @param id
     * @return
     */
    @Override
    public String paymentInfo_TimeOut(Integer id) {
        int time = 3;
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String s = "线程池:"+Thread.currentThread().getName()+ "  paymentInfo_TimeOut,id:"+id+"\t"+"耗时"+time+"s";
        return s;
    }
}

controller层

package com.hry.springcloud.controller;

import com.hry.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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 PaymentController {

    @Resource
    private PaymentService paymentService;

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

    @GetMapping(value = "/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentService.paymentInfo_OK(id);
        log.info("*****result:"+result);
        return result;
    }

    @GetMapping(value = "/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("*****result:"+result);
        return result;
    }

}

⑥测试

依次启动7001和新8001
这里ok正常是秒刷新的。
在这里插入图片描述
在这里插入图片描述

⑦压力测试

使用Jmeter
在这里插入图片描述
在这里插入图片描述
当我们使用压力测试对timeout施压时,ok也会受到影响。
这时我们刷新ok看效果
在这里插入图片描述
发现当高线程访问timeout时ok也会受到影响,从原来的秒刷新到现在的需要等待。

由此,8001自测都不能通过。你以为这就完了?下面再建一个order80消费者访问这个8001服务提供者。

3.构建项目

①创建module

在这里插入图片描述

②编写pom文件
<dependencies>
        <!-- openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

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

        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--引入自定义的api通用包  可以使用公用的entities-->
        <dependency>
            <groupId>com.hry.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
③修改yml文件
server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
④创建主启动类
package com.hry.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

⑤业务代码

service层

package com.hry.springcloud.service;

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-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
    @GetMapping(value = "/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping(value = "/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}

controller层

package com.hry.springcloud.controller;

import com.hry.springcloud.service.PaymentHystrixService;
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/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping(value = "/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
}

⑥测试

启动新80
在这里插入图片描述
把Jmeter跑起来
访问发现也需要等待了,甚至多访问几次出现error page页面报错
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.服务降级

①修改8001

在这里插入图片描述

(1)修改service层

添加

public String PaymentInfo_TimeOutHandler(Integer id);

修改与添加

/**
 * 超时访问
 * fallbackMethod:指定方法名:PaymentInfo_TimeOutHandler 来处理
 * value指定时间为2s
 */
@HystrixCommand(fallbackMethod = "PaymentInfo_TimeOutHandler",commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@Override
public String paymentInfo_TimeOut(Integer id) {
    int time = 3;
    try {
        TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    String s = "线程池:"+Thread.currentThread().getName()+ "  paymentInfo_TimeOut,id:"+id+"\t"+"耗时"+time+"s";
    return s;
}

/**
 * 用于处理fallback
 * @param id
 * @return
 */
@Override
public String PaymentInfo_TimeOutHandler(Integer id) {
    String s = "线程池:"+Thread.currentThread().getName()+ "  TimeOutHandler,id:"+id+"\t"+"o(╥﹏╥)o";
    return s;
}

这里的"execution.isolation.thread.timeoutInMilliseconds",value = “2000” 设置了超时2s,而下面int time还是3s.

(2)修改主启动类

添加注解

@EnableCircuitBreaker
(3)测试

测试发现当超时3s超过我们设置的2s时就会走我们的Handler方法。
在这里插入图片描述
运行异常和超时异常都会走这个方法
在这里插入图片描述

②修改80
(1)修改yml文件

添加配置

feign:
  hystrix:
    enabled: true
(2)修改主启动类

添加注解

@EnableHystrix
(3)添加和修改controller
/**
     * 超时访问
     * fallbackMethod:指定方法名:PaymentInfo_TimeOutHandler 来处理
     * value指定时间为2s
     */
    @HystrixCommand(fallbackMethod = "PaymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    @GetMapping(value = "/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        String s = paymentHystrixService.paymentInfo_TimeOut(id);
        return s;
    }

    /**
     * 用于处理fallback
     * @param 
     * @return
     */

    public String PaymentInfo_TimeOutHandler() {
        String s = "消费者80出错啦!!!!!!!! 支付系统8001繁忙,请稍后再试";
        return s;
    }
(4)将8001改回正常状态

80设置了超时为2s,而8001休眠了3s显然 802s后不会再等待8001了,因此自身出错走下面的fallback方法打印消费者80出错啦!

在测试之前需要回到8001service层修改注解上的超时时间 改成大于3s 比如设置为5000
在这里插入图片描述
在这里插入图片描述

(5)测试

当我们准备通过客户端访问支付服务端时,报了一个错,提示我们没有找到我们的handler,原因是:fallback方法参数列表必须与加了注解的方法参数列表一致
在这里插入图片描述
我们加入参数

 public String PaymentInfo_TimeOutHandler(@PathVariable("id") Integer id) 

在这里插入图片描述
修改后重启80继续测试。
看到成功打印了handler中的语句。
这就是客户端80访问服务端8001时由于响应超过期待的2s的情况。
在这里插入图片描述
同理运行时出错也会直接跳到自己的fallback方法中。例如在代码最前面加一行

int a = 1/0;

还没去调用服务端8001,也不涉及超时,就已经报错,也会进入我们的兜底方法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值