Nepxion Discovery学习笔记3 Sentinel流量防卫兵/服务容错综合方案

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

是阿里开源的一套用于服务容错的综合性解决方案。它以流量 为切入点, 流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。


笔记1:

Sentinel 具有以下特征:

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

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

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

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

Sentinel 分为两个部分:

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

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


笔记2:

Sentinel是阿里巴巴开发的一个开源服务器,用于给微服务体系提供服务容错的解决方案,流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。

在使用Sentinel 之前, 必须先 安装 Sentinel控制台并启动!

注意: Sentinel 是个springboot项目,因此可以解压后通过IDEA导入项目,再运行启动类启动,或者不需解压,直接在控制台运行jar包启动(建议)!

# 直接在cmd命令窗口使用jar命令启动项目,因为Sentinle本身是SpringBoot项目(先cd到jar包目录) 
# 我下载的是1.7.2的版本
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.2.jar

扩展:

  • -Dsentinel.dashboard.auth.username=sentinel //用于指定控制台的登录用户名为 sentinel;
  • -Dsentinel.dashboard.auth.password=123456  //用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel
  • -Dserver.servlet.session.timeout=7200    //用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

启动成功:

输入地址 localhost:8080 访问Sentinel控制台(注意:用户名密码都是: sentinel):

依赖:

        <!--Sentinel组件-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
配置文件(yml)中配置Sentinel:
server:
  port: 8091
  tomcat:
    max-threads: 10 #tomcat的最大并发值修改为10,默认是200
spring:
  application:
    name: service-order
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    username: root
    password: root
  cloud:
    nacos: #nacos的作用就是一个注册中心
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
    #Sentinel是个springboot项目的控制台, 提供服务容错方案,通过流量控制、熔断降级、系统负载保护来维持服务的稳定性
    #cmd命令窗口启动Sentinel控制台命令:(cd 到 jar包所在目录)
    #java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
      transport:
        port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可
        dashboard: localhost:8080 # 指定Sentinel服务地址(要和-Dserver.port端口一致)
service-product: # 调用外部服务的名称
  ribbon: #配置 ribbon
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    #设置负载均衡策略 BestAvailableRule 访问最小并发请求的服务; RandomRule 随机访问服务等策略
jpa:
  properties:
    hibernate:
      hbm2ddl:
        auto: update
      dialect: org.hibernate.dialect.MySQL5InnoDBDialect

调用controller层的接口,然后在新的标签页中访问 localhost:8080,才能显示出被调用的接口对应的微服务.

(不知道是不是google浏览器的问题,调用接口后刷新当前标签,居然不显示微服务的!!!!!!)

注意:如果设置 -Dserver.port-Dcsp.sentinel.dashboard.server端口一样,则会把sentinel自带的控制台服务 sentinel-dashboard 也显示出来;

如果不想看见该服务,则可以设置不同的端口号,或者启动命令中不带 -Dcsp.sentinel.dashboard.server 


笔记3:

实时监控:

经常会发现sentinel的实时监控没有数据,是一片空白的,这是因为:

1.浏览器问题,比如我用的google浏览器就不能实时更新,而是要自己去快速的手动刷新.

2.时间问题,sentinel是实时监控的,只有在接口调用的瞬间,马上刷新sentinle控制台的页面才有可能看得见.(太过拙劣了,以后得想办法看看如何解决)


笔记4:

簇点链路:

该选项中可以对具体的接口实行流量控制,熔断降级等操作,用于管理控制访问资源(是sentinel的保护对象,可以是服务,也可以是接口或一段代码)的请求数量.

这里我对 /order/message接口 选择流控:

资源名:唯一名称,默认是请求路径,可自定义.

 

针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制.

阈值类型/单机阈值

      QPS每秒请求数量): 当调用该接口的每秒请求数达到阈值的时候,进行限流

      线程数:当调用该接口的总线程数达到阈值的时候,进行限流

是否集群:暂不需要集群

 

当我设置了流控规则为:每秒请求数量不得超过2,否则限流;

 

然后快速访问接口,会出现以下信息,就是限流成功.


笔记5:

流控模式(规则)有3种:

 

在规则编辑界面,点击高级选项,可以看见流控模式和流控效果:

 

直接默认):当前资源(接口)达到限流条件时,开启限流,最简单的模式,这里不介绍.

关联:当关联的资源(接口)达到限流条件时,开启限流 [适合做应用让步],

           1.配置限流规则, 将流控模式设置为关联,关联资源设置为的 /order/message1

       2.然后快速访问 /order/message1 接口, 再访问回 /order/message, 就会发生限流:

链路:当从某个(资源)接口过来的请求量达到限流条件时,开启限流(和关联流控的区别在于: 链路流控是针对上级接口,而关联流控可以是已注册的任意接口)

注意:

Sentinel1.7.0 版本开始(对应SCA2.1.1.RELEASE),官方在CommonFilter 引入了 WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的 URL 进行链路限流。

SCA(spring-cloud-alibaba) 2.1.1.RELEASE之后的版本,可以通过配置spring.cloud.sentinel.web-context-unify=false即 可关闭收敛.

所以2.1.1.RELEASE之前的版本无法配置链路限流.

创建OrderServiceImpl3 和 OrderController3,测试链路流控.

@Service
public class OrderServiceImpl3 {
	/*
	@SentinelResource("资源名")注解: 用于指定本地资源(接口)并配置相应的流控规则.
	 */
	@SentinelResource("/message")
	public void message() { System.out.println("message"); }
}
@RestController
@Slf4j
public class OrderController3 {
	@Autowired
	private OrderServiceImpl3 orderServiceImpl3;

	@RequestMapping("/order/message1")
	public String message1() { return "message1"; }

	@RequestMapping("/order/message2")
	public String message2() { return "message2"; }

	@RequestMapping("/order/message3")
	public String message3() {
		orderServiceImpl3.message();
		return "message3";
	}
}

配置message的链路流控规则

快速访问发现message3会被限流,但message2不会:

流控效果有3种:

快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果

Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。

排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设 置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。


笔记6:

降级模式(规则):

降级就是降低服务的优先级的意思,让优先级更高的服务能正常顺利运行.

有3种条件:

平均响应时间(RT) :当资源的平均响应时间超过阈值(以 ms 为单位)之后,资源进入准降级状态。 如果接下来1s 内持续进入 5 个请求,它们的 RT都持续超过这个阈值,那么在接下的时间窗口 (以 s 为单位)之内,就会对这个方法进行服务降级

[注意: Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要 变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。]

以上设置为:当平均响应时间(RT)>1ms,接下来10s内该服务降级,10s后恢复正常,并进入下一轮判断!

异常比例:当资源的每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口(以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0]

以上设置为:当每秒异常数超过0.25,则降级,在10s内,自动返回对该接口的调用.

异常数 :当资源近 1 分钟的异常数超过阈值之后会在接下来的指定时间内进行服务降级

[注意: 由于统计时间窗口是分钟级别的,若时间窗口小于 60s则可能导致在接下来统计的60s内又检测到异常数超过阈值(降级不会取消该检测),这样一来即使结束熔断状态(恢复正常),也可能会再进入熔断状态。]

以上设置为:在近60s内,异常数超过3,则在70s内降级.


问题:流控规则和降级规则返回的异常页面是一样的,我们怎么来区分到底是什么原因导致的呢?

解法:可以编写自定义异常处理逻辑,通过捕获的异常类型就可以判断出相应的异常问题:

1.创建异常处理类:

/**
 * 自定义sentinel异常返回信息
 */
@Component
public class ExceptionHandlerPage implements UrlBlockHandler {
	@Override
	public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
		// BlockException 异常接口,其子类为Sentinel五种规则异常的实现类
		// AuthorityException 授权异常
		// DegradeException 降级异常
		// FlowException 限流异常
		// ParamFlowException 参数限流异常
		// SystemBlockException 系统负载异常
		ResponseData data = new ResponseData();
		if ( e instanceof FlowException ) {
			data = new ResponseData(-1, "接口被限流了。");
		} else if ( e instanceof DegradeException ) {
			data = new ResponseData(-2, "接口被降级了。");
		}
		response.setContentType("application/json;charset=utf-8");
		response.getWriter().write(JSON.toJSONString(data));
	}
}

2.创建返回实体类:

/**
 * 定义返回的实体类,字段根据需要添加
 */
@Data// 生成getter/setter/tostring/equals
@AllArgsConstructor // 全参构造
@NoArgsConstructor// 无参构造
public class ResponseData {
	private int code;
	private String message;
}

3.配置RT降级规则和QPS流控规则,再快速调用接口:


笔记7:

热点规则:

热点参数流控规则是一种粒度更细的流控规则, 它允许将规则具体到接口的参数上

注意:热点规则只能运用在@SentinelResource注解标识的资源上.

1.新建接口

@RequestMapping("/order/message4")
	@SentinelResource("message4")//必须使用@SentinelResource注解标识,否则热点规则不生效
	public String message3(String name, Integer age) { return name + age; }

2.配置热点规则

以上设置为:对接口的第一个参数进行流控,若调用接口时第一个参数传了参,且每秒接口请求数大于1,则限流.

快速访问,传了第一个参name和不传第一个参的情况:发现只有第一个参数会被限流.

参数例外项:

允许对一个参数的具体值进行流控.编辑刚才定义的规则,增加参数例外项:

以上设置为:当该参数(第一个参数)是String类型,且参数值为: stephen 时,设置QPS>1000时,才会限流.

快速访问接口,并给第一个参数(name)传参为stephen: 发现不再限流; 而参数不为stephen时则会限流.


笔记8:

授权规则(黑白名单):

很多时候,我们需要根据调用来源(外部服务的接口)来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单授权规则)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:

白名单: 只有白名单记录的请求来源可通过, 其余的请求不可通过;

黑名单: 只有黑名单记录的请求来源不可通过, 其余的请求可通过.

1.自定义来源处理规则

/*
在Sentinel的授权规则配置中,有个流控应用的项:用于标识调用本服务接口的外部服务来源.
Sentinel提供了 RequestOriginParser 接口来处理来源。
只要Sentinel保护的接口资源被访问,Sentinel就会调用 RequestOriginParser 的实现类去解析访问来源。
 */
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
	@Override
	public String parseOrigin(HttpServletRequest request) {
		//获取请求中传入的参数
		String serviceName = request.getParameter("name");
		return serviceName;
	}
}

2.配置授权规则

3.调用接口发现: 当传入name=stephen,则失败;只有传入name=william 成功.


笔记9:

系统规则:

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 LoadRT、入口 QPS 、CPU 使用率线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过 系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般 是 CPU cores * 2.5

RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护。

猜你喜欢

转载自blog.csdn.net/weixin_42585386/article/details/109222267