SpringCloud Alibaba为微服务开发提供了一站式解决方案,只需非常少量的配置,即可使用服务管理、配置管理、流控与降级、分布式事务、事件驱动等功能。
x1<!--添加SpringCloud Alibaba依赖管理(一般添加在聚合工程)-->2<dependencyManagement>3 <dependencies>4 <dependency>5 <groupId>com.alibaba.cloud</groupId>6 <artifactId>spring-cloud-alibaba-dependencies</artifactId>7 <version>2021.0.1.0</version>8 <type>pom</type>9 <scope>import</scope>10 </dependency>11 </dependencies>12</dependencyManagement>13
注意:请谨慎搭配SpringBoot、SpringCloud与SingCloud Alibaba之间的版本,可参考:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E。
Nacos是一个易于使用的动态服务发现、配置和服务管理平台,用于构建云原生应用程序。
从Github下载Nacos的最新稳定版本(Windows平台为zip格式),解压到合适的目录即可完成安装。
进入bin目录,执行startup.cmd -m standalone命令启动Nacos单机版,启动完成后如下:

浏览器访问http://localhost:8848/nacos,通过nacos/nacos用户进行登录,进入Nacos控制面板:

更多资料可参考:https://nacos.io/zh-cn/docs/quick-start.html。
从Github下载Nacos的最新稳定版本(Linux平台为tar.gz格式),上传到Linux服务器(推荐/usr/local/nacos目录)后进行解压,并将解压后的nacos目录命名为nacos8848。

编辑conf/application.properties文件,修改server.port属性及数据库相关配置。

注意: 请在配置数据库nacos_config中执行conf/nacos-mysql.sql下的初始化脚本。
复制conf/cluster.conf.example为conf/cluster.conf并进行编辑,修改为自己的Nacos集群所分配的IP地址和端口。

复制两份nacos8848目录,分别为nacos8858、nacos8868,再修改conf/application.properties文件中的server.port属性为对应的端口。
vim nacos8858/conf/application.properties

vim nacos8868/conf/application.properties

修改conf/nginx.conf,配置如下代理:

使用bin/starup.sh依次启动nacos8848、nacos8858、nacos8868,使用sbin/nginx -c /usr/local/nginx/conf/nginx.conf启动Nginx,然后访问Nginx入口http://192.168.213.128/nacos/#/login进行登录,登录后界面如下所示:

Nacos默认使用嵌入式数据库Derby,在分布式环境下会出现数据不一致问题,所以必须配置Mysql外部存储。
如果Nacos集群在同一台机器,则端口不能连续(如8848、8849、8850等),由于Nacos服务会使用多个端口,可能导致端口冲突。
如果仅可在本地访问,而不能在其它机器访问,可以尝试关闭防火墙:systemctl stop firewalld.service。
Nacos Discovery可自动将服务实例及相关的元数据(如主机、端口、运行状况检查URL、主页等)注册到Nacos服务器,并集成了RestTemplate、OpenFeign和Ribbon,可以方便的进行服务间调用和负载均衡。
491 2<project xmlns="http://maven.apache.org/POM/4.0.0"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">5 <parent>6 <artifactId>SpringCloud-demo</artifactId>7 <groupId>com.huangyuanxin.SpringCloud</groupId>8 <version>1.0-SNAPSHOT</version>9 </parent>10 <modelVersion>4.0.0</modelVersion>11
12 <artifactId>SpringCloud-nacos-provider</artifactId>13
14 <dependencies>15 <!--SpringCloud ailibaba nacos -->16 <dependency>17 <groupId>com.alibaba.cloud</groupId>18 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>19 </dependency>20 <!-- SpringBoot整合Web组件 -->21 <dependency>22 <groupId>org.springframework.boot</groupId>23 <artifactId>spring-boot-starter-web</artifactId>24 </dependency>25 <dependency>26 <groupId>org.springframework.boot</groupId>27 <artifactId>spring-boot-starter-actuator</artifactId>28 </dependency>29 <!--日常通用jar包配置-->30 <dependency>31 <groupId>org.springframework.boot</groupId>32 <artifactId>spring-boot-devtools</artifactId>33 <scope>runtime</scope>34 <optional>true</optional>35 </dependency>36 <dependency>37 <groupId>org.projectlombok</groupId>38 <artifactId>lombok</artifactId>39 <optional>true</optional>40 </dependency>41 <dependency>42 <groupId>org.springframework.boot</groupId>43 <artifactId>spring-boot-starter-test</artifactId>44 <scope>test</scope>45 </dependency>46 </dependencies>47
48</project>49 注意:必须先在dependencyManagement标签中进行spring-cloud-alibaba-dependencies的依赖管理,请参考本文档前言部分。
181server2 port81313
4spring5 application6 namecloud-provider-payment7 cloud8 nacos9 discovery10 server-addrlocalhost8848 #配置Nacos地址11
12management13 endpoints14 web15 exposure16 include'*'17
18
151package com.huangyuanxin.springcloud.nacos.provider;2
3import org.springframework.boot.SpringApplication;4import org.springframework.boot.autoconfigure.SpringBootApplication;5import org.springframework.cloud.client.discovery.EnableDiscoveryClient;6
7
89 # 开启服务发现功能10public class NacosProviderApplication {11 public static void main(String[] args) {12 SpringApplication.run(NacosProviderApplication.class, args);13 }14}15
191package com.huangyuanxin.springcloud.nacos.provider.controller;2
3import org.springframework.beans.factory.annotation.Value;4import org.springframework.web.bind.annotation.RequestMapping;5import org.springframework.web.bind.annotation.RestController;6
7import java.util.UUID;8
910public class PaymentController {11 ("${server.port}")12 private String serverPort;13
14 (value = "/payment/nacos")15 public String paymentnacos() {16 return "springcloud with nacos: " + serverPort + "\t" + UUID.randomUUID().toString();17 }18}19
先通过startup.cmd -m standalone启动Nacos单机版,再启动cloud-provider-payment服务,然后通过复制配置和--server.port=8132外部参数的方式启动第2个cloud-provider-payment服务组成集群。
测试两个服务都正常访问:ocalhost:8131/payment/nacos、ocalhost:8132/payment/nacos

两个服务成功注册到Nacos:http://localhost:8848/nacos

491 2<project xmlns="http://maven.apache.org/POM/4.0.0"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">5 <parent>6 <artifactId>SpringCloud-demo</artifactId>7 <groupId>com.huangyuanxin.SpringCloud</groupId>8 <version>1.0-SNAPSHOT</version>9 </parent>10 <modelVersion>4.0.0</modelVersion>11
12 <artifactId>SpringCloud-nacos-consumer</artifactId>13
14 <dependencies>15 <!--SpringCloud ailibaba nacos -->16 <dependency>17 <groupId>com.alibaba.cloud</groupId>18 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>19 </dependency>20 <!-- SpringBoot整合Web组件 -->21 <dependency>22 <groupId>org.springframework.boot</groupId>23 <artifactId>spring-boot-starter-web</artifactId>24 </dependency>25 <dependency>26 <groupId>org.springframework.boot</groupId>27 <artifactId>spring-boot-starter-actuator</artifactId>28 </dependency>29 <!--日常通用jar包配置-->30 <dependency>31 <groupId>org.springframework.boot</groupId>32 <artifactId>spring-boot-devtools</artifactId>33 <scope>runtime</scope>34 <optional>true</optional>35 </dependency>36 <dependency>37 <groupId>org.projectlombok</groupId>38 <artifactId>lombok</artifactId>39 <optional>true</optional>40 </dependency>41 <dependency>42 <groupId>org.springframework.boot</groupId>43 <artifactId>spring-boot-starter-test</artifactId>44 <scope>test</scope>45 </dependency>46 </dependencies>47
48</project>49
201server2 port82303
4
5spring6 application7 namecloud-consumer-order8 cloud9 nacos10 discovery11 server-addrlocalhost8848 #Nacos地址12
13
14#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)15service-url16 payment-servicehttp//cloud-provider-payment17
18
19
20
141package com.huangyuanxin.springcloud.nacos.consumer;2
3import org.springframework.boot.SpringApplication;4import org.springframework.boot.autoconfigure.SpringBootApplication;5import org.springframework.cloud.client.discovery.EnableDiscoveryClient;6 78 // 开启服务发现功能9public class NacosConsumerApplication {10 public static void main(String[] args) {11 SpringApplication.run(NacosConsumerApplication.class, args);12 }13}14
181package com.huangyuanxin.springcloud.nacos.consumer.config;2
3import org.springframework.cloud.client.loadbalancer.LoadBalanced;4import org.springframework.context.annotation.Bean;5import org.springframework.context.annotation.Configuration;6import org.springframework.web.client.RestTemplate;7
8
910public class ApplicationContextBean {11 12 13 public RestTemplate getRestTemplate() {14 return new RestTemplate();15 }16}17 18
241package com.huangyuanxin.springcloud.nacos.consumer.controller;2
3import org.springframework.beans.factory.annotation.Value;4import org.springframework.web.bind.annotation.RequestMapping;5import org.springframework.web.bind.annotation.RestController;6import org.springframework.web.client.RestTemplate;7
8import javax.annotation.Resource;9
1011public class OrderController {12 13 private RestTemplate restTemplate;14
15 ("${service-url.payment-service}")16 private String serverURL;17
18 (value = "/consumer/payment/nacos")19 public String paymentInfo() {20 String result = restTemplate.getForObject(serverURL + "/payment/nacos", String.class);21 return "消费者调用支付服务(nacos)--->result:" + result;22 }23}24
依次启动Nacos、cloud-provider-payment集群、cloud-consumer-order服务进行测试:
测试cloud-consumer-order调用cloud-provider-payment集群正常,并且支持负载均衡:http://localhost:8230/consumer/payment/nacos

cloud-consumer-order正常注册到nacos:

Nacos Discovery会给微服务添加一个nacos-discovery端点,可通过http://localhost:8131/actuator/nacos-discovery进行访问,包含了如下一些信息:
订阅信息: 显示当前服务订阅者。
NacosDiscovery属性: 显示当前服务的当前基本 Nacos 配置。
621{2 "subscribe": [3 {4 "jsonFromServer": "",5 "name": "nacos-provider",6 "clusters": "",7 "cacheMillis": 10000,8 "hosts": [9 {10 "instanceId": "30.5.124.156#8081#DEFAULT#nacos-provider",11 "ip": "30.5.124.156",12 "port": 8081,13 "weight": 1.0,14 "healthy": true,15 "enabled": true,16 "cluster": {17 "serviceName": null,18 "name": null,19 "healthChecker": {20 "type": "TCP"21 },22 "defaultPort": 80,23 "defaultCheckPort": 80,24 "useIPPort4Check": true,25 "metadata": {26
27 }28 },29 "service": null,30 "metadata": {31
32 }33 }34 ],35 "lastRefTime": 1541755293119,36 "checksum": "e5a699c9201f5328241c178e804657e11541755293119",37 "allIPs": false,38 "key": "nacos-provider",39 "valid": true40 }41 ],42 "NacosDiscoveryProperties": {43 "serverAddr": "127.0.0.1:8848",44 "endpoint": "",45 "namespace": "",46 "logName": "",47 "service": "nacos-provider",48 "weight": 1.0,49 "clusterName": "DEFAULT",50 "metadata": {51
52 },53 "registerEnabled": true,54 "ip": "30.5.124.201",55 "networkInterface": "",56 "port": 8082,57 "secure": false,58 "accessKey": "",59 "secretKey": ""60 }61}62
下面显示了Nacos Discovery的启动器的其他配置:
| 配置 | 钥匙 | 默认值 | 描述 |
|---|---|---|---|
| 服务器地址 | spring.cloud.nacos.discovery.server-addr | Nacos 服务器侦听器的 IP 和端口 | |
| 服务名称 | spring.cloud.nacos.discovery.service | ${spring.application.name} | 为当前服务命名 |
| 重量 | spring.cloud.nacos.discovery.weight | 1 | 取值范围:1~100。值越大,重量越大 |
| 网卡名称 | spring.cloud.nacos.discovery.network-interface | 如果未指定 IP 地址,则注册的 IP 地址为网卡的 IP 地址。如果未指定,则默认情况下将使用第一个网卡的 IP 地址。 | |
| 注册的 IP 地址 | spring.cloud.nacos.discovery.ip | 最高优先级 | |
| 已注册的端口 | spring.cloud.nacos.discovery.port | -1 | 默认情况下将自动检测。不需要配置。 |
| Namespace | spring.cloud.nacos.discovery.namespace | 一个典型的场景是隔离不同环境的服务注册,如资源(配置、服务等)在测试和生产环境之间隔离 | |
| 访问密钥 | spring.cloud.nacos.discovery.access-key | 阿里云账号访问密钥 | |
| 密钥 | spring.cloud.nacos.discovery.secret-key | 阿里云账号密钥 | |
| 元数据 | spring.cloud.nacos.discovery.metadata | 您可以以 Map 格式为服务定义一些元数据 | |
| 日志文件名 | spring.cloud.nacos.discovery.log-name | ||
| 群集名称 | spring.cloud.nacos.discovery.cluster-name | DEFAULT | Nacos 的集群名称 |
| 端点 | spring.cloud.nacos.discovery.endpoint | 特定区域中特定服务的域名。您可以使用此域名动态检索服务器地址 | |
| 是否集成功能区 | ribbon.nacos.enabled | true | 在大多数情况下设置为 true |
| 启用 Nacos 手表 | spring.cloud.nacos.discovery.watch.enabled | true | 设置为 false 以关闭监视 |

Nacos默认为AP模式(高可用),可通过如下请求切换为CP模式(一致性):
21curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'2
Nacos Config用于集中管理微服务的外部化配置文件,支持Namespace、Group、dataId三级分类,并且当服务端配置修改后,会自动同步到客户端以及实时刷新配置信息。
71<!--SpringCloud-nacos-provider/pom.xml-->2
3<!--SpringCloud ailibaba nacos-config-->4<dependency>5 <groupId>com.alibaba.cloud</groupId>6 <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>7</dependency>
151# 一定要放置在bootstrap.yml,不能是application.yml2
3spring4 application5 namecloud-provider-payment6 profiles7 activedev8 cloud9 nacos10 config11 server-addr127.0.0.18848 # Nacos地址,可写IP或域名12 namespacee786f42a-bf7c-4bf2-9917-5023f80588b8 #名称空间,默认为public13 groupDEMO_GROUP # 组名,默认为DEFAULT_GROUP14 file-extensionyaml # 后缀,支持yaml(yml)和properties格式15
如上配置会自动从Nacos服务端拉取 e786f42a-bf7c-4bf2-9917-5023f80588b8/DEMO_GROUP/cloud-provider-payment-dev.yaml 文件。
拉取文件的公式为:${server-addr}/${namespace}/${group}/${spring.application.name}-${spring.profiles.active}.${file-extension}。
1312 // 支持自动刷新3public class PaymentController {4
5 ("${config.info}")6 private String info;7
8 ("/payment/info")9 public String paymentInfo() {10 return info;11 }12}13
先进入Nacos服务端,新增e786f42a-bf7c-4bf2-9917-5023f80588b8名称空间(该ID自动生成,与配置中一致即可):

进入新增的namespace,新增DEMO_GROUP/cloud-provider-payment-dev.yaml文件,编辑配置如下:

再启动支付微服务,访问http://localhost:8131/payment/info可以看到拉取的配置信息,并且当Nacos服务端配置修改时,支付服务会实时刷新配置。

上面的${group}/${spring.application.name}-${spring.profiles.active}.${file-extension}部分配置也可通过extensionConfigs属性来配置:
181spring2 application3 namecloud-provider-payment4 profiles5 activedev6 cloud7 nacos8 config9 server-addr127.0.0.18848 # Nacos地址10 namespacee786f42a-bf7c-4bf2-9917-5023f80588b8 #名称空间11# file-extension: yaml 12# group: DEMO_GROUP13 # 直接指定组和dataId,此时文件拉取格式为:${server-addr}/${namespace}/${group}/${data-id}14 extensionConfigs15groupDEMO_GROUP16 data-idcloud-provider-payment-dev.yaml # dataId,由应用名、profile、后缀名组成17 refreshtrue # 是否自动刷新配置,默认为false18
注意:
extensionConfigs中可同时配置多个dataId组成列表,列表索引越大的配置优先级越高。
使用自定义dataId的配置允许在多个应用程序之间共享配置,并且还支持一个应用程序的多个配置。
31# https://spring-cloud-alibaba-group.github.io/github-pages/2021/en-us/index.html#_support_custom_data_id2spring.cloud.nacos.config.shared-dataids=bootstrap-common.properties,all-common.properties3spring.cloud.nacos.config.refreshable-dataids=bootstrap-common.properties
Nacos Config会给微服务添加一个nacos-config端点,可通过http://localhost:8131/actuator/nacos-config进行访问,包含了如下一些信息:
来源:当前应用程序配置数据信息。
刷新历史记录:配置刷新历史记录。
NacosConfig属性:显示当前服务的当前基本Nacos配置。
361{2 "NacosConfigProperties": {3 "serverAddr": "127.0.0.1:8848",4 "encode": null,5 "group": "DEFAULT_GROUP",6 "prefix": null,7 "fileExtension": "properties",8 "timeout": 3000,9 "endpoint": null,10 "namespace": null,11 "accessKey": null,12 "secretKey": null,13 "contextPath": null,14 "clusterName": null,15 "name": null,16 "sharedDataids": "base-common.properties,common.properties",17 "refreshableDataids": "common.properties",18 "extConfig": null19 },20 "RefreshHistory": [{21 "timestamp": "2019-07-29 11:20:04",22 "dataId": "nacos-config-example.properties",23 "md5": "7d5d7f1051ff6571e2ec9f90887d9d91"24 }],25 "Sources": [{26 "lastSynced": "2019-07-29 11:19:04",27 "dataId": "common.properties"28 }, {29 "lastSynced": "2019-07-29 11:19:04",30 "dataId": "base-common.properties"31 }, {32 "lastSynced": "2019-07-29 11:19:04",33 "dataId": "nacos-config-example.properties"34 }]35}36
下面显示了Nacos Config的启动器的其他配置:
| 配置属性 | 默认值 | 描述 |
|---|---|---|
| spring.cloud.nacos.config.server-addr | Nacos服务器侦听器的IP(域名)和端口 | |
| spring.cloud.nacos.config.name | 配置文件名,默认为spring.application.name | |
| spring.cloud.nacos.config.prefix | 配置文件前缀 | |
| spring.cloud.nacos.config.encode | 配置文件的编码格式 | |
| spring.cloud.nacos.config.group | DEFAULT_GROUP | 所属组名 |
| spring.cloud.nacos.config.fileExtension | properties | 配置文件后缀名,支持properties或yaml(yml) |
| spring.cloud.nacos.config.timeout | 3000 | 从nacos获取配置的超时时间 |
| spring.cloud.nacos.config.endpoint | 端点 | |
| spring.cloud.nacos.config.namespace | 名称空间 | |
| spring.cloud.nacos.config.accessKey | 阿里云账号访问密钥 | |
| spring.cloud.nacos.config.secretKey | 阿里云账号密钥 | |
| spring.cloud.nacos.config.contextPath | Nacos服务器的上下文路径 | |
| spring.cloud.nacos.config.clusterName | 群集名称 | |
| spring.cloud.nacos.config.sharedDataids | 共享配置的Dataid,按","拆分 | |
| spring.cloud.nacos.config.refreshableDataids | 共享配置的动态刷新数据标识,按","拆分 | |
| spring.cloud.nacos.config.extConfig | 这是一个Config列表,有dataId、group、refresh 几个属性 | |
| spring.cloud.nacos.config.enabled | true | 是否开启Nacos自动配置 |
| spring.cloud.nacos.config.refresh.enabled | true | 是否自动刷新Nacos配置修改 |
提示:Nacos2.0.4版本以上支持配置加密,可参考https://nacos.io/zh-cn/docs/config-encryption.html。
Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
| Sentinel | Hystrix | resilience4j | |
|---|---|---|---|
| 隔离策略 | 信号量隔离(并发控制) | 线程池隔离/信号量隔离 | 信号量隔离 |
| 熔断降级策略 | 基于慢调用比例、异常比例、异常数 | 基于异常比例 | 基于异常比例、响应时间 |
| 实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
| 动态规则配置 | 支持近十种动态数据源 | 支持多种数据源 | 有限支持 |
| 扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
| 基于注解的支持 | 支持 | 支持 | 支持 |
| 单机限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
| 集群流控 | 支持 | 不支持 | 不支持 |
| 流量整形 | 支持预热模式与匀速排队控制效果 | 不支持 | 简单的 Rate Limiter 模式 |
| 系统自适应保护 | 支持 | 不支持 | 不支持 |
| 热点识别/防护 | 支持 | 不支持 | 不支持 |
| 多语言支持 | Java/Go/C++ | Java | Java |
| Service Mesh 支持 | 支持 Envoy/Istio | 不支持 | 不支持 |
| 控制台 | 提供开箱即用的控制台,可配置规则、实时监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
Sentinel 的使用可以分为两个部分:
核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境。
控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。
从Github(https://github.com/alibaba/Sentinel/tags)下载Sentinel的最新稳定版本,使用java -jar sentinel-dashboard-1.8.4.jar命令运行,启动成功后如下:

注意:
Sentinel要求安装JDK8+环境,并且使用了8080端口,端口可通过
-Dserver.port=8080启动参数修改。若在单台机器上运行相同服务的多个实例,则需要通过
-Dcsp.sentinel.log.use.pid=true来保证不同实例日志的独立性。
访问http://localhost:8080,通过sentinel/sentinel登录,进入Dashboard 界面:

下面是一些控制台的启动参数,包括用户名、密码、会话过期时间等。
| 配置项 | 类型 | 默认值 | 最小值 | 描述 |
|---|---|---|---|---|
| auth.enabled | boolean | true | - | 是否开启登录鉴权,仅用于日常测试,生产上不建议关闭 |
| sentinel.dashboard.auth.username | String | sentinel | - | 登录控制台的用户名,默认为 sentinel |
| sentinel.dashboard.auth.password | String | sentinel | - | 登录控制台的密码,默认为 sentinel |
| sentinel.dashboard.app.hideAppNoMachineMillis | Integer | 0 | 60000 | 是否隐藏无健康节点的应用,距离最近一次主机心跳时间的毫秒数,默认关闭 |
| sentinel.dashboard.removeAppNoMachineMillis | Integer | 0 | 120000 | 是否自动删除无健康节点的应用,距离最近一次其下节点的心跳时间毫秒数,默认关闭 |
| sentinel.dashboard.unhealthyMachineMillis | Integer | 60000 | 30000 | 主机失联判定,不可关闭 |
| sentinel.dashboard.autoRemoveMachineMillis | Integer | 0 | 300000 | 距离最近心跳时间超过指定时间是否自动删除失联节点,默认关闭 |
| sentinel.dashboard.unhealthyMachineMillis | Integer | 60000 | 30000 | 主机失联判定,不可关闭 |
| server.servlet.session.cookie.name | String | sentinel_dashboard_cookie | - | 控制台应用的 cookie 名称,可单独设置避免同一域名下 cookie 名冲突 |
提示:通过环境变量进行配置时,因为不支持
.所以需要将其更换为_。
61<!--SpringCloud ailibaba sentinel -->2<dependency>3 <groupId>com.alibaba.cloud</groupId>4 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>5</dependency>6
81spring2 application3 namecloud-provider-payment4 cloud5 sentinel6 transport7 dashboardlocalhost8080 #配置Sentinel地址8
1412("/sentinel")3public class SentinelTestController {4 ("/testA")5 public String testA() {6 return UUID.randomUUID().toString();7 }8
9 ("/testB")10 public String testB() {11 return UUID.randomUUID().toString();12 }13}14
依次启动Nacos、Sentinel和支付服务,先调用http://localhost:8131/sentinel/testA和http://localhost:8131/sentinel/testB测试业务接口,再登录Sentinel(http://localhost:8080/)查看监控情况。

资源是Sentinel所保护的对象,可以是某个服务、请求URL、方法,甚至是一段代码等。默认情况下,Sentinel对一些主流框架(Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor等)进行了适配,如自动将请求路径作为资源名等。
我们也可以通过@SentinelResource注解方式来定义资源,其常用的属性如下:
value: 资源名称(必选项)。
entryType:entry类型,默认为EntryType.OUT。
blockHandler/blockHandlerClass:可用于处理BlockException异常的方法名及所属类。
该方法要求兼容原方法的参数类型(允许多加一个BlockException类型参数来接收对应异常)和返回值。
并且如果配置了所属类,则必须为静态方法。
fallback/fallbackClass:可用于处理所有类型异常的方法名及所属类。
该方法要求兼容原方法的参数类型(允许多加一个Throwable类型参数来接收对应异常)和返回值。
并且如果配置了所属类,则必须为静态方法。
defaultFallback(since 1.6.0):默认处理方法名,在未配置fallback时生效,要求方法参数为空或仅有一个Throwable类型参数。
exceptionsToIgnore(since 1.6.0):配置的异常将会被直接抛出,不会计入异常统计,也不会进入 fallback 逻辑中。
161// ---------- Test.java -----------------2(value = "hello", blockHandlerClass = {ExceptionUtil.class}, blockHandler = "helloBlockHandler", fallback = "helloFallback")3public String hello(long s) {4 return String.format("Hello at %d", s);5}6
7public String helloFallback(long s) {8 return String.format("Halooooo %d", s);9}10
11
12// ---------- ExceptionUtil.java -----------------13public static String helloBlockHandler(long s, BlockException ex) {14 ex.printStackTrace();15 return "Oops, error occurred at " + s;16}注意:
注解方式埋点不支持 private 方法。
1.6.0之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。
Sentinel也可以通过代码方式来定义资源和支持异步调用,但与业务代码耦合度高,不推荐使用,相关资料请参考官方文档。
规则是针对特定资源如何进行处理的描述,Sentinel的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和热点参数规则。
Sentinel会根据实时统计信息,在访问资源前判断是否符合所有的流量控制规则,如果超过设置的阈值,则抛出FlowException异常。
下面是流量控制的一些配置选项:
资源名(resource):限流的资源对象。
针对来源(limitApp):针对的资源调用者(服务名),默认为default,表示不区分来源。
阈值类型(grade):可选择QPS(每秒请求数)或并发线程数。
单机阈值(count):大于1的整数,指QPS或并发线程数的限流阈值。
流控模式(strategy):可选直接、关联、链路,下面将会详细讲解。
流控效果(controlBehavior):表示触发流控后的处理方式。可选直接拒绝、Warm Up(预热)、排队等待。
直接流控模式直接对目标资源进行流控。如下设置/sentinel/testA资源的QPS阈值为1:

当每秒请求数超过1次时则进行流控,默认效果为直接失败,返回 Blocked by Sentinel (flow limiting):

关联流控模式是在关联的资源访问超过阈值时,才对目标资源进行流控。如下设置/sentinel/testA资源的QPS阈值为1,关联资源为/sentinel/testB:

当/sentinel/testB每秒请求数超过1次时,对/sentinel/testA进行流控。
链路流控模式只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。
使用@SentinelResource注解定义doService资源如下:
812public class DemoService {3 ("doService")4 public String doService() {5 return UUID.randomUUID().toString();6 }7}8
通过两条不同的链路访问该资源:
2012("/sentinel")3public class SentinelTestController {4 5 private DemoService demoService;6 7 // 测试链路流控规则(与testC2一起)8 ("/testC1")9 public String testC1() {10 return demoService.doService();11 }12
13 // 测试链路流控规则(与testC1一起)14 ("/testC2")15 public String testC2() {16 return demoService.doService();17 }18}19
20
如下设置表示只有从/sentinel/testC2访问doService资源才会被限流。

注意:
调用doService资源时必须被SpringAOP拦截,否则链路流控规则失效。
从1.6.3版本开始,Sentinel Web Filter默认收敛所有URL的入口context,导致链路限流不生效。
解决方案:从1.7.0版本开始,官方在CommonFilter引入了WEB_CONTEXT_UNIFY参数,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流。首先引入依赖如下:
41<dependency>2<groupId>com.alibaba.csp</groupId>3<artifactId>sentinel-web-servlet</artifactId>4</dependency>然后添加如下配置:
281package com.huangyuanxin.springcloud.nacos.provider.config;23import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;4import org.springframework.boot.web.servlet.FilterRegistrationBean;5import org.springframework.context.annotation.Bean;6import org.springframework.context.annotation.Configuration;789public class FilterContextConfig {10/**11* @NOTE 在spring-cloud-alibaba v2.1.1.RELEASE及前,sentinel1.7.0及后,关闭URL PATH聚合需要通过该方式,spring-cloud-alibaba v2.1.1.RELEASE后,可以通过配置关闭:spring.cloud.sentinel.web-context-unify=false12* 手动注入Sentinel的过滤器,关闭Sentinel注入CommonFilter实例,修改配置文件中的 spring.cloud.sentinel.filter.enabled=false13* 入口资源聚合问题:https://github.com/alibaba/Sentinel/issues/1024 或 https://github.com/alibaba/Sentinel/issues/121314* 入口资源聚合问题解决:https://github.com/alibaba/Sentinel/pull/111115*/1617public FilterRegistrationBean sentinelFilterRegistration() {18FilterRegistrationBean registration = new FilterRegistrationBean();19registration.setFilter(new CommonFilter());20registration.addUrlPatterns("/*");21// 入口资源关闭聚合22registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");23registration.setName("sentinelFilter");24registration.setOrder(1);25return registration;26}27}28
流控效果除了默认的直接失败外,还可以选择Warm Up(预热)或排队等待方式。
Warm Up(预热)
该流控效果用于防止突发的大流量冲跨系统,其采用令牌桶算法进行流量整形和限制,在预热时长内逐渐提高阈值。如下设置表示阈值在5s内从33(约为最高阈值的1/3)提高到100。

排队等待
该流控效果用于防止间隔性的突发流量,其采用漏桶算法让请求均速通过,多余的请求进行排队等待。如下设置表示每秒处理10个请求,多余的请求排队等待,等待超过1000ms则报错处理。

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。
下面是熔断的一些配置选项:
资源名(resource):限流的资源对象。
熔断策略(grade):支持慢调用比例、异常比例、异常数策略,下面将会详细讲解。
单机阈值(count):慢调用比例策略下表示最大响应时长,异常比例/异常数模式下为对应的阈值。
熔断时长(timeWindow):触发熔断后的熔断时长,该时间段内请求直接被拒绝。
最小请求数(minRequestAmount):熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(since 1.7.0)。
统计时长(statIntervalMs):统计的时间窗口时长(since 1.8.0)。
慢调用比例阈值(slowRatioThreshold):仅慢调用比例模式有效(since 1.8.0)。
该熔断策略下,当满足下面两个条件时,则接下来一段时间内(熔断时长)该资源被熔断:
单位统计时长内的请求数大于设置的最小请求数。
慢调用(响应时间超过设置的时间阈值RT)的比例大于设置的比例阈值。
经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若下一个请求的响应时间小于阈值则结束熔断,否则再次被熔断。

该熔断策略下,当满足下面两个条件时,则接下来一段时间内(熔断时长)该资源被熔断:
单位统计时长内的请求数大于设置的最小请求数。
异常的比例大于阈值。
经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若下一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

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

从整体维度对应用入口流量进行控制,结合应用的Load、CPU使用率、总体平均RT、入口QPS和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则支持以下的阈值类型:
Load(highestSystemLoad):当系统load1超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的maxQps*minRt计算得出,设定参考值一般是CPU cores * 2.5(仅对Linux/Unix-like机器生效)。
RT(avgRt):当单台机器上所有入口流量的平均响应时间达到阈值即触发系统保护,单位是毫秒。
线程数(maxThread):当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
入口QPS(qps):当单台机器上所有入口流量的QPS达到阈值即触发系统保护。
CPU使用率(highestCpuUsage):当系统CPU使用率超过阈值即触发系统保护(1.5.0+ 版本)。

注意:入口流量指的是EntryType.IN类型流量,比如Web服务或Dubbo服务端接收的请求,都属于入口流量。
访问控制规则通俗来说就是针对调用方(Origin)的黑白名单功能。主要有以下配置项:
资源名(resource):资源名,即限流规则的作用对象。
流控应用(limitApp):调用方的白名单或黑名单列表,如有多个则用逗号分隔,如app1,app2。
授权类型(strategy):限制模式,可选白名单模式或黑名单模式。
如下代码在访问doService资源前设置Origin为app1:
2512("/sentinel")3public class SentinelTestController {4 5 private DemoService demoService;6
7 ("/testE")8 public String testE() {9 // 设置Origin10 Context enter = ContextUtil.enter("doService", "app1");11 enter.setOrigin("app1");12
13 return demoService.doService();14 }15}16
17
1819public class DemoService {20 ("doService")21 public String doService() {22 return UUID.randomUUID().toString();23 }24}25
如果对doService资源设置访问控制,则仅当白名单包含app1或黑名单不包含app1时可访问该资源,设置如下:

注意:调用doService资源时必须被SpringAOP拦截,否则访问控制规则失效。
热点参数流控是Sentinel利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流量控制。下面是其配置说明:
资源名(resource):资源名,即限流规则的作用对象。
限流模式(grade):默认为QPS模式。
参数索引(paramIdx):热点参数的索引,从0开始。
单机阈值(count):大于1的整数,最大允许的QPS。
统计窗口时长(durationInSec):统计窗口时间长度,单位为秒(since 1.6.0)。
参数例外项(paramFlowItemList):参数例外项,可以针对指定的参数值单独设置限流阈值。
参数类型:热点参数的Java类型,只支持基本类型和String)。
参数值:例外项的值,当参数为该值时,使用特定的限流阈值。
限流阈值:特定的限流阈值。
使用@SentinelResource注解定义testD资源如下:
71("/testD")2("testD")3public String testD((value = "username", required = false) String username) {4 System.out.println(username);5 return UUID.randomUUID().toString();6}7
然后配置其默认的限流阈值为1,当值为username参数为zhangsan时,阈值为5,为lisi时,阈值为10:

注意:
热点参数规则配置时的资源名必须是@SentinelResource注解注册的资源名,而不是自动注册的URL资源。
热点参数流控仅在资源调用时包含了热点参数时才生效,否则不进行流控。
集群流控可以解决由于单机流量不均而造成总体限流效果不佳的问题。集群流控中有两种身份:
集群流控客户端(Token Client):用于向所属Token Server通信请求Token。集群限流服务端会返回给客户端结果,决定是否限流。
集群流控服务端(Token Server):用于处理来自Token Client的请求,根据配置的集群规则判断是否应该发放Token(是否允许通过)。
Sentinel集群限流服务端有两种启动方式:
独立模式(Alone):即作为独立的Token server进程启动,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为Global Rate Limiter给集群提供流控服务。
嵌入模式(Embedded):即作为内置的Token server与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,Token server和client可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制Token server的总QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。
下面我们采用嵌入模式来演示,首先在服务集群引入Token server和Token client的相关依赖:
131<!--SpringCloud-nacos-provider/pom.xml-->2
3<!--SpringCloud ailibaba sentinel cluster server-->4<dependency>5 <groupId>com.alibaba.csp</groupId>6 <artifactId>sentinel-cluster-server-default</artifactId>7</dependency>8<!--SpringCloud ailibaba sentinel cluster client -->9<dependency>10 <groupId>com.alibaba.csp</groupId>11 <artifactId>sentinel-cluster-client-default</artifactId>12</dependency>13
然后重启集群,并调用集群中任意接口初始化Sentinel。再打开Sentinel控制台的集群流控菜单,点击新增Token server。选择一个应用内的机器作为Server,其它都作为Client。
新增一条流控规则,勾选"是否集群",选择集群的阈值模式为单机均摊(根据均摊阈值*机器数量动态计算集群阈值)或总体阈值(固定的集群阈值)。

使用Postman压测集群中的一个服务节点,达到集群阈值后,发现其它服务节点也进入了限流。

提示:
一般勾选"失败退化"选项,在Token Server不可用时,退化到单机限流。
热点参数流控也支持集群模式,与普通流控类似,不再赘述。
从1.6.0版本开始,Sentinel提供了Spring Cloud Gateway的适配模块,可以提供两种资源维度的限流:
route:网关配置文件中的routes条目,资源名为对应的routeId。
API组:Sentinel中自定义的API分组,包括一组URL集合。
在配置网关限流规则时,一些可用的属性配置如下:
API类型(resourceMode):可选route维度限流(默认)或API维度限流。
API名称(resource):资源名称,可以是网关中的route名称或者用户自定义的API分组名称。
阈值类型(grade):可选QPS类型或线程数类型。
QPS阈值/线程数(count):限流阈值。
间隔(intervalSec):统计时间窗口,单位是秒,默认是1秒。
流控方式(controlBehavior):流量整形的控制效果,支持快速失败和匀速排队两种模式,默认是快速失败。
Burst size(burst):应对突发请求时额外允许的请求数目,仅在快速失败模式下生效。
超时时间(maxQueueingTimeoutMs):匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
针对请求属性(paramItem):参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。
参数属性(parseStrategy):从请求中提取参数的策略,目前支持提取来源IP、Host、Cookie、Header和URL参数五种模式。
Header名称/URL参数名称/Cookie名称(fieldName):若提取策略选择后三种,则需要指定对应的Cookie/Header/URL参数名称。
匹配模式(matchStrategy):参数值的匹配策略,目前支持精确匹配、子串匹配和正则匹配。
匹配串(pattern):参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。
注意:
Sentinel网关流控默认的粒度是route维度以及自定义API分组维度,默认不支持 URL 粒度。
网关模块在启动时添加
-Dcsp.sentinel.app.type=1参数,Sentinel控制台才有API管理等菜单。默认的降级逻辑由DefaultBlockRequestHandler处理,可通过GatewayCallbackManager.setBlockHandler()进行覆盖。
Sentinel也支持Zuul1.x和Zuul2.x的流控控制,请参考官方文档!
131<!--SpringCloud-gateway-server/pom.xml-->2
3<!--SpringCloud ailibaba sentinel -->4<dependency>5 <groupId>com.alibaba.cloud</groupId>6 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>7</dependency>8<!--sentinel适配gateway-->9<dependency>10 <groupId>com.alibaba.csp</groupId>11 <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>12</dependency>13
221spring2 application3 namecloud-gateway-server4 cloud5 # 网关6 gateway7 discovery8 locator9 enabledtrue #开启从注册中心动态创建路由的功能,利用微服务名进行路由10 routes11idpayment_route01 #路由的ID,没有固定规则但要求唯一,建议配合服务名12 urilb//CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址13 # uri: http://127.0.0.1:8100 #匹配后提供服务的路由地址14 predicates15Path=/payment/** # 断言,路径相匹配的进行路由16 # Sentinel限流17 sentinel18 transport19 dashboardlocalhost8080 #配置Sentinel地址20 filter21 enabledfalse # Sentinel不支持URL粒度的网关限流,因此设置为false22
提示:
网关配置的Routes会自动被注册为Sentinel资源,资源ID为routeId。
但有的时候Spring Cloud Gateway会自己在route名称前面拼一个前缀,如ReactiveCompositeDiscoveryClient_xxx 这种,请观察簇点链路页面实际的资源名。
641package com.huangyuanxin.springcloud.gateway.config;2
3import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;4import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;5import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;6import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;7import org.springframework.beans.factory.ObjectProvider;8import org.springframework.cloud.gateway.filter.GlobalFilter;9import org.springframework.context.annotation.Bean;10import org.springframework.context.annotation.Configuration;11import org.springframework.core.Ordered;12import org.springframework.core.annotation.Order;13import org.springframework.http.codec.ServerCodecConfigurer;14import org.springframework.web.reactive.function.server.ServerResponse;15import org.springframework.web.reactive.result.view.ViewResolver;16import org.springframework.web.server.ServerWebExchange;17import reactor.core.publisher.Mono;18
19import javax.annotation.PostConstruct;20import java.util.Collections;21import java.util.List;22
2324public class GatewayConfiguration {25
26 private final List<ViewResolver> viewResolvers;27 private final ServerCodecConfigurer serverCodecConfigurer;28
29 public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,30 ServerCodecConfigurer serverCodecConfigurer) {31 this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);32 this.serverCodecConfigurer = serverCodecConfigurer;33 }34
35 // 自定义降级处理逻辑(可选)36 37 public void init() {38 GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {39 40 public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {41 throwable.printStackTrace();42 String result = "请求[" + serverWebExchange.getRequest().getURI().toString() + "]被Sentinel降级!";43 return ServerResponse.ok().body(Mono.just(result), String.class);44 }45 });46 }47
48 // SentinelGatewayBlockExceptionHandler49 50 (Ordered.HIGHEST_PRECEDENCE)51 public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {52 // Register the block exception handler for Spring Cloud Gateway.53 return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);54 }55
56 // SentinelGatewayFilter57 58 (-1)59 public GlobalFilter sentinelGatewayFilter() {60 return new SentinelGatewayFilter();61 }62
63}64
71// 支付服务提供测试接口,后续通过网关访问2("/payment/testGatewaySentinel")3public String testGatewaySentinel(("userName") String userName) {4 System.out.println(userName);5 return "I am " + userName + ".";6}7
依次启动Eureka注册中心、Config配置中心(非必须)、Gateway网关(带-Dcsp.sentinel.app.type=1启动参数)、支付服务8101/8102(注册到Eureka),先测试支付服务单独访问OK,通过网关访问OK。

打开Sentinel控制台,配置Route流控如下:

然后再通过网关连续多次调用支付服务,发现出现了限流,且降级逻辑为我们自定义的降级逻辑。

删除上述流控规则,重新添加Route流控规则如下,当URL属性userName的值为zhangsan时,限制QPS为2,其它情形不做限流:

删除上述流控规则,添加熔断规则如下,当1s的时间窗口内请求次数超过5次,并且慢调用的比例(响应时间大于1000ms的请求)达到了50%,则熔断1s。

异常比例策略和异常数策略和普通服务流控类似,不再赘述。
首先通过API管理菜单添加一个API分组,支持精确匹配、前缀匹配和正则匹配三种模式。

然后在流控规则菜单新增网关流控规则,选择API分组类型和API名称,其它配置和Route类型一致。

请参考下一章节!注意:若使用Spring Cloud Alibaba Sentinel数据源模块,需要注意网关流控规则数据源类型是gw-flow,若将网关流控规则数据源指定为flow则不生效。
Sentinel默认将规则保存在内存中,如果应用重启,则所有规则需要重新配置。如需通过外部数据源进行持久化,常见实现方式有两种:
拉模式(Pull-based):客户端主动向某个规则管理中心定期轮询拉取规则,这样做的方式是简单,缺点是无法及时获取变更。Sentinel提供的支持该模式的数据源扩展有动态文件、Consul、Eureka等;
推模式(Push-based):规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,这种方式有更好的实时性和一致性保证。Sentinel提供的支持该模式的数据源扩展有ZooKeeper、Redis、Nacos、Apollo、etcd等。
下面介绍如何使用Nacos配置中心进行规则持久化。
61<!--SpringCloud ailibaba sentinel-datasource-nacos -->2<dependency>3 <groupId>com.alibaba.csp</groupId>4 <artifactId>sentinel-datasource-nacos</artifactId>5</dependency>6
在application.yml中配置Nacos的地址和dataId相关信息:
211# application.yml2spring3 application4 namecloud-provider-payment5 cloud6 nacos7 discovery8 server-addrlocalhost8848 #配置Nacos地址9 sentinel10 transport11 dashboardlocalhost8080 #配置Sentinel地址12 datasource13 ds114 nacos15 server-addrlocalhost884816 namespacee786f42a-bf7c-4bf2-9917-5023f80588b817 groupIdDEFAULT_GROUP18 dataId$spring.application.name19 data-typejson20 rule-typeflow21 在Nacos配置中心对应的名称空间和组下添加对应的dataId,并选择json格式,添加一条规则。

111[2 {3 "resource": "/sentinel/testA",4 "limitApp": "default",5 "grade": 1,6 "count": 1,7 "strategy": 0,8 "controlBehavior": 0,9 "clusterMode": false10 }11]
刷新Sentinel就可以看到添加的规则了,并且重启后也存在。

准备支付服务集群,注册到Nacos,提供http://localhost:8131/payment/nacos和http://localhost:8132/payment/nacos两个服务接口,测试正常访问OK,且服务端未做流控。
541 2<project xmlns="http://maven.apache.org/POM/4.0.0"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">5 <parent>6 <artifactId>SpringCloud-demo</artifactId>7 <groupId>com.huangyuanxin.SpringCloud</groupId>8 <version>1.0-SNAPSHOT</version>9 </parent>10 <modelVersion>4.0.0</modelVersion>11
12 <artifactId>SpringCloud-nacos-consumer</artifactId>13
14 <dependencies>15 <!--SpringCloud ailibaba nacos-discovery -->16 <dependency>17 <groupId>com.alibaba.cloud</groupId>18 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>19 </dependency>20 <!--SpringCloud ailibaba sentinel -->21 <dependency>22 <groupId>com.alibaba.cloud</groupId>23 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>24 </dependency>25
26 <!-- SpringBoot整合Web组件 -->27 <dependency>28 <groupId>org.springframework.boot</groupId>29 <artifactId>spring-boot-starter-web</artifactId>30 </dependency>31 <dependency>32 <groupId>org.springframework.boot</groupId>33 <artifactId>spring-boot-starter-actuator</artifactId>34 </dependency>35 <!--日常通用jar包配置-->36 <dependency>37 <groupId>org.springframework.boot</groupId>38 <artifactId>spring-boot-devtools</artifactId>39 <scope>runtime</scope>40 <optional>true</optional>41 </dependency>42 <dependency>43 <groupId>org.projectlombok</groupId>44 <artifactId>lombok</artifactId>45 <optional>true</optional>46 </dependency>47 <dependency>48 <groupId>org.springframework.boot</groupId>49 <artifactId>spring-boot-starter-test</artifactId>50 <scope>test</scope>51 </dependency>52 </dependencies>53
54</project>
231server2 port82303
4spring5 application6 namecloud-consumer-order7 cloud8 nacos9 discovery10 server-addrlocalhost884811 sentinel12 transport13 dashboardlocalhost8080 #配置Sentinel地址14
15#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)16service-url17 payment-servicehttp//cloud-provider-payment18
19#是否开启sentinel对resttemplate的支持,false则关闭 默认true20#resttemplate:21# sentinel:22# enabled: true23
812 // 注册到Nacos3public class NacosConsumerApplication {4 public static void main(String[] args) {5 SpringApplication.run(NacosConsumerApplication.class, args);6 }7}8
201package com.huangyuanxin.springcloud.nacos.consumer.handler;2
3import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;4import com.alibaba.csp.sentinel.slots.block.BlockException;5import org.springframework.http.HttpRequest;6import org.springframework.http.client.ClientHttpRequestExecution;7
8public class GlobalExceptionHandler {9 // 处理限流10 public static SentinelClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {11 return new SentinelClientHttpResponse("Global Block:" + request.getURI());12 }13
14 // 处理降级15 public static SentinelClientHttpResponse fallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {16 return new SentinelClientHttpResponse("Global Fallback:" + request.getURI());17 }18}19 20 注意:该方法的参数跟返回值跟org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。
1312public class ApplicationContextBean {3 4 5 (6 blockHandler = "handleException", blockHandlerClass = GlobalExceptionHandler.class,7 fallback = "fallback", fallbackClass = GlobalExceptionHandler.class8 )9 public RestTemplate getRestTemplate() {10 return new RestTemplate();11 }12}13
1512public class OrderController {3 4 private RestTemplate restTemplate;5
6 ("${service-url.payment-service}")7 private String serverURL;8
9 (value = "/consumer/payment/nacos")10 public String paymentInfo() {11 String result = restTemplate.getForObject(serverURL + "/payment/nacos", String.class);12 return "消费者调用支付服务(nacos)--->result:" + result;13 }14}15
对RestTemplate调用进行限流时,支持的资源格式为:方法类型:协议://主机:端口/路径。其中主机和端口可用服务名替代,路径可省略表示对整个服务限流。

访问http://localhost:8230/consumer/payment/nacos,多次点击后出现限流。

准备支付服务集群,注册到Nacos,提供http://localhost:8131/payment/nacos和http://localhost:8132/payment/nacos两个服务接口,测试正常访问OK,且服务端未做流控。
601 2<project xmlns="http://maven.apache.org/POM/4.0.0"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">5 <parent>6 <artifactId>SpringCloud-demo</artifactId>7 <groupId>com.huangyuanxin.SpringCloud</groupId>8 <version>1.0-SNAPSHOT</version>9 </parent>10 <modelVersion>4.0.0</modelVersion>11
12 <artifactId>SpringCloud-nacos-consumer</artifactId>13
14 <dependencies>15 <!--SpringCloud ailibaba nacos-discovery -->16 <dependency>17 <groupId>com.alibaba.cloud</groupId>18 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>19 </dependency>20 <!--SpringCloud ailibaba sentinel -->21 <dependency>22 <groupId>com.alibaba.cloud</groupId>23 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>24 </dependency>25 <!--SpringCloud ailibaba sentinel 支持客户端Feign调用限流-->26 <dependency>27 <groupId>org.springframework.cloud</groupId>28 <artifactId>spring-cloud-starter-openfeign</artifactId>29 </dependency>30
31 <!-- SpringBoot整合Web组件 -->32 <dependency>33 <groupId>org.springframework.boot</groupId>34 <artifactId>spring-boot-starter-web</artifactId>35 </dependency>36 <dependency>37 <groupId>org.springframework.boot</groupId>38 <artifactId>spring-boot-starter-actuator</artifactId>39 </dependency>40 <!--日常通用jar包配置-->41 <dependency>42 <groupId>org.springframework.boot</groupId>43 <artifactId>spring-boot-devtools</artifactId>44 <scope>runtime</scope>45 <optional>true</optional>46 </dependency>47 <dependency>48 <groupId>org.projectlombok</groupId>49 <artifactId>lombok</artifactId>50 <optional>true</optional>51 </dependency>52 <dependency>53 <groupId>org.springframework.boot</groupId>54 <artifactId>spring-boot-starter-test</artifactId>55 <scope>test</scope>56 </dependency>57 </dependencies>58
59</project>60
221server2 port82303
4spring5 application6 namecloud-consumer-order7 cloud8 nacos9 discovery10 server-addrlocalhost884811 sentinel12 transport13 dashboardlocalhost8080 #配置Sentinel地址14
15#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)16service-url17 payment-servicehttp//cloud-provider-payment18
19# 激活Sentinel对Feign的支持20feign21 sentinel22 enabledtrue
912 // 注册到Nacos3 // 开启Feign支持4public class NacosConsumerApplication {5 public static void main(String[] args) {6 SpringApplication.run(NacosConsumerApplication.class, args);7 }8}9
121package com.huangyuanxin.springcloud.nacos.consumer.feign;2
3import com.huangyuanxin.springcloud.nacos.consumer.feign.fallback.PaymentFeignClientFallback;4import org.springframework.cloud.openfeign.FeignClient;5import org.springframework.web.bind.annotation.RequestMapping;6 7(value = "cloud-provider-payment", fallback = PaymentFeignClientFallback.class)8public interface PaymentFeignClient {9 (value = "/payment/nacos")10 String paymentnacos();11}12
221package com.huangyuanxin.springcloud.nacos.consumer.feign.fallback;2
3import com.huangyuanxin.springcloud.nacos.consumer.feign.PaymentFeignClient;4import feign.hystrix.FallbackFactory;5import org.springframework.stereotype.Component;6
78public class PaymentFeignClientFallbackFactory implements FallbackFactory<PaymentFeignClient> {9 10 public PaymentFeignClient create(Throwable throwable) {11 // 使用FallbackFactory的优势是可以获取到异常信息12 throwable.printStackTrace();13
14 return new PaymentFeignClient() {15 16 public String paymentnacos() {17 return "PaymentFeignClientFallbackFactory.paymentnacos";18 }19 };20 }21}22
1212public class OrderController {3 4 private PaymentFeignClient paymentFeignClient;5
6 (value = "/consumer/feign/payment/nacos")7 public String paymentInfo2() {8 String result = paymentFeignClient.paymentnacos();9 return "消费者调用支付服务(nacos)--->result:" + result;10 }11}12
对RestTemplate调用进行限流时,支持的资源格式为:方法类型:协议://主机:端口/路径。其中主机和端口可用服务名替代,路径可省略表示对整个服务限流。

访问http://localhost:8230/consumer/feign/payment/nacos,多次点击后出现限流。

由于版本差异,Feign的parseAndValidatateMetadata方法可能不兼容,在工程下创建com.alibaba.cloud.sentinel.feign包,粘贴如下代码:
321package com.alibaba.cloud.sentinel.feign;2
3import feign.Contract;4import feign.MethodMetadata;5
6import java.util.HashMap;7import java.util.List;8import java.util.Map;9
10/**11 * 解决如下错误:12 * Caused by: java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidatateMetadata(Ljava/lang/Class;)Ljava/util/List;13 */14public class SentinelContractHolder implements Contract {15
16 private final Contract delegate;17
18 public final static Map<String, MethodMetadata> METADATA_MAP = new HashMap<>();19
20 public SentinelContractHolder(Contract delegate) {21 this.delegate = delegate;22 }23
24 25 public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {26 List<MethodMetadata> metadatas = delegate.parseAndValidatateMetadata(targetType);27 metadatas.forEach(metadata -> METADATA_MAP28 .put(targetType.getName() + metadata.configKey(), metadata));29 return metadatas;30 }31}32
Sentinel为应用程序提供了一个端点sentinel,可通过http://localhost:8131/actuator/sentinel进行访问,包含如下一些属性:
761{2 "blockPage": null,3 "appName": "sentinel-example",4 "consoleServer": "localhost:8080",5 "coldFactor": "3",6 "rules": {7 "flowRules": [{8 "resource": "GET:http://www.taobao.com",9 "limitApp": "default",10 "grade": 1,11 "count": 0.0,12 "strategy": 0,13 "refResource": null,14 "controlBehavior": 0,15 "warmUpPeriodSec": 10,16 "maxQueueingTimeMs": 500,17 "clusterMode": false,18 "clusterConfig": null19 }, {20 "resource": "/test",21 "limitApp": "default",22 "grade": 1,23 "count": 0.0,24 "strategy": 0,25 "refResource": null,26 "controlBehavior": 0,27 "warmUpPeriodSec": 10,28 "maxQueueingTimeMs": 500,29 "clusterMode": false,30 "clusterConfig": null31 }, {32 "resource": "/hello",33 "limitApp": "default",34 "grade": 1,35 "count": 1.0,36 "strategy": 0,37 "refResource": null,38 "controlBehavior": 0,39 "warmUpPeriodSec": 10,40 "maxQueueingTimeMs": 500,41 "clusterMode": false,42 "clusterConfig": null43 }]44 },45 "metricsFileCharset": "UTF-8",46 "filter": {47 "order": -2147483648,48 "urlPatterns": ["/*"],49 "enabled": true50 },51 "totalMetricsFileCount": 6,52 "datasource": {53 "ds1": {54 "file": {55 "dataType": "json",56 "ruleType": "FLOW",57 "converterClass": null,58 "file": "...",59 "charset": "utf-8",60 "recommendRefreshMs": 3000,61 "bufSize": 104857662 },63 "nacos": null,64 "zk": null,65 "apollo": null,66 "redis": null67 }68 },69 "clientIp": "30.5.121.91",70 "clientPort": "8719",71 "logUsePid": false,72 "metricsFileSize": 52428800,73 "logDir": "...",74 "heartbeatIntervalMs": 1000075}76
拦截日志记录了Sentinel在进行资源拦截时的一些日志信息,包括拦截详情日志、秒级监控日志、业务日志和集群限流日志等。日志目录可通过csp.sentinel.log.dir启动参数进行配置,详情请参考通用配置项文档。
拦截详情日志
无论触发了限流、熔断降级还是系统保护,它们的秒级拦截详情日志都在${user_home}/logs/csp/sentinel-block.log里。如果没有发生拦截,则该日志不会出现。日志格式如下:
212014-06-20 16:35:10|1|sayHello(java.lang.String,long),FlowException,default,origin|61,022014-06-20 16:35:11|1|sayHello(java.lang.String,long),FlowException,default,origin|1,0
秒级监控日志
所有的资源访问都会产生秒级监控日志,日志文件默认为${user_home}/logs/csp/${app_name}-${pid}-metrics.log。格式:
111532415661000|2018-07-24 15:01:01|sayHello(java.lang.String)|12|3|4|2|295|0|0|1
业务日志
其它的日志在${user_home}/logs/csp/sentinel-record.log.xxx里。该日志包含规则的推送、接收、处理等记录,排查问题的时候会非常有帮助。
集群限流日志
Token Client日志记录在${log_dir}/sentinel-cluster-client.log,包括请求失败的信息。
SpringCloud Alibaba Sentinel还支持如下一些配置选项:
| 配置 | 描述 | 默认值 |
|---|---|---|
| spring.application.name(或project.name) | Sentinel项目名称 | |
| spring.cloud.sentinel.enabled | Sentinel自动配置是否生效 | true |
| spring.cloud.sentinel.eager | 是否提前触发Sentinel初始化 | false |
| spring.cloud.sentinel.transport.port | 应用程序与Sentinel控制台交互的端口 | 8719(向下探测) |
| spring.cloud.sentinel.transport.dashboard | Sentinel控制台地址 | |
| spring.cloud.sentinel.transport.heartbeatIntervalMs | 应用程序和Sentinel控制台之间的心跳间隔 | |
| spring.cloud.sentinel.transport.client-ip | 此配置的客户端IP将注册到Sentinel服务器端 | |
| spring.cloud.sentinel.filter.order | Servlet Filter的加载顺序 | Integer.MIN_VALUE |
| spring.cloud.sentinel.filter.url-patterns | Data type is array. Refers to the collection of Servlet Filter ULR patterns | /* |
| spring.cloud.sentinel.filter.enabled | Enable to instance CommonFilter | true |
| spring.cloud.sentinel.metric.charset | metric文件字符集 | UTF-8 |
| spring.cloud.sentinel.metric.fileSingleSize | metric单个文件大小 | |
| spring.cloud.sentinel.metric.fileTotalCount | metric总文件数 | |
| spring.cloud.sentinel.log.dir | Sentinel日志文件目录 | |
| spring.cloud.sentinel.log.switch-pid | If PID is required for Sentinel log file names | false |
| spring.cloud.sentinel.servlet.blockPage | Customized redirection URL. When rate limited, the request will be redirected to the pre-defined URL | |
| spring.cloud.sentinel.flow.coldFactor | 冷因子 | 3 |
| spring.cloud.sentinel.zuul.order.pre | SentinelZuulPreFilter的Order值 | 10000 |
| spring.cloud.sentinel.zuul.order.post | SentinelZuulPostFilter的Order值 | 1000 |
| spring.cloud.sentinel.zuul.order.error | SentinelZuulErrorFilter的Order值 | -1 |
| spring.cloud.sentinel.scg.fallback.mode | Response mode after Spring Cloud Gateway circuit break (select or redirect response) | |
| spring.cloud.sentinel.scg.fallback.redirect | Spring Cloud Gateway response mode is the redirect URL corresponding to 'redirect' mode | |
| spring.cloud.sentinel.scg.fallback.response-body | Spring Cloud Gateway response mode is response content corresponding to 'response' mode | |
| spring.cloud.sentinel.scg.fallback.response-status | Spring Cloud Gateway response mode is the response code corresponding to 'response' mode | 429 |
| spring.cloud.sentinel.scg.fallback.content-type | The Spring Cloud Gateway response mode is the content-type corresponding to the 'response' mode. | application/json |
除此之外,也可以通过向Sentinel注册一些Bean来控制Sentinel的行为:
| Bean类型 | 注册语句 | 效果 |
|---|---|---|
| UrlCleaner | WebCallbackManager.setUrlCleaner(urlCleaner) | URL修改。例如将/foo/1修改为/foo/* |
| UrlBlockHandler | WebCallbackManager.setUrlBlockHandler(urlBlockHandler) | 自定义限流逻辑 |
| RequestOriginParser | WebCallbackManager.setRequestOriginParser(requestOriginParser) | 设置origin |