写点什么

Sentinel:万字详解微服务的哨兵机制,我跪了,mysql 编程入门教程

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:7106 字

    阅读完需:约 23 分钟

private static void initFlowRules(){List<FlowRule> rules = new ArrayList<>();FlowRule rule = new FlowRule();rule.setResource("HelloWorld");rule.setGrade(RuleConstant.FLOW_GRADE_QPS);// Set limit QPS to 20.rule.setCount(20);rules.add(rule);FlowRuleManager.loadRules(rules);}


完成!


完整的代码如下:


pom.xml


1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">4 <modelVersion>4.0.0</modelVersion>5 <parent>6 <groupId>org.springframework.boot</groupId>7 <artifactId>spring-boot-starter-parent</artifactId>8 <version>2.2.2.RELEASE</version>9 <relativePath/> <!-- lookup parent from repository -->10 </parent>11 <groupId>com.cjs.example</groupId>12 <artifactId>sentinel-example</artifactId>13 <version>0.0.1-SNAPSHOT</version>14 <name>sentinel-example</name>1516 <properties>17 <java.version>1.8</java.version>18 <spring-cloud.version>Greenwich.SR4</spring-cloud.version>19 <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>20 </properties>2122 <dependencies>23 <dependency>24 <groupId>org.springframework.boot</groupId>25 <artifactId>spring-boot-starter-actuator</artifactId>26 </dependency>27 <dependency>28 <groupId>org.springframework.boot</groupId>29 <artifactId>spring-boot-starter-web</artifactId>30 </dependency>31 <dependency>32 <groupId>com.alibaba.cloud</groupId>33 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>34 </dependency>3536 </dependencies>3738 <dependencyManagement>39 <dependencies>40 <dependency>41 <groupId>org.springframework.cloud</groupId>42 <artifactId>spring-cloud-dependencies</artifactId>43 <version>{spring-cloud-alibaba.version}</version>52 <type>pom</type>53 <scope>import</scope>54 </dependency>55 </dependencies>56 </dependencyManagement>5758 <build>59 <plugins>60 <plugin>61 <groupId>org.springframework.boot</groupId>62 <artifactId>spring-boot-maven-plugin</artifactId>63 </plugin>64 </plugins>65 </build>6667 </project>


application.properties


server.port=8084spring.application.name=sentinel-examplespring.cloud.sentinel.transport.dashboard=127.0.0.1:8080


SentinelExampleApplication.java


1 package com.cjs.example.sentinel;23 import com.alibaba.csp.sentinel.Entry;4 import com.alibaba.csp.sentinel.SphU;5 import com.alibaba.csp.sentinel.slots.block.BlockException;6 import com.alibaba.csp.sentinel.slots.block.RuleConstant;7 import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;8 import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;9 import org.springframework.boot.SpringApplication;10 import org.springframework.boot.autoconfigure.SpringBootApplication;1112 import java.util.ArrayList;13 import java.util.List;1415 @SpringBootApplication16 public class SentinelExampleApplication {1718 public static void main(String[] args) {19 SpringApplication.run(SentinelExampleApplication.class, args);202122 // 配置规则.23 initFlowRules();2425 while (true) {26 // 1.5.0 版本开始可以直接利用 try-with-resources 特性,自动 exit entry27 try (Entry entry = SphU.entry("HelloWorld")) {28 // 被保护的逻辑 29 System.out.println("hello world");30 } catch (BlockException ex) {31 // 处理被流控的逻辑 32 System.out.println("blocked!");33 }34 }35 }363738 private static void initFlowRules() {39 List<FlowRule> rules = new ArrayList<>();4041 FlowRule rule = new FlowRule();42 rule.setResource("HelloWorld");43 rule.setGrade(RuleConstant.FLOW_GRADE_QPS);44 // Set limit QPS to 20.45 rule.setCount(20);46 rules.add(rule);4748 FlowRuleManager.loadRules(rules);4950 }51 }


TestController.java


1 package com.cjs.example.sentinel;23 import com.alibaba.csp.sentinel.annotation.SentinelResource;4 import org.springframework.web.bind.annotation.GetMapping;5 import org.springframework.web.bind.annotation.RestController;67 @RestController8 public class TestController {910 @GetMapping("/hello")11 @SentinelResource("hello")12 public String hello() {13 return "hello";14 }1516 }

3. Sentinel 控制台

Sentinel 控制台最少应该包含如下功能:


  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。

  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。

  • 规则管理和推送:统一管理推送规则。

  • 鉴权:生产环境中鉴权非常重要。


https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0


获取控制台:

方式一:下载已经打好的包

https://github.com/alibaba/Sentinel/releases?


wget https://github.com/alibaba/Sentinel/releases/download/1.7.1/sentinel-dashboard-1.7.1.jar

方式二:通过源码构件?

mvn clean package?


启动控制台


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


默认用户名密码都是 sentinel?




4. Sentinel 注解支持

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项


@SentinelResource 注解的属性:


  • value :资源名称

  • entryType :the entry type (inbound or outbound)

  • blockHandler/blockHandlerClass :?blockHandler 是对应处理 BlockException 的函数名称。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass。blockHandlerClass 为对应函数所在类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

  • fallback :fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了?exceptionsToIgnore?里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:defaultFallback :默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑

  • 返回值类型必须与原函数返回值类型一致;

  • 方法参数列表需要和原函数一致,或者可以额外多一个?Throwable?类型的参数用于接收对应的异常;

  • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定?fallbackClass?为对应的类的?Class?对象,注意对应的函数必需为 static 函数,否则无法解析;

  • exceptionsToIgnore :用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出?


需要注意的是,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。?


示例:


1 public class TestService {23 // 对应的 handleException 函数需要位于 ExceptionUtil 类中,并且必须为 static 函数.4 @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})5 public void test() {6 System.out.println("Test");7 }89 // 原函数 10 @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")11 public String hello(long s) {12 return String.format("Hello at %d", s);13 }14


15 // Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.16 public String helloFallback(long s) {17 return String.format("Halooooo %d", s);18 }1920 // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.21 public String exceptionHandler(long s, BlockException ex) {22 // Do some log here.23 ex.printStackTrace();24 return "Oops, error occurred at " + s;25 }26 }


可以看到,blockHandler 和 fallback 必须与原方法在同一个类中。如果不想写在同一个类中,可以利用 blockHandlerClass 来指定类,然后通过 blockHandler 指定方法名。


如果同时配置了 blockHandler 和 fallback,则 BlockException 只会进到 blockHandler 处理逻辑中。

5. Sentinel 基本概念

资源


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


规则


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


流量控制


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



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


  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;

  • 运行指标,例如 QPS、线程池、系统负载等;

  • 控制的效果,例如直接限流、冷启动、排队等;?


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


熔断降级?


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



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


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



Sentinel 对这个问题采取了两种手段:


  • 通过并发线程数进行限制


和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。


  • 通过响应时间对资源进行降级


除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。


系统负载保护


Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。


针对这个情况,Senti


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


nel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

6. 如何使用 Sentinel

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。


资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:


  1. 定义资源

  2. 定义规则

  3. 检验规则是否生效?


在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。


定义资源的常用方式

方式一:?抛出异常的方式定义资源

SphU?包含了 try-catch 风格的 API。用这种方式,当资源发生了限流之后会抛出?BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理。示例代码如下:


1 // 1.5.0 版本开始可以利用 try-with-resources 特性 2 // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。3 try (Entry entry = SphU.entry("resourceName")) {4 // 被保护的业务逻辑 5 // do something here...6 } catch (BlockException ex) {7 // 资源访问阻止,被限流或被降级 8 // 在此处进行相应的处理操作 9 }


特别地,若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)),否则可能会有统计错误。这个时候不能使用 try-with-resources 的方式。另外通过 Tracer.trace(ex) 来统计异常信息时,由于 try-with-resources 语法中 catch 调用顺序的问题,会导致无法正确统计异常数,因此统计异常信息时也不能在 try-with-resources 的 catch 块中调用 Tracer.trace(ex)。


手动 exit 示例:


1 Entry entry = null;2 // 务必保证 finally 会被执行 3 try {4 // 资源名可使用任意有业务语义的字符串,注意数目不能太多(超过 1K),超出几千请作为参数传入而不要直接作为资源名 5 // EntryType 代表流量类型(inbound/outbound),其中系统规则只对 IN 类型的埋点生效 6 entry = SphU.entry("自定义资源名");7 // 被保护的业务逻辑 8 // do something...9 } catch (BlockException ex) {10 // 资源访问阻止,被限流或被降级 11 // 进行相应的处理操作 12 } catch (Exception ex) {13 // 若需要配置降级规则,需要通过这种方式记录业务异常 14 Tracer.traceEntry(ex, entry);15 } finally {16 // 务必保证 exit,务必保证每个 entry 与 exit 配对 17 if (entry != null) {18 entry.exit();19 }20 }


热点参数埋点示例:


1 Entry entry = null;2 try {3 // 若需要配置例外项,则传入的参数只支持基本类型。4 // EntryType 代表流量类型,其中系统规则只对 IN 类型的埋点生效 5 // count 大多数情况都填 1,代表统计为一次调用。6 entry = SphU.entry(resourceName, EntryType.IN, 1, paramA, paramB);7 // Your logic here.8 } catch (BlockException ex) {9 // Handle request rejection.10 } finally {11 // 注意:exit 的时候也一定要带上对应的参数,否则可能会有统计错误。12 if (entry != null) {13 entry.exit(1, paramA, paramB);14 }15 }


SphU.entry()?的参数描述:


方式二、注解方式定义资源

Sentinel 支持通过?@SentinelResource?注解定义资源并配置?blockHandler?和?fallback?函数来进行限流之后的处理。示例:


1 // 原本的业务方法.2 @SentinelResource(blockHandler = "blockHandlerForGetUser")3 public User getUserById(String id) {4 throw new RuntimeException("getUserById command failed");5 }67 // blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用 8 public User blockHandlerForGetUser(String id, BlockException ex) {9 return new User("admin");10 }

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Sentinel:万字详解微服务的哨兵机制,我跪了,mysql编程入门教程