全示例仓库:
clouddemo: https://gitee.com/huqingtao/sentinel-dashboard.git
sentinel-dashboard: https://gitee.com/huqingtao/spring-cloud-project.git
单项目多端口启动
VMoptions: -Dserver.port=8081
nacos
-
本地nacos单机启动
bin目录
startup.cmd -m standalone
-
nacos web后台 nacos/nacos
-
恢复nacos配置中心的sentinel配置
SENTINEL_GROUP.zip
解压移到:C:\Users\huqingtao\nacos\config\fixed-127.0.0.1_8848_nacos\snapshot
gateway核心
filter
Spring-Cloud-Gateway的过滤器接口分为两种:
GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上。
验证动态参数filter:AddUserInfoFilter
http://localhost:7060/provider/test/hello?str=kingtao
http://localhost:7060/provider/test/hello3?str=kingtao
http://localhost:7060/provider/test/hello5?str=kingtao&num=0
http://localhost:7060/provider/test/hello5?str=kingtao&num=1
http://localhost:7060/provider/test/hello6?str=kingtao&num=1
http://localhost:7060/provider/test/hello7?str=kingtao&num=1
http://localhost:7060/provider/test/hello8?str=kingtao
http://localhost:7060/provider/test/hello9?str=kingtao
http://localhost:7060/provider/test/hello10?str=kingtao
http://localhost:7060/consumer/test/send?str=kingtao
http://localhost:7060/consumer/test/send2?str=kingtao
sentinel 文档
-
本地sentinel单机启动
java -server -Xms64m -Xmx256m -Dserver.port=8849 -Dcsp.sentinel.dashboard.server=localhost:8849 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
-
sentinel web后台 sentinel/sentinel
-
规则配置说明
-
流控规则
[ { // 资源名 "resource": "/test", // 针对来源,若为 default 则不区分调用来源 "limitApp": "default", // 限流阈值类型(1:QPS;0:并发线程数) "grade": 1, // 阈值 "count": 1, // 是否是集群模式 "clusterMode": false, // 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待) "controlBehavior": 0, // 流控模式(0:直接;1:关联;2:链路) "strategy": 0, // 预热时间(秒,预热模式需要此参数) "warmUpPeriodSec": 10, // 超时时间(排队等待模式需要此参数) "maxQueueingTimeMs": 500, // 关联资源、入口资源(关联、链路模式) "refResource": "rrr" } ] 示例: [ { "resource": "provider-test0", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false }, { "resource": "provider-hello3", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
-
熔断降级规则: 熔断降级强依赖自定义fallBack方法
[ { // 资源名 "resource": "/test1", "limitApp": "default", // 熔断策略(0:慢调用比例,1:异常比率,2:异常计数) "grade": 0, // 最大RT、比例阈值、异常数 "count": 200, // 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) "slowRatioThreshold": 0.2, // 最小请求数 "minRequestAmount": 5, // 当单位统计时长(类中默认1000) "statIntervalMs": 1000, // 熔断时长 "timeWindow": 10 } ] 示例: [ { "resource": "provider-hello5", "limitApp": "default", "grade": 2, "count": 1, "slowRatioThreshold": 0.1, "minRequestAmount": 2, "statIntervalMs": 2000, "timeWindow": 10 },{ "resource": "provider-hello6", "limitApp": "default", "grade": 0, "count": 50, "slowRatioThreshold": 0.5, "minRequestAmount": 4, "statIntervalMs": 2000, "timeWindow": 10 },{ "resource": "/test/hello7", "limitApp": "default", "grade": 0, "count": 50, "slowRatioThreshold": 0.5, "minRequestAmount": 4, "statIntervalMs": 2000, "timeWindow": 10 } ]
-
热点参数规则:热点参数的注意点,参数必须是基本类型或者String(也就是方法体上面的参数必须为基本类型或String)
[ { // 资源名 "resource": "/test1", // 限流模式(QPS 模式,不可更改) "grade": 1, // 参数索引 "paramIdx": 0, // 单机阈值 "count": 13, // 统计窗口时长 "durationInSec": 6, // 是否集群 默认false "clusterMode": 默认false, // "burstCount": 0, // 集群模式配置 "clusterConfig": { // "fallbackToLocalWhenFail": true, // "flowId": 2, // "sampleCount": 10, // "thresholdType": 0, // "windowIntervalMs": 1000 }, // 流控效果(支持快速失败和匀速排队模式) "controlBehavior": 0, // "limitApp": "default", // "maxQueueingTimeMs": 0, // 高级选项 "paramFlowItemList": [ { // 参数类型 "classType": "int", // 限流阈值 "count": 222, // 参数值 "object": "2" } ] } ] 示例: [ { "resource": "provider-test8", "grade": 1, "paramIdx": 0, "count": 2, "durationInSec": 2, "burstCount": 0, "controlBehavior": 0, "limitApp": "default" } ]
-
系统规则:无resource,是对整个服务进程资源判断,qps模式慎用
[ { // RT "avgRt": 1, // CPU 使用率 "highestCpuUsage": -1, // LOAD "highestSystemLoad": -1, // 线程数 "maxThread": -1, // 入口 QPS "qps": -1 } ] 示例: [ { "avgRt": -1, "highestCpuUsage": -1, "highestSystemLoad": -1, "maxThread": -1, "qps": 2 } ]
授权规则:依赖自定义解析来源信息组件:RequestOriginParser
[ { // 资源名 "resource": "sentinel_spring_web_context", // 流控应用 "limitApp": "appA,appB", // 授权类型(0代表白名单;1代表黑名单。) "strategy": 0 } ] 示例: [ { "resource": "provider-test10", "limitApp": "gateway", "strategy": 1 } ]
-
-
特别说明
- 资源名-【自定义名】:如果sentinel后台设置得资源名为@SentinelResource的value,则触发的是全局异常:{@link com.example.providerservice.advice.GlobalExceptionHandler}
- a.当且仅当自定义名时,才能触发fallback、blockHandler
- 资源名-【路由】:如果sentinel后台设置的资源名为路由[/test/hello],则触发的是全局Block异常:{@link com.example.providerservice.sentinel.GlobalBlockExceptionHandler}
- 资源名-【自定义名】:如果sentinel后台设置得资源名为@SentinelResource的value,则触发的是全局异常:{@link com.example.providerservice.advice.GlobalExceptionHandler}
-
全局异常GlobalExceptionHandler、全局Block异常GlobalBlockExceptionHandler 和 fallback、blockHandler
- 全局异常和全局Block异常,项目中建议都添加
- 使用场景:接口源端流控
- 优点:便于偷懒,可随时对未设置资源名的接口流控
- fallback、blockHandler,项目中按需添加
- 使用场景:客户端对接口源端调用流控
- 优点:对远端接口流控时,可自定义资源返回结果
- 异同点:
- fallback:失败调用,若资源方法、接口出现未知异常,就会走fallback
- blockHandler:sentinel定义的失败调用或者限制调用,如限流、熔断降级,就会走blockHandler
- 关于[系统规则流控]
- 不可指定资源名:默认触发全局Block异常
- 全局异常和全局Block异常,项目中建议都添加
-
集群限流:需要注意
集群限流只有特定场景需要使用
单机流控的好处:集群扩容时不用考虑从新设置流控参数
+ Token Server自动管理(分配/选举)
+ Token Server高可用 自定义全局降级方法:BlockExceptionHandler 源码实现已代替UrlBlockHandler
-
引入sentinel所需依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
-
sentinel使用nacos配置中心
sentinel: transport: dashboard: 127.0.0.1:8849 # sentinel datasource nacos :http://blog.didispace.com/spring-cloud-alibaba-sentinel-2-1/ datasource: flow: nacos: server-addr: 127.0.0.1:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow degrade: nacos: server-addr: 127.0.0.1:8848 dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP rule-type: degrade system: nacos: server-addr: 127.0.0.1:8848 dataId: ${spring.application.name}-system-rules groupId: SENTINEL_GROUP rule-type: system authority: nacos: server-addr: 127.0.0.1:8848 dataId: ${spring.application.name}-authority-rules groupId: SENTINEL_GROUP rule-type: authority param-flow: nacos: server-addr: 127.0.0.1:8848 dataId: ${spring.application.name}-param-flow-rules groupId: SENTINEL_GROUP rule-type: param-flow
-
常见限流算法
-
令牌桶算法
所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
根据限流大小,设置按照一定的速率往桶里添加令牌;
桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
-
漏桶算法
就是注水流水过程
以任务速率流入水,以固定速率流出水
弊端:无法应对短时间的突发流量
-
滑动窗口
-
计数器算法
计数器算法是限流算法里最简单也是最容易实现的一种算法。
比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。
那么我们可以这么做:在一开 始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个 请求的间隔时间还在1分钟之内,那么说明请求数过多;
如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter
-
滑动窗口算法
更加细粒度的计数器算法 ==》 就是滑动窗口算法
当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确
-
-
provider接口
http://localhost:7073/provider/test/hello?str=kingtao&userId=100
consumer
- openfeign调用provider
- 开启sentinel支持
feign: sentinel: enabled: true
- 可设置全局ribbon超时
ribbon: ReadTimeout: 1000 ConnectTimeout: 1000
- feignclient
@FeignClient(value = "provider-service", fallback = ProviderClientFallBack.class) @SentinelResource: 对于feignClient资源名定义,不可定义, 直接使用:GET:http://[nacos-servicename]/[route] 例:GET:http://provider-service/provider/test/hello
sleuth + zipkin
-
基本使用
- pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
- yml配置
zipkin: base-url: http://localhost:9411 sender: type: web # 可配置web、mq sleuth: sampler: probability: 1.0
原理介绍sleuth
-
zipkin
- 本地启动、访问
统计数据保存到内存启动方式 java -Xms64m -Xmx256m -jar zipkin-server-2.23.9-exec.jar 统计数据保存到mysql启动方式 java -Xms64m -Xmx256m -jar zipkin-server-2.23.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=123456 访问地址 http://localhost:9411/zipkin/
- zipkin统计数据保存到mysql
- 创建mysql相关表
CREATE DATABASE zipkin; CREATE TABLE IF NOT EXISTS zipkin_spans ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL, `id` BIGINT NOT NULL, `name` VARCHAR(255) NOT NULL, `remote_service_name` VARCHAR(255), `parent_id` BIGINT, `debug` BIT(1), `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query', PRIMARY KEY (`trace_id_high`, `trace_id`, `id`) ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds'; ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames'; ALTER TABLE zipkin_spans ADD INDEX(`remote_service_name`) COMMENT 'for getTraces and getRemoteServiceNames'; ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range'; CREATE TABLE IF NOT EXISTS zipkin_annotations ( `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit', `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id', `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id', `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1', `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB', `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation', `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null' ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci; ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds'; ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames'; ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces and autocomplete values'; ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces and autocomplete values'; ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job'; CREATE TABLE IF NOT EXISTS zipkin_dependencies ( `day` DATE NOT NULL, `parent` VARCHAR(255) NOT NULL, `child` VARCHAR(255) NOT NULL, `call_count` BIGINT, `error_count` BIGINT, PRIMARY KEY (`day`, `parent`, `child`) ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;