SpringCloud 学习笔记总结 (四)

git代码地址:https://gitee.com/it-sherlock/java-project-template

1. OpenFeign 之 介绍


OpenFeign官方地址:https://spring.io/projects/spring-cloud-openfeign/

OpenFeign Github官方地址:https://github.com/spring-cloud/spring-cloud-openfeign

feign英文翻译:假装,佯装。

Feign是一个声明式WebService客户端,让编写Web服务客户端变得非常容易,只需要创建一个接口并在接口上添加注解即可。

之前是通过ribbon + restTemplate方式封装处理,形成一套模板化的调用方法。

现在,feign集成了ribbon,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

现在OpenFeign已经取代了Feign:
在这里插入图片描述

2. OpenFeign 之 消费端的 服务调用


feign是定义在消费端的。

简单说就是,更加简便了:只需要 微服务调用接口 + @FeignClient注解,就能实现。


第一步:添加OpenFeign的依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

第二步:主启动类,添加激活feign的注解@EnableFeignClients:

package com.itholmes.springcloud;

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

@SpringBootApplication
@EnableFeignClients//使用feign,激活开启feign
public class OrderFeignMain80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}

第三步:写一个service接口,配置好@FeignClient注解对应。

package com.itholmes.springcloud.service;

import com.itholmes.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 PaymentFeignService {
    
    
    /**
     * 这时候就是去注册中心找一个CLOUD-PAYMENT-SERVICE名称的微服务加上对应地址。
     */
    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id);
}

在这里插入图片描述

3. OpenFeign 之 超时控制


OpenFeign默认等待1秒钟,超过后就报错read time out。
在这里插入图片描述

# 设置feign 客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  # 指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  # 指的是进建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

4. OpenFeign 之 日志增强


Feigon 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。对Feign接口的调用情况进行监控和输出。

OpenFeign的日志级别:
在这里插入图片描述


配置类设置日志级别:

package com.itholmes.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    
    

    //设置日志级别
    @Bean
    Logger.Level feignLoggerLevel(){
    
    
        return Logger.Level.FULL;
    }

}

feign日志以什么级别监控那个接口:

server:
  port: 80

eureka:
  client:
    # 表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    # 入驻地址是哪个
    service-url:
      #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      #defaultZone: http://localhost:7001/eureka #单机版
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  #集群版

# 设置feign 客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  # 指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  # 指的是进建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.itholmes.springcloud.service.PaymentFeignService: debug

日志如下:
在这里插入图片描述

5. Hystrix 之 重要概念


分布式系统面临的问题:

  • 相互之间都是微服务调用,一个过程,可能要走好多微服务系统,其中一个微服务系统出现问题,整个过程就相当于失败了。

服务雪崩:

  • 多个微服务相互依赖调用的时候,微服务A调用微服务B,微服务B调用微服务C,微服务C有调用其他微服务,这就是扇出效果(像一把扇子,不断张开)
  • 如果一个微服务出现了问题(超时,宕机等等),例如:微服务C宕机了,那么微服务B就会不断堆积请求(请求的线程阻塞),微服务B占用越来越多的系统资源,进而微服务B系统也崩溃了,微服务B崩溃了,同样A也会不断堆积进而崩溃掉,这就是雪崩效果。

为了解决上面的问题,就有了熔断降级的思想。

Hystrix是一个用于处理分布式系统的延迟 和 容错的开源库。

在分布式系统里,许多依赖不可避免的会调用失败,比如:超时,异常等。

Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。


断路器:(熔断保险丝)
在这里插入图片描述

官方地址:https://github.com/Netflix/Hystrix


服务降级:

  • 就是返回一个友好提示(fallback),例如:服务器忙,请稍后再试;不让客户端等待并且立刻返回一个友好提示(fallback)。

那些情况下会触发降级:

  • 程序运行异常。
  • 超时。
  • 服务熔断触发服务降级。
  • 线程池 / 信号量 打满也会导致服务降级。

服务熔断:

  • 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。
  • 熔断过程:服务降级 -》 进而熔断 -》 恢复调用链路

服务限流:

  • 像秒杀,高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行,这就是服务限流。

6. jmeter 普通服务测试


使用jmeter来测试。

在这里插入图片描述
在线程组里面,设定200个线程,1秒内发送请求,循环100次。之后,再次通过浏览器访问两个接口,都有严重的卡顿。

原因就是:tomcat的默认工作线程数被打满了,没有多余的线程来分担压力和处理。

在这里插入图片描述
这样就是雪崩效应。

7. Hystrix 之 服务提供 和 服务消费 环境搭建


第一步:导入hystrix依赖:

<!--添加eureka-client客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--添加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>

第二步:搭建好SpringBoot项目。

第三步:使用openFeign,链接好消费者和提供者之间的调用。

第四步:使用Jmeter来测试,高并发的请求。

  • 通过测试,不难看出,一旦高并发的请求进来,就会导致严重的卡顿。

解决思想:
在这里插入图片描述

如何解决上面问题:
在这里插入图片描述

8. Hystrix 之 服务降级 消费端和服务端


官方github文档使用方式是通过程序:
在这里插入图片描述


这里使用@HystrixCommand注解:

@HystrixCommand报异常后的处理过程:

  • 一旦调用服务方法失败,并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法。

服务端降级代码如下:

第一步:service层逻辑代码:

package com.itholmes.springcloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class PaymentService {
    
    

    public String paymentInfo_OK(Integer id){
    
    
        return "线程池: " + Thread.currentThread().getName() + "paymentInfo_OK,id:"+id+"\t"+"hello,world";
    }

    //一旦调用服务方法失败,并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法。
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
    
    
        // 超过3秒走兜底的错误方法。
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id){
    
    
        int timeNumber = 5;
        //无论是异常还是其他的,都会引起指定的兜底方法执行。
		//int age = 10/0;
        try {
    
    
            TimeUnit.SECONDS.sleep(timeNumber);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "线程池: " + Thread.currentThread().getName() + "paymentInfo_OK,id:"+id+"\t"+"hello,world。"+"耗时(秒)"+timeNumber+"秒钟";
    }

	// 被上面指定兜底的方法
    public String paymentInfo_TimeOutHandler(Integer id){
    
    
        return "线程池: " + Thread.currentThread().getName() + "8001系统繁忙,请稍后再试,id:"+id+"\t"+"GG.";
    }
    
}

第二步:主启动类,添加注解@EnableCircuitBreaker。

package com.itholmes.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

这样,当我们访问这个服务提供者就会有兜底方法来帮我们处理超时,异常等情况。


客户端服务降级代码如下:

  • 一般我们在客户端进行服务降级!

第一步:因为客户端是通过openfeign来调用的,所以在feign要开启hystrix。

server:
  port: 80

eureka:
  client:
    # 表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    # 入驻地址是哪个
    service-url:
      #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka #单机版
      # defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  #集群版
ribbon:
  ReadTimeout: 5000
  ConnectTimeout: 5000

# 在feign中开启hystrix
feign:
  hystrix:
    enabled: true

第二步:主启动类上面添加@EnableHystrix注解。

package com.itholmes.springcloud;

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);
    }
}

第三步:对于消费端(客户端),一般采用openfeign调用服务端,注解@HystrixCommand也配置在了controller层中。

package com.itholmes.springcloud.controller;

import com.itholmes.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
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
public class PaymentHystrixController {
    
    
    @Resource
    private PaymentHystrixService paymentHystrixService;

    /**
     * 这里与服务端不同!
     *  服务端在service层添加的@HystrixCommand注解。
     *  在openfeign的消费端,是在controller层添加@HystrixCommand注解。
     */
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
    
    
            // 超过3秒走兜底的错误方法。
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

    public String paymentTimeOutFallbackMethod(@PathVariable("id")Integer id){
    
    
        return "我是消费者80,对方支付系统繁忙或自身运行出错!";
    }
}

9. Hystrix 之 全局服务降级@DefaultProperties


如果想要统一的有一个兜底的代码来处理,也就是全局服务降级的效果。

使用@DefaultProperties(defaultFallback = “”) 来实现。
在这里插入图片描述


@DefaultProperties(defaultFallback = “”) 注解的使用如下:

package com.itholmes.springcloud.controller;

import com.itholmes.springcloud.service.PaymentHystrixService;
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 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
//指名全局
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class PaymentHystrixController {
    
    

    @Resource
    private PaymentHystrixService paymentHystrixService;

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

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    //对于有@HystrixCommand注解指定的fallbackMethod,就走指定的服务降级兜底的方法。
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
    
    
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
    
    
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout2/{id}")
    //使用全局的fallback
    @HystrixCommand
    public String paymentInfo_TimeOut2(@PathVariable("id") Integer id){
    
    
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }

    public String paymentTimeOutFallbackMethod(@PathVariable("id")Integer id){
    
    
        return "我是消费者80,对方支付系统繁忙或自身运行出错!";
    }

    //全局fallback方法
    public String payment_Global_FallbackMethod(){
    
    
        return "Global 全局的服务降级,返回信息。系统方法请稍后重试。";
    }

}

10. Hystrix 之 通配服务降级


通过@FeignClient注解里面的fallback参数来配置。

第一步:创建一个实现 当前使用OpenFeign对应的service接口 的一个实现类。

package com.itholmes.springcloud.service;

import org.springframework.stereotype.Component;

//实现了PaymentHystrixService,该类就是使用的OpenFeign远程调用。
//不要忘记装配到ioc容器中。
@Component
public class PaymentFallbackService implements PaymentHystrixService{
    
    
    @Override
    public String paymentInfo_OK(Integer id) {
    
    
        return "paymentInfo_OK fallback";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
    
    
        return "paymentInfo_TimeOut fallback";
    }
}

第二步:配置fallback,配置的就是对应的PaymentFallbackService实现类。

package com.itholmes.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
//配置fallback,配置的就是对应的PaymentFallbackService实现类。
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
    
    

    @GetMapping("/payment/hystrix/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id);

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

}

这样服务降级就会走对应实现类方法的返回值了。

11. Hystrix 之 服务熔断


在这里插入图片描述
熔断机制出发后,会检测节点微服务是否相应正常,进而恢复调用链路。


// Controller层:调用Service层的服务熔断。
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
    
    
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result: "+result);
    return result;
}



//Service层:断路器实现。
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
    
    
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
        /**
         * 以下的意思就是:在10s的时间里的10次访问,如果超过百分之60失败,就跳闸限电。
         */
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), // 请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //时间窗口期
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"), //失败率达到多少后跳闸
})
public String paymentCircuitBreaker(Integer id){
    
    
    if (id < 0){
    
    
        throw new RuntimeException("********id 不能负数");
    }

    //IdUtil.simpleUUID(); 的源代码就是 UUID.random().toString(); 这是hutool糊涂jar包里面的工具类。
    String serialNumber = IdUtil.simpleUUID();
    return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serialNumber;
}

public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
    
    
    return "id 不能负数,请稍后再试,id: "+id;
}

以上对应属性如下:
在这里插入图片描述

这样上面的代码,在10s的时间里的10次访问,如果超过百分之60失败,就跳闸限电。熔断机制触发后,就会一段时间内一直触发兜底的方法,后来会慢慢进行恢复链路机制(也即是熔断半开)。

熔断有三个状态:
在这里插入图片描述

判断断路器的三个重要参数:
在这里插入图片描述


官方hystrix的架构图:

  • HystrixObservableCommand是HystrixCommand的另一个方法,效果一样的。
    在这里插入图片描述

11. Hystrix 之 图形化dashboard(图形化监控)


第一步:创建项目,导入依赖。

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

<!--所有图形化监控检测,都依赖actuator(监控信息完善,bean的状态等)-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

注意事项:

  • 有些时候,项目太多,application.yml会变成网格,idea没有识别到。
    在这里插入图片描述
    解决办法:
    在这里插入图片描述

第二步:添加@EnableHystrixDashboard注解到主启动类。

package com.itholmes.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
//开启hystrix dashboard图形化监控
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(HystrixDashboardMain9001.class,args);
    }
}

第三步:启动项目,访问http://localhost:端口/hystrix 地址。
在这里插入图片描述

12. Hystrix 之 图形化dashboard 实战演示


被监控的系统,主启动类配置如下:

package com.itholmes.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
    
    

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

    /**
     * 此配置是为了服务监控而配置,与服务容错本身无关SpringCloud升级后的坑。
     *  ServletRegistrationBean因为springboot的默认路径不是“/hystrix.stream”,
     *  只要在自己的项目配置上下面的servlet就可以了。
     *
     *  如果不配置就会报如下的一个错误:
     *      Unable to connect to Command Metric Stream 404 的错误。
     */
    @Bean
    public ServletRegistrationBean getServlet(){
    
    
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

}

Dashboard监控系统的web监控配置如下:
在这里插入图片描述
在这里插入图片描述

Circuit断路器的效果:
在这里插入图片描述

如何看图形化界面:

  • 七色:
    在这里插入图片描述
  • 实心圆:
    在这里插入图片描述
  • 1线
    在这里插入图片描述

整个图的演示说明:
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/IT_Holmes/article/details/125446746
今日推荐