Java之 Spring Cloud 微服务搭建Sentinel (第二个阶段)【三】【SpringBoot项目实现商品服务器端是调用】

x33g5p2x  于2021-11-29 转载在 Java  
字(10.3k)|赞(0)|评价(0)|浏览(374)

一、服务熔断Hystrix的替换方案

18年底Netflix官方宣布Hystrix 已经足够稳定,不再积极开发 Hystrix,该项目将处于维护模式。就目前来看Hystrix是比较稳定的,并且Hystrix只是停止开发新的版本,并不是完全停止维护,Bug什么的依然会维护的。因此短期内,Hystrix依然是继续使用的。但从长远来看,Hystrix总会达到它的生命周期,那么Spring Cloud生态中是否有替代产品呢?

1、替换方案介绍

Alibaba Sentinel
Sentinel 是阿里巴巴开源的一款断路器实现,目前在Spring Cloud的孵化器项目Spring Cloud Alibaba中的一员Sentinel本身在阿里内部已经被大规模采用,非常稳定。因此可以作为一个较好的替代品。

Resilience4J
Resilicence4J 一款非常轻量、简单,并且文档非常清晰、丰富的熔断工具,这也是Hystrix官方推荐的替代产品。
不仅如此,Resilicence4j还原生支持Spring Boot 1.x/2.x,而且监控也不像Hystrix一样弄Dashboard/Hystrix等一堆轮子,而是支持和Micrometer(Pivotal开源的监控门面,Spring Boot 2.x中的Actuator就是基于Micrometer的)、prometheus(开源监控系统,来自谷歌的论文)、以及Dropwizard metrics(Spring Boot曾经的模仿对象,类似于Spring Boot)进行整合。

2、 Sentinel概述

(1) Sentinel简介

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性:

(2) Sentinel与Hystrix的区别

(3) 迁移方案

Sentinel官方提供了详细的由Hystrix 迁移到Sentinel 的方法

(4) 名词解释

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合Dashboard 可以取得最好的效果。
使用 Sentinel 来进行熔断保护,主要分为几个步骤:

  1. 定义资源
  2. 定义规则
  3. 检验规则是否生效

资源:可以是任何东西,一个服务,服务里的方法,甚至是一段代码。

规则:Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和 热点参数规则。

Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效先把可能需要保护的资源定义好,之后再配置规则。

也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

3、Sentinel中的管理控制台

(1)下载启动控制台

1)获取 Sentinel 控制台

您可以从官方网站中下载最新版本的控制台 jar 包,下载地址如下:
https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jar

2)启动

使用如下命令启动控制台:java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.6.3.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel 。可以参考 鉴权模块文档 配置用户名和密码。

启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

访问:
http://localhost:8080/#/login

4 、基于Sentinel的服务保护

(1)客户端能接入控制台(将所有的服务交给控制台管理)

控制台启动后,客户端需要按照以下步骤接入到控制台。

1)创建案例

之前都已经创建过这里直接导入代码学习即可
代码下载地址
https://download.csdn.net/download/qq_44757034/49774279

启动所有项目

2)引入依赖

需要注意SpringCloud-Alibaba与SpringCloud的版本关系

父工程引入alibaba实现的SpringCloud

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-dependencies</artifactId>
	<version>2.1.0.RELEASE</version>
	<type>pom</type>
	<scope>import</scope>
</dependency>

子工程中引入sentinel

  • order_service_feign

  • order_service_rest

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
3)配置参数
  • 在order_service_rest当中的application.yml

cloud:
    sentinel:
      transport:
        dashboard: localhost:8080   #sentinel控制台的请求地址
  • order_service_feign当中的application.yml

cloud:
    sentinel:
      transport:
        dashboard: localhost:8080   #sentinel控制台的请求地址
4)启动运行测试

访问:http://localhost:9003/order/buy/1

http://localhost:9004/order/buy/1

访问:http://localhost:8080/#/login

(2)通用的资源保护

1)修改order_service_rest当中的OrderController

package cn.itbluebox.order.controller;

import cn.itbluebox.order.entity.Product;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/order")
public class OrderController {
	@Autowired
	private RestTemplate restTemplate;
	/** * @SentinelResource * blockHandler : 声明熔断时调用的降级方法 * fallback : 抛出异常执行的降级方法 * value : 自定义的资源名称 * * 不设置:当前全类名.方法名 */
	@SentinelResource(value="orderFindById",blockHandler = "orderBlockHandler",fallback = "orderFallback")
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		if(id != 1) {
			throw new RuntimeException("错误");
		}
		return restTemplate.getForObject("http://service-product/product/1",Product.class);
	}
	/** * 定义降级逻辑 * hystrix和sentinel * 熔断执行的降级方法 * 抛出异常执行的降级方法 */
	public Product orderBlockHandler(Long id) {
		Product product = new Product();
		product.setProductName("触发熔断的降级方法");
		return product;
	}
	public Product orderFallback(Long id) {
		Product product = new Product();
		product.setProductName("抛出异常执行的降级方法");
		return product;
	}
}

在需要被保护的方法上使用@SentinelResource注解进行熔断配置。与Hystrix不同的是,Sentinel对抛
出异常和熔断降级做了更加细致的区分,通过 blockHandler 指定熔断降级方法,通过 fallback 指定
触发异常执行的降级方法。

2)运行测试

访问http://localhost:9004/order/buy/1

访问http://localhost:8080/#/dashboard/metric/service-order-rest

访问测试:http://localhost:9004/order/buy/2进入降级方法

多刷新上述访问我们再次访问http://localhost:9004/order/buy/1也进入降级方法

等待5s以后再次访问http://localhost:9004/order/buy/1
恢复正常状态,退出降级方法

3)对于@SentinelResource的其他配置如下表:

注:1.6.0 之前的版本 fallback 函数只针对降级异常( DegradeException )进行处理,不能针对业务异常进行处理。

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。

若未配置 blockHandler 、 fallback 和 defaultFallback ,则被限流降级时会BlockException 直接抛出。

5 、加载本地配置

一条限流规则主要由下面几个因素组成:

resource:资源名,即限流规则的作用对象
count: 限流阈值
grade: 限流阈值类型(QPS 或并发线程数)
limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
strategy: 调用关系限流策略
controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

java代码 RuleConstant

配置文件添加如下配置

#通过文件读取限流规则
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

1)修改order_service_rest当中的application.yml

ds1:
          file:
            file: classpath:flowrule.json
            data-type: json
            rule-type: flow
      eager: true #立即加载

2)创建flowrule.json

[
  {
    "resource": "orderFindById",
    "controlBehavior": 0,
    "count": 1,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0
  }
]

3)运行测试

访问:http://localhost:9004/order/buy/1

访问:http://localhost:8080/#/dashboard/identity/service-order-rest

6 、RestTemplate的资源保护

(1)修改order_service_rest当中的OrderController

去除之前配置的关于熔断的方法

package cn.itbluebox.order.controller;

import cn.itbluebox.order.entity.Product;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/order")
public class OrderController {
	@Autowired
	private RestTemplate restTemplate;
	/** * @SentinelResource * blockHandler : 声明熔断时调用的降级方法 * fallback : 抛出异常执行的降级方法 * value : 自定义的资源名称 * * 不设置:当前全类名.方法名 */
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		if(id != 1) {
			throw new RuntimeException("错误");
		}
		return restTemplate.getForObject("http://service-product/product/1",Product.class);
	}

}

(2)在order_service_rest当中的RestOrderApplication上测试

1)创建ExceptionUtils

package cn.itbluebox.order.exception;

import cn.itbluebox.order.entity.Product;
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;

public class ExceptionUtils {
    /** * 静态方法 * 返回值: SentinelClientHttpResponse * 参数 : request , byte[] , clientRquestExcetion , blockException */
    //限流熔断业务逻辑
    public static SentinelClientHttpResponse handleBlock(HttpRequest request, byte[] body,
                                                         ClientHttpRequestExecution execution,
                                                         BlockException ex) {
        Product product = new Product();
        product.setProductName("限流熔断降级");
        return new SentinelClientHttpResponse(JSON.toJSONString(product));
    }
    //异常降级业务逻辑
    public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body,
                                                            ClientHttpRequestExecution execution,
                                                            BlockException ex) {
        Product product = new Product();
        product.setProductName("异常熔断降级");
        return new SentinelClientHttpResponse(JSON.toJSONString(product));
    }
}
2)完善RestOrderApplication

package cn.itbluebox.order;

import cn.itbluebox.order.exception.ExceptionUtils;
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EntityScan("cn.itbluebox.order.entity")
public class RestOrderApplication {

	/** * sentinel支持对restTemplate的服务调用使用sentinel方法.在构造 * RestTemplate对象的时候,只需要加载@SentinelRestTemplate即可 * 资源名: * httpmethod:schema://host:port/path :协议、主机、端口和路径 * httpmethod:schema://host:port :协议、主机和端口 * @SentinelRestTemplate: * 异常降级 * fallback : 降级方法 * fallbackClass : 降级配置类 * 限流熔断 * blockHandler * blockHandlerClass */
	@LoadBalanced
	@Bean
	@SentinelRestTemplate(fallbackClass = ExceptionUtils.class,fallback = "handleFallback",
			blockHandler = "handleBlock",blockHandlerClass = ExceptionUtils.class)
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}

	public static void main(String[] args) {
		SpringApplication.run(RestOrderApplication.class,args);
	}
}
3)运行测试

访问:http://localhost:9004/order/buy/1

访问:http://localhost:9004/order/buy/2

访问管理控制台:http://localhost:8080/#/dashboard/degrade/service-order-rest

访问测试:慢一些访问:http://localhost:9004/order/buy/1

快速多次访问

7 、Feign实现熔断

Sentinel 适配了 Feign 组件。如果想使用,除了引入 sentinel-starter 的依赖外还需要 2 个步骤:

  • 配置文件打开 sentinel 对 feign 的支持: feign.sentinel.enabled=true
  • 加入 openfeign starter 依赖使 sentinel starter 中的自动化配置类生效:

在order_service_feign当中的

(1)引入依赖

<!-- feign对Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

(2) 开启sentinel 支持

在工程的application.yml中添加sentinel 对 feign 的支持

# 激活sentinel的支持
feign:
  sentinel:
    enabled: true

(3)配置FeignClient

在之前我们已经设置好了熔断了直接启动运行即可
访问:http://localhost:9003/order/buy/1

访问:http://localhost:8080/#/dashboard/identity/service-order-feign

多次访问:http://localhost:9003/order/buy/1

触发熔断

相关文章

最新文章

更多