目錄
1. SpringCloudAlibaba Nacos(服務的注冊與發(fā)現(xiàn)少漆、配置的動態(tài)刷新)
2. SpringCloudAlibaba Sentinel(流量控制)
1. SpringCloudAlibaba Nacos
Nacos(Dynamic Naming and Configuration Service)由Alibaba開發(fā)的Java開源項目:服務注冊中心(實現(xiàn)服務的注冊與發(fā)現(xiàn)战坤, 類似SpringCloudEureka功能)和配置中心(實現(xiàn)配置的動態(tài)刷新弹砚,類似SpringCloudConfig+SpringCloudBus功能)的組合體(以服務為核心)迟蜜。
Nacos作為服務注冊中心經(jīng)歷了十年“雙十一”的洪峰考驗,具有簡單易用荡短、穩(wěn)定可靠丐枉、性能卓越等優(yōu)點,可以幫助用戶更敏捷掘托、容易地構建和管理微服務應用瘦锹。Nacos支持幾乎所有主流類型“服務”的發(fā)現(xiàn)、配置和管理:
1. Kubernetes Service
2. gRPC&Dubbo RPC Service
3. Spring Cloud RESTful Service
Nacos的特性
1. 服務發(fā)現(xiàn)
Nacos 支持基于 DNS 和 RPC 的服務發(fā)現(xiàn)。當服務提供者使用原生 SDK沼本、OpenAPI 或一個獨立的 Agent TODO 向 Nacos 注冊服務后噩峦,服務消費者可以在 Nacos 上通過 DNS TODO 或 HTTP&API 查找、發(fā)現(xiàn)服務抽兆。
2. 服務健康監(jiān)測
對服務實時健康檢查识补,阻止請求發(fā)送到不健康主機或服務實例上。提供了一個健康檢查儀表盤辫红,能夠幫助我們根據(jù)健康狀態(tài)管理服務的可用性及流量凭涂。
3. 動態(tài)配置服務
動態(tài)配置服務可以讓我們以中心化、外部化和動態(tài)化的方式贴妻,管理所有環(huán)境的應用配置和服務配置切油。
動態(tài)配置消除了配置變更時重新部署應用和服務的需要,讓配置管理變得更加高效名惩、敏捷澎胡。
配置中心化管理讓實現(xiàn)無狀態(tài)服務變得更簡單,讓服務按需彈性擴展變得更容易娩鹉。
Nacos 提供了一個簡潔易用的 UI 幫助我們管理所有服務和應用的配置攻谁。Nacos 還提供包括配置版本跟蹤、金絲雀發(fā)布弯予、一鍵回滾配置以及客戶端配置更新狀態(tài)跟蹤在內(nèi)的一系列開箱即用的配置管理特性戚宦,幫助我們更安全地在生產(chǎn)環(huán)境中管理配置變更和降低配置變更帶來的風險。
4. 動態(tài) DNS 服務
Nacos 提供了動態(tài) DNS 服務锈嫩,能夠讓我們更容易地實現(xiàn)負載均衡受楼、流量控制以及數(shù)據(jù)中心內(nèi)網(wǎng)的簡單 DNS 解析服務。
Nacos 提供了一些簡單的 DNS APIs TODO呼寸,可以幫助我們管理服務的關聯(lián)域名和可用的 IP:PORT 列表艳汽。
5. 服務及其元數(shù)據(jù)管理
Nacos 能讓我們從微服務平臺建設的視角管理數(shù)據(jù)中心的所有服務及元數(shù)據(jù),包括管理服務的描述对雪、生命周期河狐、服務的靜態(tài)依賴分析、服務的健康狀態(tài)慌植、服務的流量管理甚牲、路由及安全策略义郑、服務的 SLA 以及 metrics 統(tǒng)計數(shù)據(jù)蝶柿。
Nacos的兩大組件
與Eureka類似,Nacos也采用CS(Client/Server非驮,客戶端/服務器)架構交汤。
1. NacosServer(Nacos服務端)
與EurekaServer不同,NacosServer由阿里巴巴團隊使用Java語言開發(fā),只需下載并運行芙扎。
NacosServer可以作為服務注冊中心星岗,幫助NacosClient實現(xiàn)服務的注冊與發(fā)現(xiàn)。
NacosServer可以作為配置中心戒洼,幫助NacosClient在不重啟的情況下俏橘,實現(xiàn)配置的動態(tài)刷新。
2. NacosClient(Nacos 客戶端)
通常指的是微服務架構中的各個服務圈浇,由開發(fā)者自己搭建寥掐,可以使用多種語言編寫。
NacosClient通過添加依賴spring-cloud-starter-alibaba-nacos-discovery磷蜀,在服務注冊中心(Nacos Server)中實現(xiàn)服務的注冊與發(fā)現(xiàn)召耘。
NacosClient通過添加依賴spring-cloud-starter-alibaba-nacos-config,在配置中心(Nacos Server)中實現(xiàn)配置的動態(tài)刷新褐隆。
NacosServer目錄說明:
1. bin目錄
用于存放Nacos的可執(zhí)行命令污它。
2. conf目錄
用于存放Nacos配置文件。
3. target目錄
用于存放Nacos應用的jar包庶弃。
運行NacosServer
1. 終端執(zhí)行
cd NacosServer的bin目錄
Windows:startup.cmd -m standalone 以單機模式啟動NacosServer
Linux:sh startup.sh -m standalone
2. 在瀏覽器中訪問http://localhost:8848/nacos登陸頁面衫贬,輸入登錄名和密碼(默認都是nacos)跳轉(zhuǎn)到NacosServer控制臺主頁。
- Nacos服務注冊中心
共涉及3個角色:
1. 服務注冊中心(Register Service)NacosServer
為服務提供者和服務消費者提供服務注冊和發(fā)現(xiàn)功能虫埂。
2. 服務提供者(Provider Service)NacosClient
對外提供服務(將自己提供的服務注冊到服務注冊中心祥山,以供服務消費者發(fā)現(xiàn)和調(diào)用)。
3. 服務消費者(Consumer Service)NacosClient
用于消費服務(從服務注冊中心獲取服務列表掉伏,調(diào)用所需的服務)缝呕。
Nacos實現(xiàn)服務注冊與發(fā)現(xiàn)的流程如下:
1. 下載NacosServer并運行。
2. 服務提供者NacosClient啟動時斧散,會把服務以服務名(spring.application.name)的方式注冊到服務注冊中心(NacosServer)供常。
3. 服務消費者NacosClient啟動時,也會將自己的服務注冊到服務注冊中心鸡捐;并從服務注冊中心獲取一份服務注冊列表信息栈暇,該列表中包含了所有注冊到服務注冊中心上的服務的信息(包括服務提供者和自身的信息);通過HTTP或消息中間件遠程調(diào)用服務提供者提供的服務箍镜。
示例
===》1. 創(chuàng)建spring-cloud-alibaba-demo主項目
1. 修改pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sst.cx</groupId>
<artifactId>spring-cloud-alibaba-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath />
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!--Spring Cloud Alibaba 的版本信息-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.1</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>
</dependencies>
</dependencyManagement>
</project>
===》2. 創(chuàng)建spring-cloud-alibaba-provider-8001 子項目(搭建服務提供者)
1. 修改pom.xml文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring Cloud Alibaba Nacos discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建application.properties配置文件(類路徑resources目錄下)
#端口號
server.port=8001
#服務名
spring.application.name=spring-cloud-alibaba-provider
#Nacos Server 的地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*
3. 創(chuàng)建UserController.java
package com.sst.cx.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class UserController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/user/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id) {
return "<h2>服務訪問成功源祈!</h2>服務名:spring-cloud-alibaba-provider<br /> 端口號: " + serverPort + "<br /> 傳入的參數(shù):" + id;
}
}
4. 在主啟動類上,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能色迂。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 開啟服務發(fā)現(xiàn)功能
public class SpringCloudAlibabaProvider8001Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaProvider8001Application.class, args);
}
}
5. 啟動spring-cloud-alibaba-provider-8001,在瀏覽器中訪問http://localhost:8001/user/nacos/1歇僧、訪問http://localhost:8848/nacos查看“服務管理”下的“服務列表”
===》3. 創(chuàng)建spring-cloud-alibaba-consumer-nacos-8801子項目(搭建服務消費者)
1. 修改pom.xml文件
<dependencies>
<!--SpringCloud ailibaba nacos discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--由于 Netflix Ribbon 進入停更維護階段图张,因此新版本的 Nacos discovery 都已經(jīng)移除了 Ribbon ,此時我們需要引入 loadbalancer 代替 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建application.yml配置文件(類路徑resources目錄下)
server:
port: 8801 #端口號
spring:
application:
name: spring-cloud-alibaba-consumer #服務名
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos server 的地址
#以下配置信息并不是默認配置,而是我們自定義的配置祸轮,目的是不在 Controller 內(nèi)硬編碼服務提供者的服務名
service-url:
nacos-user-service: http://spring-cloud-alibaba-provider #服務提供者的服務名
3. 創(chuàng)建ApplicationContextBean.java配置類兽埃,添加@LoadBalanced注解與Ribbon進行集成開啟負載均衡功能。
package com.sst.cx.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextBean {
@Bean
@LoadBalanced // 與Ribbon集成适袜,并開啟負載均衡功能
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
4. 創(chuàng)建UserController_Consumer.java
package com.sst.cx.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class UserController_Consumer {
@Resource
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")
private String serverURL; //服務提供者的服務名
@GetMapping("/consumer/user/nacos/{id}")
public String paymentInfo(@PathVariable("id") Long id) {
return restTemplate.getForObject(serverURL + "/user/nacos/" + id, String.class);
}
}
5. 在主啟動類上柄错,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 開啟服務注冊與發(fā)現(xiàn)功能
public class SpringCloudAlibabaConsumerNacos8801Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaConsumerNacos8801Application.class, args);
}
}
6. 啟動spring-cloud-alibaba-consumer-nacos-8801苦酱,
在瀏覽器中訪問http://localhost:8001/consumer/user/nacos/1鄙陡、訪問http://localhost:8848/nacos查看“服務管理”下的“服務列表。
- Nacos配置中心
NacosServer還可以作為配置中心躏啰,對SpringCloud應用的外部配置進行統(tǒng)一地集中化管理趁矾。只需要在應用的pom.xml文件中引入spring-cloud-starter-alibaba-nacos-config即可實現(xiàn)配置的獲取與動態(tài)刷新。
示例
創(chuàng)建spring-cloud-alibaba-config-client-3377子項目
1. 修改pom.xml文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringCloud2020及以后的版本默認不啟用 bootstrap 配置给僵,我們需要在pom里面顯式地引入:-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring Cloud Alibaba Config 依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--SpringCloud ailibaba nacos 服務注冊與發(fā)現(xiàn)模塊 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--Spring Boot 監(jiān)控模塊-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建bootstrap.yml配置文件(類路徑resources目錄下)
server:
port: 3377 #端口號
spring:
application:
name: config-client #服務名
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #Nacos服務注冊中心地址
config:
server-addr: 127.0.0.1:8848 #Nacos作為配置中心地址
file-extension: yaml #指定yaml格式的配置
3. 創(chuàng)建application.yml配置文件(類路徑resources目錄下)
spring:
profiles:
active: dev #激活 dev 的配置
4. 創(chuàng)建ConfigClientController.java
package com.sst.cx.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String ConfigInfo;
@GetMapping("/config/info")
public String getConfigInfo(){
return ConfigInfo;
}
}
5. 在主啟動類上毫捣,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaNacosConfigClient3377Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaNacosConfigClient3377Application.class, args);
}
}
6. 啟動NacosServer,并在NacosServer控制臺的“配置管理”下的“配置列表”中,點擊“+”按鈕翩肌,新建如下配置
Data ID:config-client-dev.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置內(nèi)容:config:
info: com.sst.cx
/*
Data ID的完整格式:${prefix}-${spring.profiles.active}.${file-extension}
說明:
1. ${prefix}:默認取值為微服務的服務名,即配置文件中 spring.application.name 的值斑粱,可以在配置文件中通過配置 spring.cloud.nacos.config.prefix 來指定。
2. ${spring.profiles.active}:表示當前環(huán)境對應的 Profile脯爪,例如 dev则北、test、prod 等痕慢。當沒有指定環(huán)境的 Profile 時尚揣,其對應的連接符也將不存在, dataId 的格式變成 ${prefix}.${file-extension}掖举。
3. ${file-extension}:表示配置內(nèi)容的數(shù)據(jù)格式快骗,可以在配置文件中通過配置項 spring.cloud.nacos.config.file-extension 來配置,例如 properties 和 yaml塔次。
*/
7. 啟動spring-cloud-alibaba-config-client-3377方篮,并使用瀏覽器訪問http://localhost:3377/config/info。
在NacosServer中励负,將config-client-dev.yaml 中的配置修改info: hello com.sst.cx藕溅,使用瀏覽器再次訪問http://localhost:3377/config/info,可以看到發(fā)生改變熄守。
- NacosServer集群化部署
實際的項目開發(fā)中蜈垮,一個微服務系統(tǒng)往往由十幾,幾十個甚至幾百個微服務組成裕照。 這些服務若全部注冊到同一臺NacosServer攒发,就極有可能導致NacosServer因為不堪重負而崩潰,最終導致整個微服務系統(tǒng)癱瘓晋南。解決這個問題最直接的辦法就是使用NacosServer集群惠猿。
NacosServer的集群化部署有一個十分明顯的優(yōu)點,那就是可以保障系統(tǒng)的高可用性负间。在集群化部署中偶妖,只要不是所有的NacosServer都停止工作,NacosClient就還可以從集群中正常的NacosServer上獲取服務信息及配置政溃,而不會導致系統(tǒng)的整體癱瘓趾访,這就是NacosServer集群化部署的高可用性。
示例
1. 將NacosServer的conf目錄下的cluster.conf.example文件重命名為cluster.conf董虱,添加
192.168.0.101:3333
192.168.0.101:4444
192.168.0.101:5555
2. 在config目錄下的application.properties中扼鞋,將server.port(端口號)修改為 3333,添加MySQL數(shù)據(jù)庫配置
server.port=3333
###MySQL數(shù)據(jù)庫配置####
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
db.user=root
db.password=12345678
3. 將該NacosServer目錄復制到另外兩臺機器上愤诱,并將它們的端口號分別修改為: 4444 和 5555云头。
4. 下載Nginx,并修改Nginx中conf目錄下的nginx.conf的配置
/*
下載Nginx穩(wěn)定版并解壓
cd跳轉(zhuǎn)到該目錄下,編譯安裝
./configure
make
sudo make install
啟動
cd /usr/local/nginx/sbin
sudo ./nginx
*/
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream cluster{
server 127.0.0.1:3333;
server 127.0.0.1:4444;
server 127.0.0.1:5555;
}
server {
listen 1111;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://cluster;
}
}
}
5. 啟動集群中所有的NacosServer淫半、Nginx溃槐,在瀏覽器中訪問http://localhost:1111/nacos/,若成功訪問 NacosServer的控制臺科吭,則說明 Nacos 集群部署成功昏滴。
6. 將主工程spring-cloud-alibaba-demo下所有子模塊配置文件中的 Nacos Server 地址統(tǒng)一修改為:localhost:1111
server-addr: localhost:1111 #集群版 Nacos Server 的地址
7. 重啟spring-cloud-alibaba-consumer-nacos-8801,并使用瀏覽器訪問“http://localhost:1111/nacos”对人,查看“服務管理”下的“服務列表”影涉。
2. SpringCloudAlibaba Sentinel(高可用流量控制組件)
Sentinel由Alibaba開發(fā)的開源項目:面向分布式微服務架構的輕量級高可用流量控制組件(以流量為切入點,從流量控制规伐、熔斷降級、系統(tǒng)負載保護等多個維度幫助用戶保護服務的穩(wěn)定性)吵护。
功能上類似SpringCloudNetfilxHystrix ,但比Hystrix更強大(如:提供了流量控制功能份招、更完善的實時監(jiān)控功能等)切揭。
優(yōu)勢:
1. 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的“雙十一”大促流量的核心場景,例如秒殺(將突發(fā)流量控制在系統(tǒng)可以承受的范圍)锁摔、消息削峰填谷廓旬、集群流量控制、實時熔斷下游不可用服務等谐腰。
2. 完備的實時監(jiān)控:Sentinel 提供了實時監(jiān)控功能孕豹。用戶可以在控制臺中看到接入應用的單臺機器的秒級數(shù)據(jù),甚至是 500 臺以下規(guī)模集群的匯總運行情況十气。
3. 廣泛的開源生態(tài):Sentinel 提供了開箱即用的與其它開源框架或庫(例如 Spring Cloud励背、Apache Dubbo、gRPC砸西、Quarkus)的整合模塊叶眉。只需在項目中引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel。此外芹枷,Sentinel 還提供 Java衅疙、Go 以及 C++ 等多語言的原生實現(xiàn)。
4. 完善的 SPI 擴展機制:Sentinel 提供簡單易鸳慈、完善的 SPI 擴展接口饱溢,我們可以通過實現(xiàn)這些擴展接口快速地定制邏輯,例如定制規(guī)則管理走芋、適配動態(tài)數(shù)據(jù)源等绩郎。
SPI(全稱:Service Provider Interface)是一種服務發(fā)現(xiàn)機制潘鲫。它可以在 ClassPath 路徑下的 META-INF/services 文件夾查找文件,并自動加載文件中定義的類肋杖。
Sentinel由2部分組成:
1. Sentinel核心庫
不依賴任何框架或庫溉仑,能夠運行于 Java 8 及以上的版本的運行時環(huán)境中,同時對 Spring Cloud兽愤、Dubbo 等微服務框架提供了很好的支持。
Sentinel 核心庫不依賴 Sentinel Dashboard挪圾,但兩者結合使用可以有效的提高效率浅萧,讓 Sentinel 發(fā)揮它最大的作用。
2. Sentinel控制臺(Dashboard)
1. 機器自發(fā)現(xiàn)(查看機器列表以及健康情況)
收集Sentinel客戶端發(fā)送的心跳包哲思,判斷機器是否在線洼畅。
2. 監(jiān)控(單機和集群聚合)
通過Sentinel客戶端暴露的監(jiān)控API,可以實現(xiàn)秒級的實時監(jiān)控棚赔。
3. 對規(guī)則(如:流量控制帝簇、熔斷降級)進行配置和管理
針對資源定義和推送規(guī)則。
5. 簇點鏈路自發(fā)現(xiàn)
6. 鑒權
從Sentinel 1.6.0起靠益,Sentinel控制臺引入基本的登錄功能丧肴,默認用戶名和密碼都是sentinel。
的重要入口之一胧后。
Sentinel的基本概念
1. 資源
可以是Java應用中的任何內(nèi)容(如:由應用提供的服務芋浮、服務里的方法、一段代碼)壳快。
通過Sentinel提供的API來定義一個資源纸巷,使其能夠被Sentinel保護起來。通常情況下眶痰,我們可以使用方法名瘤旨、URL甚至是服務名來作為資源名來描述某個資源。
2. 規(guī)則
圍繞資源而設定的規(guī)則竖伯。Sentinel支持流量控制存哲、熔斷降級、系統(tǒng)保護七婴、來源訪問控制和熱點參數(shù)等多種規(guī)則宏胯,所有這些規(guī)則都可以動態(tài)實時調(diào)整。
Sentinel的使用步驟
1. 在項目中【引入Sentinel依賴】:spring-cloud-starter-alibaba-sentinel 本姥。
Sentinel對大部分的主流框架都進行了適配(如:Web Servlet肩袍、Dubbo、Spring Cloud婚惫、gRPC氛赐、Spring WebFlux魂爪、Reactor等)。
2. 【定義資源】:
在項目開發(fā)時艰管,只需要考慮這個服務滓侍、方法或代碼是否需要保護,如果需要保護牲芋,就可以將它定義為一個資源撩笆。
在Sentinel 控制臺的“簇點鏈路”中,可查看資源的實時統(tǒng)計缸浦。
4種方式:
1. 適配主流框架 自動定義資源
Sentinel 對大部分的主流框架都進行了適配夕冲,只要引入相關的適配模塊(例如 spring-cloud-starter-alibaba-sentinel),Snetinel 就會自動將項目中的服務(包括調(diào)用端和服務端)定義為資源裂逐,【資源名就是服務的請求路徑】歹鱼。只要再對資源定義一些規(guī)則,這些資源就可以享受到Sentinel的保護卜高。
2. 通過SphU類(try-catch風格)手動定義資源弥姻。
3. 通過SphO類(if-else風格)手動定義資源。
返回值為false(發(fā)生限流)時進行限流之后的邏輯處理掺涛。
4. 注解方式(@SentinelResource注解)手動定義資源庭敦。
3. 根據(jù)實時統(tǒng)計信息,【對資源定義規(guī)則】(如:流控規(guī)則薪缆、熔斷規(guī)則螺捐、熱點規(guī)則、系統(tǒng)規(guī)則矮燎、授權規(guī)則)定血。
4. 運行程序,【檢驗規(guī)則】是否生效诞外。
@SentinelResource注解的常用屬性 | 說明 | 必填與否 | 使用要求 |
---|---|---|---|
value | 用于指定資源的名稱 | 必填 | - |
entryType | entry 類型 | 可選項(默認為 EntryType.OUT) | - |
blockHandler | 服務限流后會拋出 BlockException 異常澜沟,而 blockHandler 則是用來指定一個函數(shù)來處理 BlockException 異常的。簡單點說峡谊,該屬性用于指定服務限流后的后續(xù)處理邏輯茫虽。 可選項 | 1. blockHandler 函數(shù)訪問范圍需要是 public;2. 返回類型需要與原方法相匹配既们;3. 參數(shù)類型需要和原方法相匹配并且最后加一個額外的參數(shù)濒析,類型為 BlockException;4. blockHandler 函數(shù)默認需要和原方法在同一個類中啥纸,若希望使用其他類的函數(shù)号杏,則可以指定 blockHandler 為對應的類的 Class 對象,注意對應的函數(shù)必需為 static 函數(shù)斯棒,否則無法解析盾致。 | |
blockHandlerClass | 若 blockHandler 函數(shù)與原方法不在同一個類中主经,則需要使用該屬性指定 blockHandler 函數(shù)所在的類。 可選項 | 1. 不能單獨使用庭惜,必須與 blockHandler 屬性配合使用罩驻;2. 該屬性指定的類中的 blockHandler 函數(shù)必須為 static 函數(shù),否則無法解析护赊。 | |
fallback | 用于在拋出異常(包括 BlockException)時惠遏,提供 fallback 處理邏輯。fallback 函數(shù)可以針對所有類型的異常(除了 exceptionsToIgnore 里面排除掉的異常類型)進行處理骏啰。 可選項 | 1. 返回值類型必須與原函數(shù)返回值類型一致节吮;2. 方法參數(shù)列表需要和原函數(shù)一致,或者可以額外多一個 Throwable 類型的參數(shù)用于接收對應的異常再榄;3. fallback 函數(shù)默認需要和原方法在同一個類中下翎,若希望使用其他類的函數(shù),則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數(shù)必需為 static 函數(shù)啄清,否則無法解析。 | |
fallbackClass | 若 fallback 函數(shù)與原方法不在同一個類中遗嗽,則需要使用該屬性指定 blockHandler 函數(shù)所在的類宪祥。 可選項 | 1. 不能單獨使用,必須與 fallback 或 defaultFallback 屬性配合使用瞭亮;2. 該屬性指定的類中的 fallback 函數(shù)必須為 static 函數(shù)方仿,否則無法解析。 | |
defaultFallback | 默認的 fallback 函數(shù)名稱统翩,通常用于通用的 fallback 邏輯(即可以用于很多服務或方法)仙蚜。默認 fallback 函數(shù)可以針對所以類型的異常(除了 exceptionsToIgnore 里面排除掉的異常類型)進行處理。 可選項 | 1. 返回值類型必須與原函數(shù)返回值類型一致厂汗;2. 方法參數(shù)列表需要為空委粉,或者可以額外多一個 Throwable 類型的參數(shù)用于接收對應的異常;3. defaultFallback 函數(shù)默認需要和原方法在同一個類中娶桦。若希望使用其他類的函數(shù)贾节,則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數(shù)必需為 static 函數(shù)衷畦,否則無法解析栗涂。 | |
exceptionsToIgnore | 用于指定哪些異常被排除掉,不會計入異常統(tǒng)計中祈争,也不會進入 fallback 邏輯中斤程,而是會原樣拋出。 可選項 | - |
注:在 Sentinel 1.6.0 之前菩混,fallback 函數(shù)只針對降級異常(DegradeException)進行處理暖释,不能處理業(yè)務異常袭厂。
流量控制規(guī)則
任何系統(tǒng)處理請求的能力都是有限的,但任意時間內(nèi)到達系統(tǒng)的請求量往往是隨機且不可控的球匕,如果在某一個瞬時時刻請求量急劇增纹磺,那么系統(tǒng)就很有可能被瞬時的流量高峰沖垮。為了避免此類情況發(fā)生亮曹,需要根據(jù)系統(tǒng)的處理能力對請求流量進行控制橄杨,即流量控制(簡稱:流控)。
流控規(guī)則
1. 資源名(流控規(guī)則的作用對象)照卦。
2. 閾值(流控閾值)式矫。
3. 閾值類型(流控閾值的類型)
QPS(默認值,表示并發(fā)請求數(shù)役耕,即每秒鐘最多通過的請求數(shù))采转、并發(fā)線程數(shù)。
4. 針對來源(流控針對的調(diào)用來源)
默認值:default(表示不區(qū)分調(diào)用來源)瞬痘。
5. 流控模式(調(diào)用關系限流策略)
直接(默認值)故慈、鏈路、關聯(lián)框全。
6. 流控效果
直接拒絕(默認值)察绷、Warm Up、勻速排隊津辩。不支持按調(diào)用關系限流拆撼。
對資源定義流控規(guī)則后:
Sentinel會根據(jù)這些規(guī)則對流量相關的各項指標進行監(jiān)控,當這些指標當達到或超過流控規(guī)則規(guī)定的閾值時喘沿,Sentinel會對請求的流量進行限制(即“限流”)闸度,以避免系統(tǒng)被瞬時的流量高峰沖垮,保障系統(tǒng)的高可用性蚜印。
觸發(fā)限流時莺禁,資源會拋出BlockException異常,可以捕捉該異常來自定義被限流后的處理邏輯晒哄。
·同一個資源可以創(chuàng)建多條流控規(guī)則睁宰,Sentinel會遍歷這些規(guī)則,直到有規(guī)則觸發(fā)限流或者所有規(guī)則遍歷完畢為止寝凌。
熔斷降級規(guī)則
除了流量控制以外柒傻,對調(diào)用鏈路中不穩(wěn)定資源的熔斷降級,也是保障服務高可用的重要措施之一较木。
在分布式微服務架構中红符,一個系統(tǒng)往往由多個服務組成,不同服務之間相互調(diào)用,組成復雜的調(diào)用鏈路预侯。如果鏈路上的某一個服務出現(xiàn)故障致开,那么故障就會沿著調(diào)用鏈路在系統(tǒng)中蔓延,最終導致整個系統(tǒng)癱瘓萎馅。Sentinel 提供了熔斷降級機制就可以解決這個問題双戳。Sentinel 的熔斷將機制會在調(diào)用鏈路中某個資源出現(xiàn)不穩(wěn)定狀態(tài)時(例如調(diào)用超時或異常比例升高),暫時切斷對這個資源的調(diào)用糜芳,以避免局部不穩(wěn)定因素導致整個系統(tǒng)的雪崩飒货。
熔斷降級作為服務保護自身的手段,通常在客戶端(調(diào)用端)進行配置峭竣,資源被熔斷降級最直接的表現(xiàn)就是拋出 DegradeException 異常塘辅。
熔斷規(guī)則
1. 資源名(熔斷規(guī)則的作用對象)
2. 熔斷策略(慢調(diào)用比例---默認、異常比例皆撩、異常數(shù)策略)
3. 最大RT(請求的最大相應時間扣墩,請求的響應時間大于該值則統(tǒng)計為慢調(diào)用)
僅限熔斷策略為慢調(diào)用比例。
4. 熔斷時長(熔斷開啟狀態(tài)持續(xù)的時間扛吞,超過該時間熔斷器會切換為探測恢復狀態(tài)HALF-OPEN呻惕,單位為s)
5. 最小請求數(shù)(熔斷觸發(fā)的最小請求數(shù),默認值:5喻粹,請求數(shù)小于該值時即使異常比率超出閾值也不會熔斷)1.7.0 引入蟆融。
6. 統(tǒng)計時長(熔斷觸發(fā)需要統(tǒng)計的時長草巡,默認值:1000ms守呜,單位為ms)1.8.0 引入
7. 比例閾值(分為慢調(diào)用比例閾值和異常比例閾值,取值范圍[0.0,1.0]山憨,即慢調(diào)用或異常調(diào)用占所有請求的百分比)
僅限熔斷策略為:慢調(diào)用比例 查乒、異常比例。
8. 異常數(shù)(請求或調(diào)用發(fā)生的異常的數(shù)量)
僅限熔斷策略為:異常數(shù)
Sentinel熔斷策略(3種)
1. 慢調(diào)用比例(SLOW_REQUEST_RATIO)
選擇以慢調(diào)用比例作為閾值郁竟,需要設置允許的慢調(diào)用RT(即最大響應時間)玛迄,若請求的響應時間大于該值則統(tǒng)計為慢調(diào)用。
當單位統(tǒng)計時長(statIntervalMs)內(nèi)請求數(shù)目大于設置的最小請求數(shù)目棚亩,且慢調(diào)用的比例大于閾值蓖议,則接下來的熔斷時長內(nèi)請求會自動被熔斷。經(jīng)過熔斷時長后熔斷器會進入探測恢復狀態(tài)(HALF-OPEN 狀態(tài))讥蟆,若接下來的一個請求響應時間小于設置的慢調(diào)用 RT 則結束熔斷勒虾,若大于設置的慢調(diào)用 RT 則再次被熔斷。
2. 異常比例(ERROR_RATIO)
當單位統(tǒng)計時長(statIntervalMs)內(nèi)請求數(shù)目大于設置的最小請求數(shù)目且異常的比例大于閾值瘸彤,則在接下來的熔斷時長內(nèi)請求會自動被熔斷修然。經(jīng)過熔斷時長后熔斷器會進入探測恢復狀態(tài)(HALF-OPEN 狀態(tài)),若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷愕宋。異常比率的閾值范圍是 [0.0, 1.0]玻靡,代表 0% - 100%。
3. 異常數(shù)(ERROR_COUNT)
當單位統(tǒng)計時長內(nèi)的異常數(shù)目超過閾值之后會自動進行熔斷中贝。經(jīng)過熔斷時長后熔斷器會進入探測恢復狀態(tài)(HALF-OPEN 狀態(tài))囤捻,若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷邻寿。
Sentinel熔斷狀態(tài)(3種)
1. 熔斷關閉狀態(tài)(CLOSED)
處于關閉狀態(tài)時最蕾,請求可以正常調(diào)用資源。
滿足以下任意條件老厌,Sentinel熔斷器進入熔斷關閉狀態(tài):
1. 全部請求訪問成功瘟则。
2. 單位統(tǒng)計時長(statIntervalMs)內(nèi)請求數(shù)目小于設置的最小請求數(shù)目。
3. 未達到熔斷標準枝秤,例如服務超時比例醋拧、異常數(shù)、異常比例未達到閾值淀弹。
4. 處于探測恢復狀態(tài)時丹壕,下一個請求訪問成功。
2. 熔斷開啟狀態(tài)(OPEN)
處于熔斷開啟狀態(tài)時薇溃,熔斷器會一定的時間(規(guī)定的熔斷時長)內(nèi)菌赖,暫時切斷所有請求對該資源的調(diào)用,并調(diào)用相應的降級邏輯使請求快速失敗避免系統(tǒng)崩潰沐序。
滿足以下任意條件琉用,Sentinel 熔斷器進入熔斷開啟狀態(tài):
1. 單位統(tǒng)計時長內(nèi)請求數(shù)目大于設置的最小請求數(shù)目,且已達到熔斷標準策幼,例如請求超時比例邑时、異常數(shù)、異常比例達到閾值特姐。
2. 處于探測恢復狀態(tài)時晶丘,下一個請求訪問失敗。
3. 探測恢復狀態(tài)(HALF-OPEN)
處于探測恢復狀態(tài)時唐含,Sentinel 熔斷器會允許一個請求調(diào)用資源浅浮。則若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,熔斷器進入熔斷關閉(CLOSED)狀態(tài)捷枯;否則會再次被熔斷滚秩,熔斷器進入熔斷開啟(OPEN)狀態(tài)。
在熔斷開啟一段時間(降級窗口時間或熔斷時長铜靶,單位為 s)后叔遂,Sentinel 熔斷器自動會進入探測恢復狀態(tài)他炊。
Sentinel實現(xiàn)熔斷降級過程
1. 在項目中,使用@SentinelResource注解的fallback屬性可以為資源指定熔斷降級邏輯(方法)已艰。
2. 通過Sentinel控制臺或代碼定義熔斷規(guī)則痊末,包括熔斷策略、最小請求數(shù)哩掺、閾值凿叠、熔斷時長以及統(tǒng)計時長等。
3. 若單位統(tǒng)計時長(statIntervalMs)內(nèi)嚼吞,請求數(shù)目大于設置的最小請求數(shù)目且達到熔斷標準(例如請求超時比例盒件、異常數(shù)、異常比例達到閾值)舱禽,Sentinel 熔斷器進入熔斷開啟狀態(tài)(OPEN)炒刁。
4. 處于熔斷開啟狀態(tài)時, @SentinelResource 注解的 fallback 屬性指定的降級邏輯會臨時充當主業(yè)務邏輯誊稚,而原來的主邏輯則暫時不可用翔始。當有請求訪問該資源時,會直接調(diào)用降級邏輯使請求快速失敗里伯,而不會調(diào)用原來的主業(yè)務邏輯城瞎。
5. 在經(jīng)過一段時間(在熔斷規(guī)則中設置的熔斷時長)后,熔斷器會進入探測恢復狀態(tài)(HALF-OPEN)疾瓮,此時 Sentinel 會允許一個請求對原來的主業(yè)務邏輯進行調(diào)用脖镀,并監(jiān)控其調(diào)用結果。
6. 若請求調(diào)用成功狼电,則熔斷器進入熔斷關閉狀態(tài)(CLOSED )蜒灰,服務原來的主業(yè)務邏輯恢復,否則重新進入熔斷開啟狀態(tài)(OPEN)漫萄。
下載Sentinel控制臺
1. 啟動Sentinel控制臺(Dashboard)
java -jar sentinel-dashboard-xxx.jar
2. 瀏覽器訪問http://localhost:8080/卷员,輸入用戶名和密碼(默認都是 sentinel)
示例
- 引入Sentinel依賴
創(chuàng)建spring-cloud-alibaba-sentinel-service-8401子項目
1. 修改pom.xml文件
<dependencies>
<!--Nacos 服務發(fā)現(xiàn)依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--Snetinel 依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后續(xù)做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建application.yml配置文件(類路徑resources目錄下)
server:
port: 8401 #端口
spring:
application:
name: sentinel-service #服務名
cloud:
nacos:
discovery:
#Nacos服務注冊中心(集群)地址
server-addr: localhost:1111
sentinel:
transport:
#配置 Sentinel dashboard 地址
dashboard: localhost:8080
#默認8719端口奕枢,假如被占用會自動從8719開始依次+1掃描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
3. 創(chuàng)建SentinelFlowLimitController.java
package com.sst.cx.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class SentinelFlowLimitController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/testA")
public String testA() {
return "服務訪問成功------testA";
}
@GetMapping("/testB")
public String testB() {
return "服務訪問成功------testB";
}
}
4. 在主啟動類上瘪板,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能岳链。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaSentinelService8401Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaSentinelService8401Application.class, args);
}
}
5. 依次啟動NacosServer集群、 spring-cloud-alibaba-sentinel-service-8401
在瀏覽器中訪問http://localhost:8401/testA岩瘦。
訪問Sentinel控制臺主頁,在“首頁”下方新增了一個“sentinel-servcie”的菜單窿撬,而這正是 spring-cloud-alibaba-sentinel-service-8401 的服務名(spring.application.name)启昧,說明 Sentinel 已經(jīng)監(jiān)控到這個服務。點擊“實時監(jiān)控”劈伴,查看sentinel-service下各請求的實時監(jiān)控數(shù)據(jù)密末。
- 定義資源(通過SphU、SphO、注解 定義資源)
1. 在spring-cloud-alibaba-sentinel-service-8401的SentinelFlowLimitController中严里,創(chuàng)建
testAbySphU()方法新啼、testBbySphO()方法、testC()方法刹碾,分別定義資源:testAbySphU燥撞、testBbySphO、testCbyAnnotation迷帜。
// 通過 SphU 手動定義資源
public String testAbySphU() {
Entry entry = null;
try {
entry = SphU.entry("testAbySphU");
// 您的業(yè)務邏輯 - 開始
log.info("服務訪問成功------testA:"+serverPort);
return "服務訪問成功------testA:"+serverPort;
// 您的業(yè)務邏輯 - 結束
} catch (BlockException e1) {
// 流控邏輯處理 - 開始
log.info("testA 服務被限流");
return "testA 服務被限流";
// 流控邏輯處理 - 結束
} finally {
if (entry != null) {
entry.exit();
}
}
}
// 通過 SphO 手動定義資源
public String testBbySphO() {
if (SphO.entry("testBbySphO")) {
// 務必保證finally會被執(zhí)行
try {
log.info("服務訪問成功------testB:" + serverPort);
return "服務訪問成功------testB:" + serverPort;
} finally {
SphO.exit();
}
} else {
// 資源訪問阻止物舒,被限流或被降級
// 流控邏輯處理 - 開始
log.info("testB 服務被限流");
return "testB 服務被限流";
// 流控邏輯處理 - 結束
}
}
// 通過注解定義資源
@GetMapping("/testC")
@SentinelResource(value = "testCbyAnnotation")
public String testC() {
log.info("服務訪問成功------testC:" + serverPort);
return "服務訪問成功------testC:" + serverPort;
}
在testA()方法中直接返回testAbySphU();、在testB()方法中直接返回testBbySphO();
2. 重啟 spring-cloud-alibaba-sentinel-service-8401戏锹,
在瀏覽器中訪問http://localhost:8401/testA冠胯、http://localhost:8401/testB、http://localhost:8401/testC锦针,訪問Sentinel控制臺主頁涵叮,點擊sentinel-service下的“簇點鏈路”。
- 流量控制
===》1. 通過Sentinel控制臺定義流控規(guī)則
1. 在 spring-cloud-alibaba-sentinel-service-8401 下的 SentinelFlowLimitController 中伞插,新增
// 通過 Sentinel 控制臺定義流控規(guī)則
@GetMapping("/testD")
public String testD() {
log.info("服務訪問成功------testD:" + serverPort);
return "服務訪問成功------testD:" + serverPort;
}
2. 重啟 spring-cloud-alibaba-sentinel-service-8401割粮,
在瀏覽器中訪問http://localhost:8401/testD,點擊 sentinel-sevice 下的“簇點鏈路”,點擊“/testD”右側(cè)的“+流控”按鈕媚污,在彈出的“新增流控規(guī)則”窗口中定義流控規(guī)則(單機閥值添2舀瓢,其他默認),點擊新增按鈕耗美,跳轉(zhuǎn)到“流控規(guī)則”列表京髓。
3. 快速連續(xù)(頻率大于每秒鐘 2 次)訪問http://localhost:8401/testD,頁面會顯示Blocked by Sentinel (flow limiting)商架,說明該服務已被限流堰怨。這種提示是Sentinel系統(tǒng)自動生成的,用戶體驗不好蛇摸。
4. 在服務代碼SentinelFlowLimitController中使用 @SentinelResource注解定義資源名稱备图,并在 blockHandler屬性指定一個限流函數(shù),來自定義服務限流信息(展示給用戶):
// 通過 Sentinel 控制臺定義流控規(guī)則
@GetMapping("/testD")
@SentinelResource(value = "testD-resource", blockHandler = "blockHandlerTestD")
public String testD() {
log.info("服務訪問成功------testD:" + serverPort);
return "服務訪問成功------testD:" + serverPort;
}
// 限流之后的邏輯
public String blockHandlerTestD(BlockException exception) {
log.info(Thread.currentThread().getName() + "TestD服務訪問失敗! 您已被限流赶袄,請稍后重試");
return "TestD服務訪問失敗! 您已被限流揽涮,請稍后重試";
}
使用@SentinelResource注解的blockHandler屬性時,需要注意以下事項:
1. blockHandler 函數(shù)訪問范圍需要是 public饿肺;
2. 返回類型需要與原方法相匹配蒋困;
3. 參數(shù)類型需要和原方法相匹配并且最后加一個額外的參數(shù),類型為 BlockException敬辣;
4. blockHandler 函數(shù)默認需要和原方法在同一個類中雪标,若希望使用其他類的函數(shù)零院,則可以指定 blockHandler 為對應的類的 Class 對象,注意對應的函數(shù)必需為 static 函數(shù)村刨,否則無法解析门粪。
5. 請務必添加 blockHandler 屬性來指定自定義的限流處理方法,若不指定烹困,則會跳轉(zhuǎn)到錯誤頁(用戶體驗不好)玄妈。
5. 重啟 spring-cloud-alibaba-sentinel-service-8401,在瀏覽器中訪問Sentinel控制臺主頁髓梅,點擊 sentinel-sevice 下的“簇點鏈路拟蜻,點擊資源“testD-resource”右側(cè)的“+流控”按鈕,并在彈出的“新增流控規(guī)則”窗口中為這個資源定義流控規(guī)則枯饿,流控規(guī)則內(nèi)容為 :QPS 的閾值為 2(即每秒最多通過 2 個請求)
6. 快速連續(xù)(頻率大于每秒鐘 2 次)訪問http://localhost:8401/testD酝锅,結果如下:
TestD服務訪問失敗! 您已被限流,請稍后重試
===》2. 通過代碼定義流控規(guī)則
在SentinelFlowLimitController中奢方,首先通過FlowRule的以下屬性來定義流控規(guī)則搔扁,然后調(diào)用FlowRuleManager類的loadRules(List<FlowRule>)方法。
1. resource(資源名蟋字,即流控規(guī)則的作用對象)
2. count(限流的閾值)
3. grade(流控閾值的類型:QPS---默認值稿蹲、并發(fā)線程數(shù))
4. limitApp(流控針對的調(diào)用來源。默認值:default鹊奖,表示不區(qū)分調(diào)用來源)
5. strategy(調(diào)用關系限流策略:直接--默認值苛聘、鏈路、關聯(lián))
6. controlBehavior(流控效果:直接拒絕--默認值忠聚、Warm Up设哗、勻速排隊)不支持按調(diào)用關系限流。
1. SentinelFlowLimitController 中添加一個 initFlowRules() 方法两蟀,為名為 testD-resource 的資源定義流控規(guī)則:每秒最多只能通過 2 個請求(即:QPS的閾值為 2)
// 通過代碼定義流量控制規(guī)則
private static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
// 定義一個限流規(guī)則對象
FlowRule rule = new FlowRule();
// 資源名稱
rule.setResource("testD-resource");
// 限流閾值的類型
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 設置 QPS 的閾值為 2
rule.setCount(2);
rules.add(rule);
// 定義限流規(guī)則
FlowRuleManager.loadRules(rules);
}
2. 在testD()方法中調(diào)用initFlowRules()方法网梢,初始化流控規(guī)則:
@GetMapping("/testD")
@SentinelResource(value = "testD-resource", blockHandler = "blockHandlerTestD")
public String testD() {
initFlowRules(); // 調(diào)用初始化流控規(guī)則的方法
log.info("服務訪問成功------testD:" + serverPort);
return "服務訪問成功------testD:" + serverPort;
}
3. 重啟spring-cloud-alibaba-sentinel-service-8401,
使用瀏覽器訪問“http://localhost:8401/testD
服務訪問成功------testD:8401
快速連續(xù)(頻率大于每秒鐘 2 次)訪問http://localhost:8401/testD
TestD服務訪問失敗! 您已被限流赂毯,請稍后重試
命令查看資源的實時統(tǒng)計信息
curl http://localhost:8719/cnode?id=testD-resource
idx id thread pass blocked success total aRt 1m-pass 1m-block 1m-all exception
說明:
1. thread: 代表當前處理該資源的并發(fā)數(shù)战虏;
2. pass: 代表一秒內(nèi)到來到的請求;
3. blocked: 代表一秒內(nèi)被流量控制的請求數(shù)量欢瞪;
4. success: 代表一秒內(nèi)成功處理完的請求活烙;
5. total: 代表到一秒內(nèi)到來的請求以及被阻止的請求總和;
6. RT: 代表一秒內(nèi)該資源的平均響應時間遣鼓;
7. 1m-pass: 則是一分鐘內(nèi)到來的請求;
8. 1m-block: 則是一分鐘內(nèi)被阻止的請求重贺;
9. 1m-all: 則是一分鐘內(nèi)到來的請求和被阻止的請求的總和骑祟;
10. exception: 則是一秒內(nèi)業(yè)務本身異常的總和回懦。
- 熔斷降級
===》1. 通過Sentinel控制臺定義熔斷降級規(guī)則
創(chuàng)建spring-cloud-alibaba-api子項目
1. 修改pom.xml文件
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. 創(chuàng)建User.java
package com.sst.cx.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@AllArgsConstructor
@NoArgsConstructor // 無參構造函數(shù)
@Data // 提供類的get、set次企、equals怯晕、hashCode、canEqual缸棵、toString 方法
@Accessors(chain = true)
public class User implements Serializable {
private Integer id;
private String name;
private String password;
}
3. 創(chuàng)建CommonResult.java
package com.sst.cx.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message) {
this(code, message, null);
}
}
創(chuàng)建spring-cloud-alibaba-provider-mysql-8003子項目
1. 修改pom.xml文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>net.biancheng.c</groupId>
<artifactId>spring-cloud-alibaba-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--添加 Spring Boot 的監(jiān)控模塊-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建application.yml配置文件(類路徑resources目錄下)
server:
port: 8003 #端口
spring:
application:
name: spring-cloud-alibaba-provider-mysql
cloud:
nacos:
discovery:
server-addr: localhost:1111
####### 數(shù)據(jù)庫連接 #######
datasource:
username: root #數(shù)據(jù)庫登陸用戶名
password: 12345678 #數(shù)據(jù)庫登陸密碼
url: jdbc:mysql://127.0.0.1:3306/test #數(shù)據(jù)庫url
driver-class-name: com.mysql.cj.jdbc.Driver
management:
endpoints:
web:
exposure:
include: "*" # * 在yaml 文件屬于關鍵字舟茶,所以需要加引號
###### MyBatis 配置 #######
mybatis:
# 指定 mapper.xml 的位置
mapper-locations: classpath:mybatis/mapper/*.xml
#掃描實體類的位置,在此處指明掃描實體類的包,在 mapper.xml 中就可以不寫實體類的全路徑名
type-aliases-package: com.sst.cx.domain
configuration:
#默認開啟駝峰命名法堵第,可以不用設置該屬性
map-underscore-to-camel-case: true
3. 創(chuàng)建UserMapper.java
package com.sst.cx.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.sst.cx.domain.User;
@Mapper
public interface UserMapper {
// 根據(jù)主鍵獲取數(shù)據(jù)
User selectByPrimaryKey(Integer id);
// 獲取表中的全部數(shù)據(jù)
List<User> getAll();
}
4. 創(chuàng)建UserMapper.xml(resources/mybatis/mapper/目錄下)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sst.cx.mapper.UserMapper">
<sql id="Base_Column_List">
id, name, password
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultType="User">
select
<include refid="Base_Column_List"/>
from users
where id = #{id,jdbcType=INTEGER}
</select>
<select id="getAll" resultType="User">
select *
from users;
</select>
</mapper>
7. 創(chuàng)建UserService.java
package com.sst.cx.service;
import java.util.List;
import com.sst.cx.domain.User;
public interface UserService {
User get(Integer id);
List<User> selectAll();
}
5. 創(chuàng)建UserServiceImpl.java
package com.sst.cx.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sst.cx.domain.User;
import com.sst.cx.mapper.UserMapper;
import com.sst.cx.service.UserService;
import java.util.List;
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User get(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
@Override
public List<User> selectAll() {
return userMapper.getAll();
}
}
6. 創(chuàng)建UserController.java
package com.sst.cx.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.sst.cx.domain.*;
import com.sst.cx.service.UserService;
@RestController
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/user/get/{id}", method = RequestMethod.GET)
public CommonResult<User> get(@PathVariable("id") int id) {
log.info("端口:" + serverPort + "\t+ user/get/");
try {
TimeUnit.SECONDS.sleep(1);
log.info("休眠 1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
User user = userService.get(id);
CommonResult<User> result = new CommonResult(200, "from mysql,serverPort: " + serverPort, user);
return result;
}
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public CommonResult<List<User>> list() {
log.info("端口:" + serverPort + "\t+ user/list/");
List<User> userList = userService.selectAll();
CommonResult<List<User>> result = new CommonResult(200, "from mysql,serverPort: " + serverPort, userList);
return result;
}
}
7. 在主啟動類上吧凉,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaProviderMysql8003Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaProviderMysql8003Application.class, args);
}
}
創(chuàng)建spring-cloud-alibaba-consumer-mysql-8803子項目
1. 修改pom.xml文件
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入 OpenFeign 的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.sst.cx</groupId>
<artifactId>spring-cloud-alibaba-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2. 創(chuàng)建application.yml配置文件(類路徑resources目錄下)
server:
port: 8803
spring:
application:
name: spring-cloud-alibaba-consumer-mysql-feign
cloud:
nacos:
discovery:
server-addr: localhost:1111
sentinel:
transport:
dashboard: localhost:8080
port: 8719
# 以下配置信息并不是默認配置踏志,而是我們自定義的配置阀捅,目的是不在 Controller 內(nèi)硬編碼 服務提供者的服務名
service-url:
nacos-user-service: http://spring-cloud-alibaba-provider-mysql #消費者要方位的微服務名稱
# 激活Sentinel對Feign的支持
feign:
sentinel:
enabled: true
3. 創(chuàng)建UserFeignService.java
package com.sst.cx.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.sst.cx.domain.*;
import java.util.List;
@Component
@FeignClient(value = "spring-cloud-alibaba-provider-mysql", fallback = UserFallbackService.class)
public interface UserFeignService {
@RequestMapping(value = "/user/get/{id}", method = RequestMethod.GET)
public CommonResult<User> get(@PathVariable("id") int id);
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public CommonResult<List<User>> list();
}
4. 創(chuàng)建UserFallbackService.java
package com.sst.cx.service;
import java.util.List;
import org.springframework.stereotype.Component;
import com.sst.cx.domain.CommonResult;
import com.sst.cx.domain.User;
@Component
public class UserFallbackService implements UserFeignService{
@Override
public CommonResult<User> get(int id) {
System.err.println("--------->>>>服務降級邏輯");
User user = new User(id, "null", "null");
return new CommonResult(444, "服務被降級" , user);
}
@Override
public CommonResult<List<User>> list() {
System.err.println("--------->>>>服務降級邏輯");
return null;
}
}
5. 創(chuàng)建UserFeignController.java
package com.sst.cx.service.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
import com.alibaba.csp.sentinel.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.sst.cx.domain.*;
import com.sst.cx.service.UserFeignService;
@RestController
@Slf4j
public class UserFeignController {
@Resource
UserFeignService userFeignService;
// 使用@SentinelResource注解的fallback屬性指定了一個fallback函數(shù),進行熔斷降級的后續(xù)處理针余。
@RequestMapping(value = "consumer/feign/user/get/{id}", method = RequestMethod.GET)
@SentinelResource(value = "fallback", fallback = "handlerFallback")
public CommonResult<User> get(@PathVariable("id") int id) {
monitor();
System.out.println("--------->>>>主業(yè)務邏輯");
CommonResult<User> result = userFeignService.get(id);
if (id == 6) {
System.err.println("--------->>>>主業(yè)務邏輯饲鄙,拋出非法參數(shù)異常");
throw new IllegalArgumentException("IllegalArgumentException,非法參數(shù)異常....");
} else if (result.getData() == null) {
System.err.println("--------->>>>主業(yè)務邏輯圆雁,拋出空指針異常");
throw new NullPointerException("NullPointerException忍级,該ID沒有對應記錄,空指針異常");
}
return result;
}
@RequestMapping(value = "consumer/feign/user/list", method = RequestMethod.GET)
public CommonResult<List<User>> list() {
return userFeignService.list();
}
// 處理異常的回退方法(服務降級)
public CommonResult handlerFallback(@PathVariable int id, Throwable e) {
System.err.println("--------->>>>服務降級邏輯");
User user = new User(id, "null", "null");
return new CommonResult(444, "服務被降級!異常信息為:" + e.getMessage(), user);
}
// 自定義事件監(jiān)聽器伪朽,監(jiān)聽熔斷器狀態(tài)轉(zhuǎn)換
public void monitor() {
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
(prevState, newState, rule, snapshotValue) -> {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (newState == CircuitBreaker.State.OPEN) {
// 變換至 OPEN state 時會攜帶觸發(fā)時的值
System.err.println(String.format("%s -> OPEN at %s, 發(fā)送請求次數(shù)=%.2f", prevState.name(),
format.format(new Date(TimeUtil.currentTimeMillis())), snapshotValue));
} else {
System.err.println(String.format("%s -> %s at %s", prevState.name(), newState.name(),
format.format(new Date(TimeUtil.currentTimeMillis()))));
}
});
}
}
5. 在主啟動類上颤练,添加@EnableDiscoveryClient注解開啟Nacos服務發(fā)現(xiàn)功能、添加@EnableFeignClients注解開啟驱负。
package com.sst.cx;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudAlibabaConsumerMysql8803Application {
public static void main(String[] args) {
SpringApplication.run(SpringCloudAlibabaConsumerMysql8803Application.class, args);
}
}
6. 依次啟動 NacosServer集群嗦玖、Sentinel控制臺、spring-cloud-alibaba-provider-mysql-8003 和 spring-cloud-alibaba-consumer-mysql-8803跃脊,
在瀏覽器中訪問http://localhost:8803/consumer/feign/user/get/1宇挫,結果如下
{"code":200,"message":"from mysql,serverPort: 8003","data":{"id":1,"name":"zhansan","password":"123456"}}
在瀏覽器訪問“http://localhost:8803/consumer/feign/user/get/7”,結果如下
{"code":444,"message":"服務被降級酪术!異常信息為:NullPointerException器瘪,該ID沒有對應記錄,空指針異常","data":{"id":7,"name":"null","password":"null"}}
7. 訪問Sentinel控制臺,在“簇點鏈路”列表中绘雁,點擊fallback資源的“+降級”按鈕橡疼,選擇異常數(shù),并設置異常數(shù)為1庐舟,熔斷時常(時間窗口)為10s欣除。
當熔斷器處于熔斷開啟狀態(tài)時,所有的請求都直接交給降級邏輯處理挪略。
熔斷器在經(jīng)歷了10秒的熔斷時長后历帚,自動切換到了探測恢復狀態(tài)(HALF-OPEN)滔岳,并在下一個請求成功的情況下,結束了熔斷開啟狀態(tài)挽牢,切換到了熔斷關閉狀態(tài)(CLOSED)谱煤。
【存疑:無法設置最小請求數(shù)、統(tǒng)計時長禽拔,1.70版本沒有這兩選項刘离,未進入熔斷狀態(tài)】
===》2. 通過代碼定義熔斷規(guī)則
首先通過DegradeRule類的以下屬性來定義熔斷降級規(guī)則,然后調(diào)用DegradeRuleManager類(Sentinel核心庫提供)的loadRules(List<DegradeRule> rules) 方法睹栖。
1. resource(資源名硫惕,即規(guī)則的作用對象)
2. grade(熔斷策略,慢調(diào)用比例---默認磨淌、異常比例疲憋、異常數(shù)策略)
3. count(慢調(diào)用比例模式下為慢調(diào)用臨界RT,超出該值計為慢調(diào)用梁只;異常比例/異常數(shù)模式下為對應的閾值)
4. timeWindow(熔斷時長缚柳,單位為s)
5. minRequestAmount(熔斷觸發(fā)的最小請求數(shù),默認5搪锣,請求數(shù)小于該值時即使異常比率超出閾值也不會熔斷)1.7.0 引入【注意該屬性】
6. statIntervalMs(統(tǒng)計時長秋忙,單位為ms,默認1000ms)1.8.0 引入
7. slowRatioThreshold(慢調(diào)用比例閾值构舟,僅慢調(diào)用比例模式有效)1.8.0 引入
1. 在 spring-cloud-alibaba-consumer-mysql-8803的UserFeignController 中灰追,添加initDegradeRule方法定義熔斷規(guī)則(30s內(nèi)當請求數(shù)>=100且異常率大于0.7時會進入熔斷狀態(tài)10s),在UserFeignController的get()方法的開始處調(diào)用initDegradeRule()方法初始化熔斷規(guī)則狗超。
// 初始化熔斷策略
private static void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule("fallback");
// 熔斷策略為異常比例
rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
// 異常比例閾值
rule.setCount(0.7);
// 最小請求數(shù)
rule.setMinRequestAmount(100);
// 統(tǒng)計時長弹澎,單位毫秒
rule.setStatIntervalMs(30000);
// 熔斷時長,單位秒
rule.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
2. 重啟spring-cloud-alibaba-consumer-mysql-8803努咐,
在瀏覽器中訪問http://localhost:8803/consumer/feign/user/get/1苦蒿,結果如下
{"code":200,"message":"from mysql,serverPort: 8003","data":{"id":1,"name":"zhansan","password":"123456"}}
訪問Sentinel控制主頁,點擊“降級規(guī)則”查看熔斷降級規(guī)則列表渗稍。