SpringCloud Alibaba系列 Sentinel(三)

导读:本篇文章讲解 SpringCloud Alibaba系列 Sentinel(三),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

高并发下的微服务容错方案?

限流、熔断、降级

1:限流

2:熔断

3:降级

分布式系统的流量防卫兵-Sentinel

什么是 Sentinel ?

Sentinel 的主要概念

资源

规则

上手 Sentinel

部署Sentinel控制台

从 Github 上下载 Sentinel

启动 Sentinel 服务

SpringCloud Alibaba 整合 Sentinel

配置流控规则

流控控制面板介绍

流控效果介绍

快速失败

Warm Up

排队等待

熔断降级介绍

慢调用比例

异常比例

异常数

权限介绍

自定义流控熔断返回的JSON信息

Feign 整合 Sentinel 返回兜底数据


高并发下的微服务容错方案?

  • 限流、熔断、降级

1:限流

在高并发系统中一定要用,高并发的所有请求进来,不是让每个请求都打到后台集群的,后台集群有它的消费能力,应该在它消费能力之内放行请求,这个就是限流

比如服务集群的处理能力是每秒1w,那么从网关处放过来的请求就是1w,超过1w的请求将直接丢弃,返回 “服务繁忙,稍后重试” 等字样。

2:熔断

一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段.

熔断就是在规定的时间内,下游服务还没有返回数据,上游服务在指定的时间内比如10秒内不调用下游服务,会在10秒后重新尝试调用下游服务,看下游服务是否正常响应了

3:降级

我们知道在一套完整的业务流程中是有主要的核心业务,和非核心业务的,比如电商系统中的商品、订单、支付是核心业务。推荐、优惠、附加业务(如小游戏)等是非核心业务。当服务流量很大的时候,可以降低非核心业务的可用性或者直接停掉。保证核心业务的可用。


分布式系统的流量防卫兵-Sentinel

官网:https://sentinelguard.io/zh-cn

github:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

什么是 Sentinel ?

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

Sentinel 具有以下特征:

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

Sentinel 的主要概念

  • 资源

资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

  • 规则

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


上手 Sentinel

  • 部署Sentinel控制台

  • 从 Github 上下载 Sentinel

https://github.com/alibaba/Sentinel

SpringCloud Alibaba系列 Sentinel(三)

SpringCloud Alibaba系列 Sentinel(三)

SpringCloud Alibaba系列 Sentinel(三)

  • 启动 Sentinel 服务

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

注意:Sentinel 控制台目前仅支持单机部署。

使用如下命令启动控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

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

访问地址:http://ip:8080

默认账号密码:sentinel/sentinel

SpringCloud Alibaba系列 Sentinel(三)


SpringCloud Alibaba 整合 Sentinel

maven版本管理如下

	<properties>
		<!-- jdk版本 -->
		<java.version>17</java.version>
		<!-- maven 打包版本 -->
		<maven.compiler.source>17</maven.compiler.source>
		<maven.compiler.target>17</maven.compiler.target>
		<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
		<!-- 编码 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 
		<spring.boot.version>2.7.4</spring.boot.version>
		<spring.cloud.version>2021.0.4</spring.cloud.version>
		<spring.cloud.alibaba.version>2021.0.4.0</spring.cloud.alibaba.version>
	</properties>
 
	<dependencyManagement>
		<dependencies>
			<!-- spring boot 版本 -->
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-dependencies</artifactId>
				<version>${spring.boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
 
			<!-- spring cloud 版本 -->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring.cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
 
			<!-- spring cloud alibaba 版本 -->
			<dependency>
				<groupId>com.alibaba.cloud</groupId>
				<artifactId>spring-cloud-alibaba-dependencies</artifactId>
				<version>${spring.cloud.alibaba.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

子服务 pom 中添加依赖

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

application.yml 文件配置 sentinel

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        # sentinel 控制台地址
        dashboard: localhost:8080

这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。这个端口不能被占用,多个微服务配置不同的port。若被占用,则端口自动+1

确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。微服务接口被请求后,就会在控制台显示出微服务

SpringCloud Alibaba系列 Sentinel(三)


配置流控规则

注意:这里的配置规则是通过 调用 sentinel 提供的 HTTP API 接口来改变的,这也意味着这些规则仅在内存态生效,应用重启之后,该规则会丢失。关于持久化规则后面会讲到,请查看官网:在生产环境中使用 Sentinel · alibaba/Sentinel Wiki · GitHub

SpringCloud Alibaba系列 Sentinel(三)

SpringCloud Alibaba系列 Sentinel(三)SpringCloud Alibaba系列 Sentinel(三)

  • 测试一下流控效果

正常的请求拿到的数据如下

SpringCloud Alibaba系列 Sentinel(三)

 当 一秒 时间里 请求次数超过 2 次,返回流控限制信息

SpringCloud Alibaba系列 Sentinel(三)


流控控制面板介绍

流量控制 · alibaba/Sentinel Wiki · GitHub

SpringCloud Alibaba系列 Sentinel(三)

资源名:默认是请求路径,可自定义,要保证唯一

针对来源:对哪个微服务进行限流,默认是不区分来源,全部限流,这个是针对 区分上游服务进行限流, 比如 视频服务 被 订单服务、用户服务调用,就可以针对订单服务来源进行限流,对用户服务来源不限流

阈值类型:

  • 流量控制
    • 原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
  • 两种规则
    1. 基于统计QPS的流量控制:当 QPS 超过某个阈值的时候,则采取措施进行流量控制
    2. 基于统计并发线程数的流量控制:并发数控制用于保护业务线程池不被慢调用耗尽。Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目)如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。

流控效果介绍

SpringCloud Alibaba系列 Sentinel(三)

快速失败

默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝

Warm Up

即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

排队等待

严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

  • 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
  • 注意:匀速排队模式暂时不支持 QPS > 1000 的场景,不能让用户无限的排对,不然等到啥时候去了?

熔断降级介绍

慢调用比例

SpringCloud Alibaba系列 Sentinel(三)

选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

示例:

SpringCloud Alibaba系列 Sentinel(三)

同下面的异常比例、异常数类似,就不贴示例了

异常比例

SpringCloud Alibaba系列 Sentinel(三)

当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% – 100%。 

异常数

SpringCloud Alibaba系列 Sentinel(三)

当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。


权限介绍

SpringCloud Alibaba系列 Sentinel(三)

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。


自定义流控熔断返回的JSON信息

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Component
public class CustomUrlBlockHandler implements BlockExceptionHandler {

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
		Map<String, Object> backMap = new HashMap<>(2);
		if (e instanceof FlowException) {
			backMap.put("code", -1);
			backMap.put("msg", "限流-异常啦");
		} else if (e instanceof DegradeException) {
			backMap.put("code", -2);
			backMap.put("msg", "降级-异常啦");
		} else if (e instanceof ParamFlowException) {
			backMap.put("code", -3);
			backMap.put("msg", "热点-异常啦");
		} else if (e instanceof SystemBlockException) {
			backMap.put("code", -4);
			backMap.put("msg", "系统规则-异常啦");
		} else if (e instanceof AuthorityException) {
			backMap.put("code", -5);
			backMap.put("msg", "认证-异常啦");
		}
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Cache-Control", "no-cache");
		response.setStatus(200);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json");
		response.getWriter().println(JSON.toJSONString(backMap));
		response.getWriter().flush();
	}
}

SpringCloud Alibaba系列 Sentinel(三)


Feign 整合 Sentinel 返回兜底数据

子服务 pom 中添加依赖

<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>

application.yml 文件配置 打开Sentinel对Feign的支持

feign:
  sentinel:
    enabled: true

当使用 feigin 调用下游服务的时候,下游服务异常,可以使用 @FeignClient 注解的 fallback 属性指定返回兜底数据

// fallback:指定兜底数据是哪个实现类(兜底实现类,要实现本接口类)
@FeignClient(name = "order-service", fallback = OrderServiceFallback.class)
public interface OrderService {

	@GetMapping("/order/one")
	OrderDO getOne(@RequestParam("orderId") Long orderId);

}
@Service
public class OrderServiceFallback implements OrderService {

	@Override
	public OrderDO getOne(Long orderId) {
		// 返回兜底数据
		OrderDO orderDO = new OrderDO();
		orderDO.setId(1L);
		return orderDO;
	}

}

返回了兜底数据

SpringCloud Alibaba系列 Sentinel(三)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72507.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!