谷粒商城 高级篇 (二十五) --------- SpringCloud Alibaba Sentinel


一、简介

1. 熔断降级限流

什么是熔断?

A 服务调用 B 服务的某个功能,由于网络不稳定问题,或者 B 服务卡机,导致功能时间超长。如果这样子的次数太多。我们就可以直接将 B 断路了 (A 不再请求B 接口) ,凡是调用 B 的直接返回降级数据,不必等待 B 的超长执行。 这样 B 的故障问题,就不会级联影响到 A。

什么是降级?

整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和页面进行有策略的降级[停止服务,所有的调用直接返回降级数据]。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。

异同:

相同点:

1、为了保证集群大部分服务的可用性和可靠性,防止崩溃,牺牲小我
2、用户最终都是体验到某个功能不可用

不同点:

1、熔断是被调用方故障,触发的系统主动规则
2、降级是基于全局考虑,停止一些正常服务,释放资源

什么是限流?

对打入服务的请求流量进行控制,使服务能够承担不超过自己能力的流量压力。

2. Sentinel 简介

官方文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
项目地址:https://github.com/alibaba/Sentinel

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

Sentinel 具有以下特征:

  • 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀 (即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

  • 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

  • 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

  • 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

在这里插入图片描述
Sentinel 分为两个部分:

  • 核心库 (Java 客户端) 不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

  • 控制台 (Dashboard) 基于 Spring Boot 开发,打包后可以直接运行,不需要额外的Tomcat 等应用容器。

Sentinel 基本概念:

资源:

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

规则:

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

二、Hystrix 与 Sentinel 比较

在这里插入图片描述

三、整合 Feign+Sentinel 测试熔断降级

https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。

在这里插入图片描述
Sentinel 和 Hystrix 的原则是一致的:

当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

熔断降级设计理念

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

Hystrix 通过 线程池隔离 的方式,来对依赖 (在 Sentinel 的概念中对应资源) 进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本 (过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。Sentinel 对这个问题采取了两种手段:

  • 通过并发线程数进行限制
    • 和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
  • 通过响应时间对资源进行降级
    • 除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

整合测试:

https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-feign-example/readme-zh.md

A、引入依赖

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

B、使用 Nacos 注册中心

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

C、定义 fallback 实现

在服务消费者中,实现 feign 远程接口,接口的实现方法即为调用错误的容错方法

public class OrderFeignServiceFallBack implements OrderFeignService {
	@Override
	public Resp<OrderVo> getOrderInfo(String orderSn) {
		return null;
	}
}

D、定义 fallbackfactory 并放在容器中

@Component
public class OrderFeignFallbackFactory implements FallbackFactory<OrderFeignServiceFallBack> {
	@Override
	public OrderFeignServiceFallBack create(Throwable throwable) {
		return new OrderFeignServiceFallBack(throwable);
	}
}

E、改造 fallback 类接受异常并实现容错方法

public class OrderFeignServiceFallBack implements OrderFeignService {
	private Throwable throwable;
	public OrderFeignServiceFallBack(Throwable throwable){
		this.throwable = throwable;
	}
	@Override
	public Resp<OrderVo> getOrderInfo(String orderSn) {
		return Resp.fail(new OrderVo());
	}
}

F、远程接口配置 feign 客户端容错

@FeignClient(value = "gulimall-oms",fallbackFactory = OrderFeignFallbackFactory.class)
public interface OrderFeignService {
	@GetMapping("/oms/order/bysn/{orderSn}")
	public Resp<OrderVo> getOrderInfo(@PathVariable("orderSn") StringorderSn);
}

G、开启 sentinel 代理 feign 功能

在 application.properties 中配置

feign.sentinel.enabled=true

测试熔断效果。当远程服务出现问题,会自动调用回调方法返回默认数据。

更快的容错方式

H、使用 @SentinelResource,并定义 fallback

@SentinelResource(value = "order",fallback = "e")

Fallback 和原方法签名一致,但是最多多一个 Throwable 类型的变量接受异常。
https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

需要给容器中配置注解切面

@Bean
public SentinelResourceAspect sentinelResourceAspect() {
	return new SentinelResourceAspect();
}

在控制台添加降级策略

在这里插入图片描述
I、测试降级效果

当远程服务停止,前几个服务会尝试调用远程服务,满足降级策略条件以后则不会再尝试调用远程服务

四、整合 Sentinel 测试限流 (流量控制)

https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md

什么是流量控制?

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

在这里插入图片描述
流量控制设计理念

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系
  • 运行指标,例如 QPS、线程池、系统负载等
  • 控制的效果,例如直接限流、冷启动、排队等

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

A、引入 Sentinel starter

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

B、接入限流埋点

  • HTTP 埋点
    Sentinel starter 默认为所有的 HTTP 服务提供了限流埋点,如果只想对 HTTP 服务进行限流,那么只需要引入依赖,无需修改代码。
  • 自定义埋点
    如果需要对某个特定的方法进行限流或降级,可以通过 @SentinelResource 注解来完成限流
    的埋点,示例代码如下:
@SentinelResource("resource")
public String hello() {
	return "Hello";
}

当然也可以通过原始的 SphU.entry(xxx) 方法进行埋点, 可以参见 Sentinel 文档

https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%B5%84%E6%BA%90

C、配置限流规则

Sentinel 提供了两种配置限流规则的方式:代码配置 和 控制台配置。

List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule = new FlowRule();
rule.setResource(str);
// set limit qps to 10
rule.setCount(10);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");

rules.add(rule);
FlowRuleManager.loadRules(rules);

D、启动应用并配置

增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息

spring.application.name=sentinel-example
server.port=18083
spring.cloud.sentinel.transport.dashboard=localhost:8080

E、控制台配置限流规则并验证

访问 http://localhost:8080 页面

在这里插入图片描述

如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了 lazy load 策略。

任意发送请求,可以在簇点链路里面看到刚才的请求,可以对请求进行流控。

在这里插入图片描述
测试流控效果

在这里插入图片描述

E、自定义流控响应

package com.fancy.gulimall.seckill.config;

import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.fancy.common.exception.BizCodeEnume;
import com.fancy.common.utils.R;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class SeckillSentinelConfig {

    public SeckillSentinelConfig(){
        WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler(){
            @Override
            public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws IOException {
                R error = R.error(BizCodeEnume.TOO_MANY_REQUEST.getCode(), BizCodeEnume.TOO_MANY_REQUEST.getMsg());
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json");
                response.getWriter().write(JSON.toJSONString(error));
            }
        });
    }
}

F、持久化流控规则

默认的流控规则是保存在项目的内存中,项目停止再启动,流控规则就是失效。我们可以持久化保存规则:

https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95

生产环境使用模式:

我们推荐通过控制台设置规则后将规则推送到统一的规则中心, 客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更。
在这里插入图片描述

解决方案:

DataSource 扩展常见的实现方式有:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更。
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

推模式:使用 Nacos 配置规则

1、引入依赖

<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-datasource-nacos</artifactId>
	<version>1.6.3</version>
</dependency>

2、编写配置类

@Configuration
public class SentinelConfig {
	public SentinelConfig(){
	
		//1、加载流控策略
		ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>("127.0.0.1:8848", "demo", "sentinel", source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
		FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
		
		//2、加载降级策略
		ReadableDataSource<String, List<DegradeRule>> degradeRuleDataSource = new NacosDataSource<>("127.0.0.1:8848", "demo", "sentinel", source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {}));
		DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
		
		//3、加载系统规则
		ReadableDataSource<String, List<SystemRule>> systemRuleDataSource = new NacosDataSource<>("127.0.0.1:8848", "demo", "sentinel", source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {}));
		SystemRuleManager.register2Property(systemRuleDataSource.getProperty());
		
		//4、加载权限策略
		ReadableDataSource<String, List<AuthorityRule>>
		authorityRuleDataSource = new NacosDataSource<>("127.0.0.1:8848", "demo", "sentinel", source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {}));
		AuthorityRuleManager.register2Property(authorityRuleDataSource.getProperty());
	}
}

参照 https://github.com/alibaba/Sentinel/wiki/Dynamic-Rule-Configuration 查看更多控制规则

3、在 nacos 中创建 dataId,并使用 json 格式

在这里插入图片描述
4、添加一条流控规则测试

[
	{ 
		"resource": "/ums/member/list", 
		"limitApp": "default", 
		"grade": 1, 
		"count": 5, 
		"strategy": 0, 
		"controlBehavior": 0, 
		"clusterMode": false
	}
]

配置含义说明:

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

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

5、系统规则,降级规则等均可添加

[
	{ 
		"resource": "/ums/member/list", 
		"limitApp": "default", 
		"grade": 1, 
		"count": 5, 
		"strategy": 0, 
		"controlBehavior": 0, 
		"clusterMode": false
	},
	{ 
		"highestSystemLoad": -1, 
		"highestCpuUsage": 0.99, 
		"qps": 2, 
		"avgRt": 10, 
		"maxThread": 10
	}
]

6、最终效果
Sentinel 控制台改变流控规则,不能推送到 nacos 中,
Nacos 中改变流控规则可以实时观察到变化

在这里插入图片描述
第 2 步 API 的方式,可以直接变为配置方式:

在 application.properties 中配置

spring.cloud.sentinel.datasource.ds.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds.nacos.group-id=demo
spring.cloud.sentinel.datasource.ds.nacos.rule-type=flow
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds1.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds1.nacos.group-id=demo
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=system

ds,ds1 是随便写的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在森林中麋了鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值