Hystrix 官网也是停更了,但是设计理念是后序别的框架的基础

为什么要有Hystrix呢 ?
因为多个微服务的调用,一个如果超时,会让其他的微服务都需要等待,这样一来,一个微服务的性能下降,就影响了与之关联的很多个服务,这不是我们想看到的。所以Hystrix出现了,将服务降级,熔断,限流。来保证每个服务的正常使用。

现实场景:10086 坐席忙
家里的电闸。保险。
什么时候派上用场呢
1.服务发生异常
2。超时
3,线程池满了。

为了测试方便,我们先将集群变成单机

新建一个8001 的项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud</artifactId>
        <groupId>com.home</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hystrix8001</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>
                mybatis-spring-boot-starter
            </artifactId>
        </dependency>
        <dependency>
            <artifactId>common</artifactId>
            <groupId>com.home</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--<dependency>-->

            <!--<groupId>com.alibaba</groupId>-->
            <!--<artifactId>druid-spring-boot-starter</artifactId>-->
            <!--<version>1.1.9</version>-->
        <!--</dependency>-->
        <!--<dependency>-->
            <!--<groupId>mysql</groupId>-->
            <!--<artifactId>mysql-connector-java</artifactId>-->
        <!--</dependency>-->
        <!--<dependency>-->
            <!--<groupId>org.springframework.boot</groupId>-->
            <!--<artifactId>spring-boot-starter-jdbc</artifactId>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    </dependencies>


</project>

加了一个hystrix的依赖

controller

package home.controller;

import home.entity.MyResult;
import home.entity.Pay;
import home.service.PaySer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class PayCon {
    @Autowired
    PaySer paySer;

    @Autowired
    DiscoveryClient discoveryClient;

    @GetMapping(value = "/hystrix/ok/{id}")
    public String ok(@PathVariable(value = "id") int id) {
        return paySer.ok(id);

    }

    @GetMapping(value = "/hystrix/notok/{id}")
    public String notok(@PathVariable(value = "id") int id) {
        return paySer.notok(id);
    }
}

service

package home.service;

import home.entity.MyResult;
import home.entity.Pay;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class PaySer {
@Value("${server.port}"

)
    String port;
    public String ok(int id) {
        return "线程:"+Thread.currentThread().getName()+"ok:"+id+"o(∩_∩)o 哈哈";



    }

    public String notok(int id) {
        int n = 5;
        try {
            TimeUnit.SECONDS.sleep(n);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程:"+Thread.currentThread().getName()+"notok:"+id+"o(∩_∩)o 哈哈"+"耗时"+n+"秒";



    }

}

在自己测试的情况下,一切都是正常的,如果我们用jmeter 设置每秒200 个线程,循环100次,访问notok的,同时访问ok的,ok的也会变成转圈的状态。在高并发的情况下,原来的方式是有问题的。客户体验差

我们建了一个新的项目hystrix的80,这个80是复制的之前的项目open80
The bean ‘PAY-SERVICE.FeignClientSpecification’ could not be registered. A b 会报出这样一个错误 怎么处理?
其原因是idea中,如果复制项目,要将 .iml文件删除。

80 改造 controller

package home.controller;

import com.netflix.discovery.converters.Auto;
import home.entity.MyResult;
import home.entity.Pay;
import home.lb.Lb;
import home.service.FiegnService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.ResponseEntity;
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 java.util.List;

@RestController
@Slf4j
public class OpenCon {

@Autowired
    FiegnService fiegnService;


    @GetMapping(value = "/consumer/hystrix/notok/{id}")
    public String notok(@PathVariable(value = "id") int id){
        return fiegnService.notok(id);

    }

    @GetMapping(value = "/consumer/hystrix/ok/{id}")
    public String ok(@PathVariable(value = "id") int id){
        return  fiegnService.ok(id);

    }
}

service

package home.service;

import home.entity.MyResult;
import home.entity.Pay;
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;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@Component
@FeignClient(value = "PAY-SERVICE")
public interface FiegnService {
    @GetMapping(value = "/hystrix/ok/{id}")
    public String ok(@PathVariable(value = "id") int id);

    @GetMapping(value = "/hystrix/notok/{id}")
    public String notok(@PathVariable(value = "id") int id);
}

8001 改造controller

package home.controller;

        import home.entity.MyResult;
        import home.entity.Pay;
        import home.service.PaySer;
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.cloud.client.ServiceInstance;
        import org.springframework.cloud.client.discovery.DiscoveryClient;
        import org.springframework.web.bind.annotation.*;

        import java.util.Arrays;
        import java.util.List;
        import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class PayCon {
    @Autowired
    PaySer paySer;

    @Autowired
    DiscoveryClient discoveryClient;

    @GetMapping(value = "/hystrix/ok/{id}")
    public String ok(@PathVariable(value = "id") int id) {
        return paySer.ok(id);

    }

    @GetMapping(value = "/hystrix/notok/{id}")
    public String notok(@PathVariable(value = "id") int id) {
        return paySer.notok(id);
    }
}

service 8001

package home.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import home.entity.MyResult;
import home.entity.Pay;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.naming.Name;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class PaySer {
    @Value("${server.port}"

    )
    String port;

    public String ok(int id) {
        return "线程:" + Thread.currentThread().getName() + "ok:" + id + "o(∩_∩)o 哈哈";


    }

    @HystrixCommand(fallbackMethod = "notokHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String notok(int id) {
        int n = 5;
        try {
            TimeUnit.SECONDS.sleep(n);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程:" + Thread.currentThread().getName() + "notok:" + id + "o(∩_∩)o 哈哈" + "耗时" + n + "秒";


    }


    public String notokHandler(int id) {
        return "线程:" + Thread.currentThread().getName() + "notokhandler:" + id + "(┬_┬)";

    }
}

最重要的就是这一步,我们要在service的方法上加上@HystrixCommand(fallbackMethod = “notokHandler”, commandProperties = {@HystrixProperty(name = “execution.isolation.thread.timeoutInMilliseconds”, value = “3000”)})

注解
在主方法上也要做配合的注解

package home;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker
public class
Hystrix8001 {
    public static void main(String[] args) {
        SpringApplication.run(Hystrix8001.class, args);
    }
}

@EnableHystrix 这个注解也行。
@EnableCircuitBreaker 这个注解让@hystrixconmmond注解生效。

发生异常的时候测试

  @HystrixCommand(fallbackMethod = "notokHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String notok(int id) {
//        int n = 5;
//        try {
//            TimeUnit.SECONDS.sleep(n);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        int num = 10/0;
//        return "线程:" + Thread.currentThread().getName() + "notok:" + id + "o(∩_∩)o 哈哈" + "耗时" + n + "秒";
        return "线程:" + Thread.currentThread().getName() + "notok:" + id + "o(∩_∩)o 哈哈" + "耗时";


    }

也会走fallback方法。

因为以上每个方法都要配置一个fallback 这样代码太多了
可以在类上配置一个默认的fallback ,但是这个fallback方法有个特点,不要有入参。否则找不到。方法。

package home.controller;

import com.netflix.discovery.converters.Auto;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import home.entity.MyResult;
import home.entity.Pay;
import home.lb.Lb;
import home.service.FiegnService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.ResponseEntity;
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 java.util.List;

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "allerrer")
public class OpenCon {

@Autowired
    FiegnService fiegnService;


    @GetMapping(value = "/consumer/hystrix/notok/{id}")
    @HystrixCommand(fallbackMethod = "notokHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    public String notok(@PathVariable(value = "id") int id){
        return fiegnService.notok(id);

    }
    public String notokHandler(int id) {
        return "客户端controller比你更早的超时了(┬_┬)";

    }

    @GetMapping(value = "/consumer/hystrix/ok/{id}")
    @HystrixCommand
    public String ok(@PathVariable(value = "id") int id){int n = 10/0;
        return  fiegnService.ok(id);

    }

    public String allerrer() {
        return "all超时了(┬_┬)";

    }
}

这样就解决了代码的冗余,而且可以和单独的定制共存。

解决了冗余的问题又引出了一个问题
业务代码和fallback
代码在一起混合,有没有解决方法呢?
因为你要用feignclient客户端来通过接口的方式调用。我们可以利用接口。
其实这种方法主要是利用feign 集成的hystrix 来处理。
这种是熔断:
我们需要建立一个实现类

package home.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
public class FiegnServiceimpl implements FiegnService {

    @Override
    public String ok(int id) {
        return "ok method  fallback  (┬_┬)";
    }

    @Override
    public String notok(int id) {
        return "ok method  fallback  (┬_┬)";

    }
}

还需要接口上配置一下这个类

package home.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import home.entity.MyResult;
import home.entity.Pay;
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;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@Component
@FeignClient(value = "PAY-SERVICE",fallback = FiegnServiceimpl.class)
public interface FiegnService {
    @GetMapping(value = "/hystrix/ok/{id}")
    public String ok(@PathVariable(value = "id") int id);

    @GetMapping(value = "/hystrix/notok/{id}")
    public String notok(@PathVariable(value = "id") int id);


}

主要是fallback的配置。

在yml中配置

feign:
  hystrix:
    enabled: true

#开启熔断
feign.hystrix.enabled=true
#是否开启超时熔断, 如果为false, 则熔断机制只在服务不可用时开启
hystrix.command.default.execution.timeout.enabled=true
# 设置超时熔断时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000

上面一些是参数的说明,其实是熔断,并不是直接的降级。测试需要将8001关闭,模拟宕机。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值