Springcloud之负载均衡、熔断器

SpringCloud----Eureka(一)
SpringCloud—Fegin、Gateway、分布式配置中心、Bus服务总线

1.负载均衡Ribbon

Springcloud之负载均衡、熔断器_第1张图片

1.1.案例

在user-service中设置端口:
Springcloud之负载均衡、熔断器_第2张图片

复制一个新的application,端口号设为9092

Springcloud之负载均衡、熔断器_第3张图片

启动Eureka:

Springcloud之负载均衡、熔断器_第4张图片

1.2.开启负载均衡

在consumer中加入LoadBalanced注解:
Springcloud之负载均衡、熔断器_第5张图片

修改controller,不再手动获取ip和端口,而是直接通过服务名称调用:

Springcloud之负载均衡、熔断器_第6张图片

1.3.负载均衡的策略

类名:RibbonLoadBalanceClient。

方法名:choose()

默认方法是轮询。

修改负载均衡配置规则(将轮询修改为随机):

user-service:
	ribbon: 
	NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

2.熔断器Hystix

Hystix是Netflflix开源的一个延迟和容错库,用于隔离访问远程服务,防止出现级联失败。

Hystrix解决雪崩问题的手段,主要包括:

  • 线程隔离
  • 服务降级

线程隔离

Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队,加 速失败判定时间。

用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超 时,则会进行降级处理,什么是服务降级?

服务降级:可以优先保证核心服务

用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,至少可以看到一个执行结果(例如返回 友好的提示信息) 。

服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它

服务没有响应。 触发Hystrix服务降级的情况:

  • 线程池已满
  • 请求超时

服务降级实操:

在consumer中进行下列操作:

导入依赖:

<dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
        dependency>

在application中加入注解:

package com.java.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

//@SpringBootApplication
//@EnableDiscoveryClient //开启Eureka客户端
//@EnableCircuitBreaker //开启熔断
@SpringCloudApplication  //可以代替上方三个注解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return  new RestTemplate();
    }
}

在controller中添加服务降级逻辑:

主要是加入queryByIdFallback方法以及加入@HystrixCommand(fallbackMethod = “queryByIdFallback”)注解。@HystrixCommand(fallbackMethod = “queryByIdFallBack”):用来声明一个降级逻辑的方法

package com.java.consumer.controller;

import com.java.consumer.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @Author: YNB
 * @Description:
 * @Date Created in 2021-01-11 20:56
 * @Modified By:
 */
@RestController
@RequestMapping("/consumer")
@Slf4j
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/{id}")
    @HystrixCommand(fallbackMethod = "queryByIdFallback")  //设置为下方的queryByIdFallback方法名
    public String queryById(@PathVariable Long id) {
//        String url = "http://localhost:9091/user/" + id;   // http://localhost:9091/user/ 是userservice的地址

//        List serviceInstanceList = discoveryClient.getInstances("user-service");
//        ServiceInstance serviceInstance = serviceInstanceList.get(0);
//        String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
        String url = "http://user-service/user/" + id;
        return restTemplate.getForObject(url, String.class);
    }

    public String queryByIdFallback(Long id) {
        log.error("查询用户信息失败。id:{}", id);
        return "对不起,网络太拥挤了!";
    }
}

效果:

在这里插入图片描述

设置默认fallback:

将Fallback配置加载类上

package com.java.consumer.controller;

import com.java.consumer.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @Author: YNB
 * @Description:
 * @Date Created in 2021-01-11 20:56
 * @Modified By:
 */
@RestController
@RequestMapping("/consumer")
@Slf4j
@DefaultProperties(defaultFallback = "defaultFallback")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/{id}")
//    @HystrixCommand(fallbackMethod = "queryByIdFallback")  //设置为下方的queryByIdFallback方法名
    @HystrixCommand
    public String queryById(@PathVariable Long id) {
//        String url = "http://localhost:9091/user/" + id;   // http://localhost:9091/user/ 是userservice的地址

//        List serviceInstanceList = discoveryClient.getInstances("user-service");
//        ServiceInstance serviceInstance = serviceInstanceList.get(0);
//        String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
        String url = "http://user-service/user/" + id;
        return restTemplate.getForObject(url, String.class);
    }

    public String queryByIdFallback(Long id) {
        log.error("查询用户信息失败。id:{}", id);
        return "对不起,网络太拥挤了!";
    }

    public String defaultFallback() {
        return "默认提示:对不起,网络太拥挤了!";
    }
}

效果:
Springcloud之负载均衡、熔断器_第7张图片

超时设置:

设置yml文件:

spring:
  application:
    name: consumer-demo
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 30
#超时设置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

3.服务熔断

3.1.熔断原理

在服务熔断中,使用的熔断器,也叫断路器,其英文单词为:Circuit Breaker 熔断机制与家里使用的电路熔断原理类似;当如果电路发生短路的时候能立刻熔断电路,避免发生灾难。在分布式系统中应用服务熔断后;服务调用方可以自己进行判断哪些服务反应慢或存在大量超时,可以针对这些服务进行主动熔断,防止整个系统被拖垮。Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打开,拒绝请求的服务

Hystrix的熔断状态机模型:

Springcloud之负载均衡、熔断器_第8张图片

3.2.实操

consumer中进行修改:

加入一个id=1就会抛出异常的逻辑。

package com.java.consumer.controller;

import com.java.consumer.pojo.User;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @Author: YNB
 * @Description:
 * @Date Created in 2021-01-11 20:56
 * @Modified By:
 */
@RestController
@RequestMapping("/consumer")
@Slf4j
@DefaultProperties(defaultFallback = "defaultFallback")
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/{id}")
//    @HystrixCommand(fallbackMethod = "queryByIdFallback")  //设置为下方的queryByIdFallback方法名
    @HystrixCommand
    public String queryById(@PathVariable Long id) {
//        String url = "http://localhost:9091/user/" + id;   // http://localhost:9091/user/ 是userservice的地址

//        List serviceInstanceList = discoveryClient.getInstances("user-service");
//        ServiceInstance serviceInstance = serviceInstanceList.get(0);
//        String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/user/" + id;
        if (id == 1){
            throw   new RuntimeException("!!!!!!");
        }
        String url = "http://user-service/user/" + id;
        return restTemplate.getForObject(url, String.class);
    }

    public String queryByIdFallback(Long id) {
        log.error("查询用户信息失败。id:{}", id);
        return "对不起,网络太拥挤了!";
    }

    public String defaultFallback() {
        return "默认提示:对不起,网络太拥挤了!";
    }
}

执行:

id=1:

Springcloud之负载均衡、熔断器_第9张图片

id=2:

Springcloud之负载均衡、熔断器_第10张图片

当执行多次id=1失败之后,在执行id=2:

Springcloud之负载均衡、熔断器_第11张图片

等待几秒后恢复正常。

spring:
  application:
    name: consumer-demo
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 30
#超时设置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds:  2000 #服务降级超时时间
        circuitBreaker:
          errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
          sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
          requestVolumeThreshold: 10 # 熔断触发最小请求次数,默认值是20

案例地址

你可能感兴趣的:(Java学习笔记,负载均衡,java,spring,cloud)