Spring Cloud Alibaba中文參考文檔:Spring Cloud Alibaba 參考文檔 (spring-cloud-alibaba-group.github.io)
一、navos
二、Sentinel
由於現在用的是springcloudalibaba的相關組件,不需要之前的一些組件了,所以吧項目之前的組件全部清除掉,只留下book-service、borrow-service、user-service,並且清除掉之前的依賴和配置
1、服務端部署
訪問https://github.com/alibaba/nacos
點擊Releases
下滑
點擊下載
吧下載好的壓縮包解壓,後將裏邊的nacos放到spring_cloud_study項目中
要啓動nacos可以進入nacos=>bin中在cmd中用startup.cmd -m standalone來啓動,直接startup.cmd會報錯
(27條消息) 【SpringCloudAlibaba】解決Nacos啓動報錯:ERROR Nacos failed to start,please see XXX 問題_吳Sir.的博客-CSDN博客
解決方法2:編輯startup.cmd,將startup.cmd中的MODE改為standalone,意思就是打開方式為單機版方式啓動,這樣直接雙擊startup.cmd也可以啓動
啓動後在瀏覽器中輸入http://localhost:8848/nacos用8848端口訪問nacos並且使用用户名nacos和密碼nacos登錄
在idea中配置nacos服務的啓動
(27條消息) Idea中配置Nacos服務的啓動_idea nacos_lucky趙的博客-CSDN博客
有的idea在Edit Configurations中沒有shell script,在設置中的Plugins中下載BashSupport,重啓idea
再次進入Edit Configurations,加號有Bash,點擊後配置
Apply後OK,點擊啓動鍵後啓動nacos
訪問http://localhost:8848/nacos/用來測試nacos配置完成情況
2、nacos的服務註冊於發現
在父類項目中添加依賴
<!--這裏引入最新的SpringCloud依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--這裏引入最新的SpringCloudAlibaba依賴,2021.0.1.0版本支持SpringBoot2.6.X-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
目前完整pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>user-service</module>
<module>book-service</module>
<module>borrow-service</module>
<!--<module>eureka-server</module>-->
<!--<module>hystrix-dashboard</module>-->
<!--<module>gateway-server</module>-->
<!--<module>config-server</module>-->
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring_cloud_study</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring_cloud_study</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
<!--由於不是每個子項目都要用mybatis,因此只再父項目做版本的管理,子項目自行做引入-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<!--這裏引入最新的SpringCloud依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--這裏引入最新的SpringCloudAlibaba依賴,2021.0.1.0版本支持SpringBoot2.6.X-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在三個子項目中添加依賴:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
目前完整的pom.xml(user-service子項目的)
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>spring_cloud_study</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
</project>
配置文件中配置:
application.yml
cloud:
nacos:
discovery:
# 配置Nacos註冊中心地址
server-addr: localhost://8848
啓動查看nacos
將剩下兩個子項目也註冊到nacos中
3、使用openfeign,實現服務發現遠程調用以及負載均衡
去borrow-service子項目中導入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--這裏需要單獨導入LoadBalancer依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
完整pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>spring_cloud_study</artifactId>
<groupId>com.example</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>borrow-service</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--這裏需要單獨導入LoadBalancer依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>
創建client包,在裏邊創建UserClient.java,和之前的一樣
UserClient.java
package com.test.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Date 2023/3/29 - 13:53
*/
@FeignClient(value="userservice",fallback = UserFallbackCilent.class)//聲明為userservice服務的HTTP請求客户端
public interface UserClient {
@RequestMapping("/UserController/hello/{user}")
String hello(@PathVariable("user") String user);
}
創建controller包,裏邊創建BorrowController.java
BorrowController.java
package com.test.controller;
//import com.netflix.discovery.converters.Auto;
//import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.test.client.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* @Date 2023/3/27 - 15:22
*/
@RestController
@RequestMapping("BorrowController")
public class BorrowController {
@Resource
private UserClient userClient;
// @HystrixCommand(fallbackMethod = "onError")
@GetMapping("/hello/{borrow}")
public String hello(@PathVariable("borrow") String borrow, HttpServletRequest request){
// 測試gateway過濾器
System.out.println(request.getHeader("Test"));
String user=userClient.hello(borrow);
return borrow+user;
}
//// 備選方案,這裏直接返回一個字符串
//// 注意參數和返回值要和上面一致
// String onError(String borrow){
// System.out.println("2");
// return "error:"+borrow;
// }
}
在啓動類中添加註解開啓openfeign
@EnableFeignClients
UserController.java
package com.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Date 2023/3/27 - 15:24
*/
@RestController
@RequestMapping("UserController")
public class UserController {
@GetMapping("/hello/{user}")
public String hello(@PathVariable("user") String user){
System.out.println("hello Userservice");
return user;
}
}
測試:
在創建一個user-service實例
點加號=>Spring Boot,然後配置
把之前有的userservice改個名字
Apply=>OK
重啓兩個userservice
去nacos中看眼
測試:
刷新五次,可以看見兩個服務已經被負載均衡
4、通過配置文件進行修改臨時實例:
臨時和非臨時區別:
給borrow-service子項目添加配置
# ephemeral改為false,表示非臨時實例
ephemeral: false
重啓服務,去nacos中查看,點擊詳情
看到臨時實例為false,不加上邊的配置為true
關閉borrow-service服務再次查看nacos,可以看到沒有在nacos中消失,而是標記健康實例數為0,詳情中的健康狀態為false
5、nacos的集羣分區
消費者調用生產者應該優先調用同一個區域的,這樣響應速度更快。
默認的分區是default
修改分區:給userservice-01和userservice-02分別添加環境變量
spring.cloud.nacos.discovery.cluster-name=Chongqing
也可以在配置文件中添加配置
重啓兩個服務,在nacos中查看
再把borrow-service的集羣改成成都的,重啓查看nacos
這時候請求borrow-service測試四次,發現userservice-01和userservice-02都有打印語句,説明現在的服務並沒有按照集羣劃分。
因此在borrow-service下添加配置
# 將loadbalancer的nacos支持開啓,集成nacos負載均衡
loadbalancer:
nacos:
enabled: true
注意這個loadbalancer是cloud下的
再次重啓測試,請求五次,發現請求全是和borrow-service同一集羣的userservice-02響應的
在nacos中把userservice-02下線,再次請求五次,發現這次請求全是userservice-01響應的。
6、權重機制
根據區域優先調用之外,同一區域內的實例也可以單獨設置權重,nacos會優先選擇權重更大的實例進行調用,我們可以直接在nacos管理頁面配置,或者是在配置文件中配置
配置文件:
7、nacos配置中心
在nacos管理界面的配置管理
添加配置信息,把userservice的application.yml中的配置粘貼到配置內容中,發佈。
在userservice中添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
添加配置:bootstrap.yml
spring:
application:
name: userservice
profiles:
# 環境也是和配置文件保持一致
active: dev
cloud:
nacos:
config:
# 配置文件後綴名
file-extension: yml
# 配置中心服務器地址,也是nacos地址
server-addr: localhost:8848
重啓測試
nacos還支持文件的熱更新,比如我們在配置文件中添加了一個屬性,而這時候可能需要實時修改,並在後端實時更新。
測試:
在userservice中的controller中做點改動
UserController.java
package com.test.controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Date 2023/3/27 - 15:24
*/
@RestController
@RequestMapping("UserController")
public class UserController {
@Value("${test.aa}")//從配置文件中讀取test.aa的字符串值,作為test接口的返回值
String test;
@GetMapping("/hello/{user}")
public String hello(@PathVariable("user") String user){
System.out.println("hello Userservice");
System.out.println(test);
return user;
}
}
然後再nacos中在userservice的配置添加test.aa以及值
重啓userservice測試
現在在nacos中修改配置,把aa改成1111111
如果不重啓服務響應的還是之前的nihao
添加註解@RefreshScope就可以實現自動刷新了
在UserController.java上加註解
重啓userservice服務,先請求看test.aa的值,在去nacos中修改配置值後再次查看。
請求一次
修改test.aa的值
userservice的日誌已經更新,發現test.aa被修改
再次請求,響應的是22222
8、nacos命名空間
在nacos界面的命名空間中點擊新建命名空間
創建一個開發環境
點擊dev可以查看剛創建的空間情況
把bookservice服務放到dev中
在bookservice服務的配置文件中添加配置信息
這裏namespace的值為nacos中生成dev空間的id值
重啓bookservice查看nacos
把userservice也放進dev空間中
現在是borrowservice沒在dev中,userservice在dev中,兩個服務沒有在同一個命名空間中,請求borrowservice,會發現userservice不能被發現
把borrowservice也放進dev中就可以發現了。
又能訪問了。
這裏的分組也是在配置中能配置。默認就是DEFAULT_GROUP
9、nacos在linux環境中搭建集羣
Nacos:集羣搭建(一)_嗶哩嗶哩_bilibili
在navicat中創建數據庫,運行SQL文件,運行的文件為nacos-server=>conf=>nacos-mysql.sql
把nacos-server傳到linux環境中,並且解壓
解壓命令:unzip 包名
進入nacos/conf/中編輯application.properties
### Default web server port:
server.port=8801
#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false
### Specify local server's IP:
# nacos.inetutils.ip-address=
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql
### Count of DB:
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://xxx/nacos_demo?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=nacos
db.password.0=nacos
db.url.0、db.user.0、db.password.0都修改成自己的,就是連接這個圖中的nacos_demo數據庫
然後配置集羣
把cluster.conf.example的.example去掉
編輯cluster.conf之前用ifconfig看內網ip,是127.0.0.1
編輯cluster.conf
編輯前
編輯後
保存退出
修改nacos的內存分配以及前台啓動,直接修改startup.sh文件
改動前
改動後
在拷貝一個nacos出來,名字為nacos2
用兩個會話分別打開兩個nacos
下載nginx
wget http://nginx.org/download/nginx-1.13.7.tar.gz
解壓
tar -xvf nginx-1.13.7.tar.gz
進入nginx-1.13.7=>conf
編輯nginx.conf,內容都改成自己的
...
二、Sentinel
1.配置sentinel
去Releases · alibaba/Sentinel (github.com)下載jar
在spring_cloud_study項目中創建目錄sentinel,把下好的jar包放進去
idea中Edit
加號,JAR Application
配置
應用=>OK
啓動,測試,用户和密碼都是sentinel
把服務連接到控制枱中,給三個服務添加依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
修改配置文件,在cloud下邊,spring.cloud.sentinel.transport.dashboard
sentinel:
transport:
# 添加監控頁面地址
dashboard: localhost:8858
啓動測試,這時候還是沒內容
進行一次請求
QPS是每秒查詢率
2.sentinel流量控制
在sentinel中點想要限流的接口後邊的流控
單機閾值定為1,閾值類型為qps,意思就是一秒之內只能有一條請求
流控模式Sentinel 三種流控模式_sentinel流控模式_楊 戩的博客-CSDN博客
流控效果是sentinel的三種限流措施Sentinel 三種流控效果_sentinel流控效果_楊 戩的博客-CSDN博客
方案一就是快速失敗、方案二就是warm up、方案三就是排隊等待(排隊等待的超時時間單位為毫秒)
設置好後點擊新增。
流控規則中就有一條剛新增的規則
測試:正常一秒請求一次和一秒多點幾次
測試流控模式:關聯
修改流控模式為關聯,並且關聯資源為/error
去postman中設置一個對/error的請求,請求100次,間隔500毫秒
postman右下角的runner,在把左邊保存的請求拖到run order中,在右邊設置迭代和間隔,點擊run
開始請求
現在在BorrowController/hello/aaaass接口的相關接口/error請求時,在瀏覽器中對BorrowController/hello/aaaass進行請求
怎麼請求都會被限流
在/error請求完後這個接口不被限流
測試流控模式:鏈路
我們可以用@SentinelResource註解對某個方法進行標註,對某一個方法進行限流控制,無論是誰在何處調用了他,那麼就會進行監控。
這裏給borrow-service的controller層的hello方法加@SentinelResource註解,並且命名為test
然後在application.yml中添加配置
# 關閉Context收斂,這樣被監控方法可以進行不同鏈路的單獨控制
web-context-unify: false
完整
server:
port: 8301
# 配置數據源信息
spring:
application:
name: borrowservice
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
username: root
password: root
cloud:
nacos:
discovery:
# 配置Nacos註冊中心地址
server-addr: localhost:8848
# ephemeral改為false,表示非臨時實例
ephemeral: false
cluster-name: Chengdu
# 權重大小,越大越優先調用,默認為1
weight: 0.5
namespace: f34784a5-ec4d-4659-a907-f464a4ff7aaf
# 將loadbalancer的nacos支持開啓,集成nacos負載均衡
loadbalancer:
nacos:
enabled: true
sentinel:
transport:
# 添加監控頁面地址
dashboard: localhost:8858
# 關閉Context收斂,這樣被監控方法可以進行不同鏈路的單獨控制
web-context-unify: false
然後重啓服務
重新對borrowservice進行請求後
刷新sentinel控制枱
然後可以針對這個test入口進行添加限流策略,點擊test後邊的流控
這裏的流控模式也可以用直接、關聯或者是鏈路,直接使用鏈路,設置入口資源(想限制那個入口就寫那個)
新增
再次請求,點一次正常,連點兩次報錯限流
控制枱報錯
新增系統規則
除了直接對接口進行限流規則控制之外,我們也可以根據當前系統的資源使用情況,決定是否進行限流,在系統規則的右上角可以新增系統規則
3、限流和異常處理
如果我們不想讓限流後返回默認的界面,而是自己自定義的結果。
在borrow-service的BorrowController中創建要返回的結果
@RequestMapping("/blocked")
JSONObject blocked(){
JSONObject object=new JSONObject();
object.put("code",403);
object.put("success",false);
object.put("message","您的請求過塊,請稍後在試!");
return object;
}
在application.yml中做配置
# 將剛剛編寫的請求映射設定為限流頁面
block-page: /BorrowController/blocked
完整
server:
port: 8301
# 配置數據源信息
spring:
application:
name: borrowservice
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
username: root
password: root
cloud:
nacos:
discovery:
# 配置Nacos註冊中心地址
server-addr: localhost:8848
# ephemeral改為false,表示非臨時實例
ephemeral: false
cluster-name: Chengdu
# 權重大小,越大越優先調用,默認為1
weight: 0.5
namespace: f34784a5-ec4d-4659-a907-f464a4ff7aaf
# 將loadbalancer的nacos支持開啓,集成nacos負載均衡
loadbalancer:
nacos:
enabled: true
sentinel:
transport:
# 添加監控頁面地址
dashboard: localhost:8858
# 關閉Context收斂,這樣被監控方法可以進行不同鏈路的單獨控制
web-context-unify: false
# 將剛剛編寫的請求映射設定為限流頁面
block-page:/BorrowController/blocked
重啓測試,被限流的情況
對於方法級別的限流:
在之前針對方法級別的限流上邊的@SentinelResource註解上邊添加一些設置
注意這個
- 必須是public修飾
- 返回類型與原方法一致
- 參數類型需要和原方法相匹配,並在最後加BlockException類型的參數。
在訪問指定的方法會返回替代方案,不是默認的界面
測試,在給test加了限流後重新請求
注意blockHandler只能處理限流情況下拋出的異常,包括下面要介紹的熱點參數限流也是同理,如果是方法本身拋出的其他類型異常,不在管控範圍內,但是可以通過其他參數進行處理
修改borrow-service中的BorrowController
當他裏邊拋出異常時會走替代方案except
package com.test.controller;
//import com.netflix.discovery.converters.Auto;
//import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSONObject;
import com.sun.deploy.security.BlockedException;
import com.test.client.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
/**
* @Date 2023/3/27 - 15:22
*/
@RestController
@RequestMapping("BorrowController")
public class BorrowController {
@Resource
private UserClient userClient;
// @HystrixCommand(fallbackMethod = "onError")
@SentinelResource(value = "test", blockHandler = "oooo"//監控此方法,無論被誰執行都在監控範圍內,這裏給的value是自定義名稱,
// 這個註解可以加在任何方法上邊,包括Controller中的請求映射方法,跟HystrixCommand很像。指定blockHandler,
// 也就是被限流之後的替代解決方案,這樣就不會使用默認的拋出異常的形式了
, fallback = "except", //fallback指定出現異常時的替代方案(指的是所有異常,blockHandler是BlockException的子異常)
exceptionsToIgnore = IOException.class //忽略那些異常,也就是説這些異常出現時不適用替代方案
)
@GetMapping("/hello/{borrow}")
public String hello(@PathVariable("borrow") String borrow, HttpServletRequest request) {
throw new RuntimeException("helloworld");
// 測試gateway過濾器
// System.out.println(request.getHeader("Test"));
// String user = userClient.hello(borrow);
// return borrow + user;
}
// 替代方案,注意參數和返回值需要保持一致,最後可以添加一個Throwable作為參數接受異常
public String except(String borrow, HttpServletRequest request, Throwable t) {
return "error throwable";
}
// 替代方案,注意參數和返回值需要保持一致,並且參數最後還需要額外添加一個BlockException
public String oooo(String borrow, HttpServletRequest request, BlockException e) {
return "error";
}
@RequestMapping("/blocked")
JSONObject blocked() {
JSONObject object = new JSONObject();
object.put("code", 403);
object.put("success", false);
object.put("message", "您的請求過塊,請稍後在試!");
return object;
}
//// 備選方案,這裏直接返回一個字符串
//// 注意參數和返回值要和上面一致
// String onError(String borrow){
// System.out.println("2");
// return "error:"+borrow;
// }
}
重啓測試
注意:如果blockHandler和fallback同時生效,優先級高的是blockHandler
4、熱點參數限流
在borrow-service中的BorrowController中添加一個接口映射方法
@RequestMapping("/abc")
@SentinelResource("abc")
String abc(@RequestParam(value = "a",required = false) String a,
@RequestParam(value = "b",required = false) String b,
@RequestParam(value = "c",required = false) String c){
return "success a="+a+",b="+b+",c="+c;
}
package com.test.controller;
//import com.netflix.discovery.converters.Auto;
//import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSONObject;
import com.sun.deploy.security.BlockedException;
import com.test.client.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
/**
* @Date 2023/3/27 - 15:22
*/
@RestController
@RequestMapping("BorrowController")
public class BorrowController {
@Resource
private UserClient userClient;
// @HystrixCommand(fallbackMethod = "onError")
@SentinelResource(value = "test", blockHandler = "oooo"//監控此方法,無論被誰執行都在監控範圍內,這裏給的value是自定義名稱,
// 這個註解可以加在任何方法上邊,包括Controller中的請求映射方法,跟HystrixCommand很像。指定blockHandler,
// 也就是被限流之後的替代解決方案,這樣就不會使用默認的拋出異常的形式了
, fallback = "except", //fallback指定出現異常時的替代方案(指的是所有異常,blockHandler是BlockException的子異常)
exceptionsToIgnore = IOException.class //忽略那些異常,也就是説這些異常出現時不適用替代方案
)
@GetMapping("/hello/{borrow}")
public String hello(@PathVariable("borrow") String borrow, HttpServletRequest request) {
// throw new RuntimeException("helloworld");
// 測試gateway過濾器
System.out.println(request.getHeader("Test"));
String user = userClient.hello(borrow);
return borrow + user;
}
// 替代方案,注意參數和返回值需要保持一致,最後可以添加一個Throwable作為參數接受異常
public String except(String borrow, HttpServletRequest request, Throwable t) {
return "error throwable";
}
// 替代方案,注意參數和返回值需要保持一致,並且參數最後還需要額外添加一個BlockException
public String oooo(String borrow, HttpServletRequest request, BlockException e) {
return "error";
}
@RequestMapping("/blocked")
JSONObject blocked() {
JSONObject object = new JSONObject();
object.put("code", 403);
object.put("success", false);
object.put("message", "您的請求過塊,請稍後在試!");
return object;
}
//// 備選方案,這裏直接返回一個字符串
//// 注意參數和返回值要和上面一致
// String onError(String borrow){
// System.out.println("2");
// return "error:"+borrow;
// }
@RequestMapping("/abc")
@SentinelResource("abc")
String abc(@RequestParam(value = "a",required = false) String a,
@RequestParam(value = "b",required = false) String b,
@RequestParam(value = "c",required = false) String c){
return "success a="+a+",b="+b+",c="+c;
}
}
重啓請求測試
然後對攜帶參數a的請求進行限流
進入sentinel控制枱的熱點規則,點擊新建熱點限流規則
資源名為@SentinelResource註解後邊設置的名字,參數索引是第幾個請求參數,這裏0就是a
測試,一秒點一次正常響應,多點幾次會被攔截
如果攜帶參數b,怎麼都不會被攔截
如果攜帶參數a和參數b,也會被當作攜帶a來處理
如果我們想限流帶a的參數,但是又希望a=10時不被限流,qps達到3在進行限流
在熱點規則中編輯剛添加的規則,在高級選項中設置,參數類型為參數的類型,比如a的參數類型是string,參數值就是指定的參數值,限流閾值就是qps值,設置完後點擊添加再點擊保存。
測試,再一秒點擊三次的時候會被攔截,a不等於10的時候是一秒點擊一次的時候被攔截
5、服務熔斷和降級
sentinel中的熔斷和降級:再sentinel的控制枱中點擊熔斷規則,然後新增熔斷規則
慢調用比例策略:
rt是響應時間超過後會被判定為慢調用。
比例閾值是被判定為慢調用的請求比例超過閾值會觸發熔斷。
熔斷時長是在熔斷之前是一個狀態,熔斷後就會進入另一個狀態進行試探,這個狀態的持續時間就是熔斷時長。
最小請求數和統計時長是在統計時長內達到最小請求數後才能正常的統計(按照上邊的規則進行判斷),如果統計時長內沒有執行到最小請求數時,雖然他閾值超過也不會熔斷,如果統計時長內超過到最小請求數時,閾值也超過了就會熔斷。
測試:
先修改borrow-service中的BorrowController的接口
給hello這個接口加個睡眠時間為1秒
在創建個熔斷規則
新增後測試
請求localhost:8301/BorrowController/hello/aaaass後被熔斷,熔斷和限流一樣會走限流頁面。
在等5秒後重新請求localhost:8301/BorrowController/hello/aaaass會正常,再次請求會又被重定向到限流頁面
異常比例策略
修改borrow-service中的BorrowController的接口,讓這個hello接口直接拋異常就行
新建熔斷規則
這個策略就是執行的過程中出現異常的次數,1s(統計時長)請求2次(最小請求數),如果有1次(比例閾值)出現問題就會被熔斷,被熔斷5秒(熔斷時長)。點擊新增
測試:請求慢點就是正常的異常情況,請求快點就會走限流頁面。
注意:如果異常有替代方案,則會走異常的替代方案,不會去限流頁面
異常數策略就是具體的異常數量,到了數量就熔斷
自定義服務降級也是用@SentinelResource註解的blockHandler參數,和限流一樣
讓Feign也支持Sentinel,前面我們使用Hystrix的時候,就可以直接對Feign的每個接口調用單獨進行服務降級,而使用Sentinel也可以
在borrow-service的配置文件application.yml中加配置
# 開啓feign對sentinel的支持
feign:
sentinel:
enabled: true
完整
server:
port: 8301
# 配置數據源信息
spring:
application:
name: borrowservice
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
username: root
password: root
cloud:
nacos:
discovery:
# 配置Nacos註冊中心地址
server-addr: localhost:8848
# ephemeral改為false,表示非臨時實例
ephemeral: false
cluster-name: Chengdu
# 權重大小,越大越優先調用,默認為1
weight: 0.5
namespace: f34784a5-ec4d-4659-a907-f464a4ff7aaf
# 將loadbalancer的nacos支持開啓,集成nacos負載均衡
loadbalancer:
nacos:
enabled: true
sentinel:
transport:
# 添加監控頁面地址
dashboard: localhost:8858
# 關閉Context收斂,這樣被監控方法可以進行不同鏈路的單獨控制
web-context-unify: false
# 將剛剛編寫的請求映射設定為限流頁面
block-page: /BorrowController/blocked
# 開啓feign對sentinel的支持
feign:
sentinel:
enabled: true
添加好UserClient.java和 UserFallbackCilent.java用於接口降級
UserClient.java
package com.test.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Date 2023/3/29 - 13:53
*/
@FeignClient(value="userservice",fallback = UserFallbackCilent.class)//聲明為userservice服務的HTTP請求客户端
public interface UserClient {
@RequestMapping("/UserController/hello/{user}")
String hello(@PathVariable("user") String user);
}
UserFallbackCilent.java
package com.test.client;
import org.springframework.stereotype.Component;
/**
* @Date 2023/3/30 - 14:22
*/
@Component
public class UserFallbackCilent implements UserClient {
@Override
public String hello(String user) {
return "error:"+user;
}
}
正常重啓請求,然後把userservice停止服務,會走替代方案
userservice停止服務後
傳統的RestTemplate