springcloud(六) Hystrix 熔断,限流

Easter79
• 阅读 511

Hystrix 熔断:

  首先仍然启动Eureka,这里就不说了。

OrderController.java:

package com.tuling.cloud.study.user.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.tuling.cloud.study.user.entity.User;

@RestController
public class OrderController {
  private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
  @Autowired
  private RestTemplate restTemplate;
  

  @HystrixCommand(fallbackMethod = "findByIdFallback")
  @GetMapping("/user/{id}")
  public User findById(@PathVariable Long id) {
    logger.error("================请求用户中心接口,用户id:" + id + "==============");
    return restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
  }

  //降级方法
  public User findByIdFallback(Long id) { 
    User user = new User();
    user.setId(-1L);
    user.setName("默认用户");
    return user;
  }

}

order 服务和上一章一样唯一修改的是yml文件:

server:
  port: 9010
spring:
  application:
    name: microservice-consumer-order
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
hystrix:
  command:
    default:
      circuitBreaker:
        requestVolumeThreshold: 3 #默认20,熔断的阈值,如何user服务报错满足3次,熔断器就会打开,就算order之后请求正确的数据也不行。
        sleepWindowInMilliseconds: 5000 #默认5S , 等5S之后熔断器会处于半开状态,然后下一次请求的正确和错误讲决定熔断器是否真的关闭和是否继续打开

user服务修改UserController.java其余不变

package com.tuling.cloud.study.controller;

import java.util.Random;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.tuling.cloud.study.entity.User;
import com.tuling.cloud.study.repository.UserRepository;

@RestController
public class UserController {
    
  private final Logger logger = Logger.getLogger(getClass());
    
  @Autowired
  private UserRepository userRepository;
  @Autowired
  private Registration registration;
  

  @GetMapping("/{id}")
  public User findById(@PathVariable Long id) throws Exception {
      logger.info("用户中心接口:查询用户"+ id +"信息");
      //测试熔断,传入不存在的用户id模拟异常情况
      if (id == 10) {
        throw new NullPointerException();
      }
      User findOne = userRepository.findOne(id);
      return findOne;
  }
  
  @GetMapping("/getIpAndPort")
  public String findById() {
      return registration.getHost() + ":" + registration.getPort();
  }
}

user服务模拟接口报错,order服务在调用的时候如果id传入的是10 ,就会导致user服务报错,那么满足3次报错之后,熔断器就会打开。注意:之后在5S内浏览器继续请求order服务的findById()接口是不会进入的,hystrix会直接执行降级方法。

等5S过去之后,hytrix不会全打开,而是处于半开状态,接下来的第一个请求决定熔断器是否继续打开,还是关闭。

演示:

springcloud(六) Hystrix 熔断,限流

特别注意“:user服务报错满足3次,就导致调用方order的 findById() 进不去了,而是直接进入降级方法。这就是熔断。

Hystrix 限流:

Eureka 还是用同样的(略)

order工程截图:

springcloud(六) Hystrix 熔断,限流

pom.xml 和上一章一样(略)

OrderController.java:

package com.jiagoushi.cloud.study.user.controller;

import com.jiagoushi.cloud.study.user.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

@RestController
public class OrderController {

    private static final Logger logger = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "findByIdFallback", 
                    groupKey = "orderUserGroup", 
                    threadPoolKey = "orderUserIdThreadPool", 
                    threadPoolProperties = {
                        @HystrixProperty(name = "coreSize", value = "2"), 
                        @HystrixProperty(name = "maxQueueSize", value = "2"),
                        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "1") }) //maxQueueSize和queueSizeRejectionThreshold 简单理解两者取最小值做为队列长度
    @GetMapping("/user/{id}")
    public User findById(@PathVariable Long id) {
        logger.info("================请求用户中心接口,用户id:" + id + "==============");
        return restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
    }

    @HystrixCommand(fallbackMethod = "findByIdFallback",
            groupKey = "orderUserGroup",
            threadPoolKey = "orderUserIdThreadPool",
            threadPoolProperties = {
                    @HystrixProperty(name = "coreSize", value = "2"), //配置线程池线程数量
                    @HystrixProperty(name = "maxQueueSize", value = "2"),
                    @HystrixProperty(name = "queueSizeRejectionThreshold", value = "1") })
    @GetMapping("/user/{userName}")
    public User findByUserName(@PathVariable String userName) {
        logger.info("================请求用户中心接口,用户userName:" + userName + "==============");
        return restTemplate.getForObject("http://microservice-provider-user/" + userName, User.class);
    }

    //降级方法
    public User findByIdFallback(Long id) {
        User user = new User();
        user.setId(-1L);
        user.setName("默认用户");
        return user;
    }
    
}

说明:

  1. hystix 默认线程池大小是10。
  2. groupKey 是 服务分组 , threadPoolKey 是 线程池标识 , 也就是说当groupKey和threadPoolKey 同时修饰findById() 和findByUserName() 时 ,他们共用一个线程池,大小共10。
  3. ThreadPoolProperties:配置线程池参数,coreSize配置核心线程池大小和线程池最大大 小,keepAliveTimeMinutes是线程池中空闲线程生存时间(如果不进行动态配置,那么是没 有任何作用的),maxQueueSize配置线程池队列最大大小, queueSizeRejectionThreshold限定当前队列大小,即实际队列大小由这个参数决定,通过 改变queueSizeRejectionThreshold可以实现动态队列大小调整。

applciation.xml:

server:
  port: 9010
spring:
  application:
    name: microservice-consumer-order
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 20000 #命令执行超时时间,默认1000ms,就是调接口的响应时间超过20S就执行降级,不管提供者是否挂机还是延迟超过时间就走降级

user工程截图:

springcloud(六) Hystrix 熔断,限流

pom.xml 和上一章一样(略)

UserController.java:

package com.jiagoushi.cloud.study.controller;

import com.jiagoushi.cloud.study.entity.User;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.jiagoushi.cloud.study.repository.UserRepository;

@RestController
public class UserController {
    
  private final Logger logger = Logger.getLogger(getClass());
    
  @Autowired
  private UserRepository userRepository;
  @Autowired
  private Registration registration;
  

  @GetMapping("/{id}")
  public User findById(@PathVariable Long id) throws Exception {
      logger.info("用户中心接口:查询用户"+ id +"信息");
      // 配合限流演示,模拟业务耗时3S
         Thread.sleep(3000);
      User findOne = userRepository.findOne(id);
      return findOne;
  }
  
  @GetMapping("/getIpAndPort")
  public String findById() {
      return registration.getHost() + ":" + registration.getPort();
  }
}

  application.yml:

server:
  port: 8002
spring:
  application:
    name: microservice-provider-user
  jpa:
    generate-ddl: false
    show-sql: true
    hibernate:
      ddl-auto: none
  datasource:                           # 指定数据源
    platform: h2                        # 指定数据源类型
    schema: classpath:schema.sql        # 指定h2数据库的建表脚本
    data: classpath:data.sql            # 指定h2数据库的数据脚本
logging:                                # 配置日志级别,让hibernate打印出执行的SQL
  level:
    root: INFO
    org.hibernate: INFO
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
    org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

  使用jemeter 来演示 hystrix 的限流:

先默认order接口什么都不配置:

springcloud(六) Hystrix 熔断,限流

上图:

springcloud(六) Hystrix 熔断,限流 springcloud(六) Hystrix 熔断,限流

 springcloud(六) Hystrix 熔断,限流

结果发现: 12个线程有10成功,2个被降级处理,说明hystrix 默认的线程池大小是10,

接下来配置一下order接口:

springcloud(六) Hystrix 熔断,限流

上图:

springcloud(六) Hystrix 熔断,限流

 结果发现:12个线程访问只有3个成功,9个被降级。因为hystrix 线程池被配置成2个,队列长度1,所以9个线程立即被降级。

 springcloud(六) Hystrix 熔断,限流 就好比商品详情服务一共100个线程,只允许20线程可以调用评论接口,如果并发是50,那么其他30就被降级,线程就立即回收,防止服务雪崩

 欢迎来QQ群:592495675 搞事情

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k