SpringCloud Alibaba學習筆記

来源:https://www.cnblogs.com/xiaobaiLX/archive/2022/12/04/16950908.html
-Advertisement-
Play Games

該筆記整理至尚矽谷周陽老師的SpringCloud課程SpringCloud Alibaba篇 SpringCloud Alibaba入門簡介 Spring Cloud Netflix 項目進入維護模式,Spring Cloud Netflix 將不再開發新的組件。Spring Cloud 版本迭代 ...


該筆記整理至尚矽谷周陽老師的SpringCloud課程SpringCloud Alibaba篇

SpringCloud Alibaba入門簡介

Spring Cloud Netflix 項目進入維護模式,Spring Cloud Netflix 將不再開發新的組件。Spring Cloud 版本迭代算是比較快的,因而出現了很多重大 ISSUE 都還來不及 Fix 就又推另一個 Release 了。進入維護模式意思就是目前一直以後一段時間Spring Cloud Netflix提供的服務和功能就這麼多了,不在開發新的組件和功能了。以後將以維護和Merge分支Full Request為主,新組件功能將以其他替代平代替的方式實現。基於該背景下,誕生了 SpringCloud Alibaba.

官網:https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

SpringCloud Alibaba 特性

  1. 服務限流降級:預設支持 Servlet、Feign、RestTemplate、Dubbo 和 RocketMQ 限流降級功能的接入,可以在運行時通過控制台實時修改限流降級規則,還支持查看限流降級 Metrics 監控。
  2. 服務註冊與發現:適配 Spring Cloud 服務註冊與發現標準,預設集成了 Ribbon 的支持。
  3. 分散式配置管理:支持分散式系統中的外部化配置,配置更改時自動刷新。
  4. 消息驅動能力:基於 Spring Cloud Stream 為微服務應用構建消息驅動能力。
  5. 阿裡雲對象存儲:阿裡雲提供的海量、安全、低成本、高可靠的雲存儲服務。支持在任何應用、任何時間、任何地點存儲和訪問任意類型的數據。
  6. 分散式任務調度:提供秒級、精準、高可靠、高可用的定時(基於 Cron 表達式)任務調度服務。同時提供分散式的任務執行模型,如網格任務。網格任務支持海量子任務均勻分配到所有 Worker(schedulerx-client)上執行。

Spring Alibaba核心組件

image-20220821151343839

官網:https://spring.io/projects/spring-cloud-alibaba#overview

英文文檔:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

中文文檔:https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

Nacos服務註冊和配置中心

Nacos簡介

官網:https://nacos.io/zh-cn/index.html

GitHub:https://github.com/alibaba/Nacos

開發手冊:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

Nacos,全稱 Dynamic Naming and Configuration Service,Nacos = Eureka+Config +Bus,能夠替代 Eureka 做服務註冊中心和 Config 做服務配置中心。

各類註冊中心比較

服務註冊與發現框架 CAP模型 控制台管理 社區活躍度
Euraka AP 支持 低(2.x 閉源)
Zookeeper CP 不支持
Consul CP 支持
Nacos AP 支持

Nacos安裝與運行

  1. 準備 Java8 + Maven 環境
  2. 下載 Nocas:https://github.com/alibaba/nacos/releases
  3. 解壓安裝包,直接運行 bin 目錄下的 startup.cmd
startup.cmd -m standalone
  1. 命令運行成功後直接訪問:http://localhost:8848/nacos

Nacos服務註冊中心

基於Nacos的服務提供者

  1. 新建 module:cloudalibaba-provider-payment9001

  2. 改 POM

    • 修改父 POM,添加以下依賴
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.1.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    
    • 本模塊 POM
    <dependencies>
            <!--SpringCloud ailibaba nacos -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <!-- SpringBoot整合Web組件 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--日常通用jar包配置-->
            <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>
    
  3. 寫 YML

server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主啟動
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001
{
    public static void main(String[] args) {
            SpringApplication.run(PaymentMain9001.class, args);
    }
}
  1. 業務類
@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id)
    {
        return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
    }
}
  1. 測試

基於Nacos的服務消費者

  1. 根據 cloudalibaba-provider-payment9001 新建 cloudalibaba-provider-payment9002 演示負載均衡。
  2. 新建 module:cloudalibaba-consumer-nacos-order83
  3. 改 POM
<dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.xiaobai.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web組件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <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>
  1. 寫 YML
server:
  port: 83


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848


#消費者將要去訪問的微服務名稱(註冊成功進nacos的微服務提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider 
  1. 主啟動
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderNacosMain83.class,args);
    }
} 
  1. 業務類

    • config
    @Configuration
    public class ApplicationContextBean
    {
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate()
        {
            return new RestTemplate();
        }
    }
    
    • OrderNacosController
    @RestController
    public class OrderNacosController
    {
        @Resource
        private RestTemplate restTemplate;
    
        @Value("${service-url.nacos-user-service}")
        private String serverURL;
    
        @GetMapping("/consumer/payment/nacos/{id}")
        public String paymentInfo(@PathVariable("id") Long id)
        {
            return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
        }
    }
    
  2. 測試

為什麼 Nocas 支持負載輪詢? Nocas 中內置了 Ribbon !

image-20220822222110638

服務註冊中心對比

Nocas 全景圖

image-20220822222303786

Nacos與其他註冊中心特性對比

Nacos Euraka Consul CoreDNS ZooKeeper
一致性協議 CP + AP AP CP / CP
健康檢查 TCP/HTTP/MySQL/Client Beat Client Beat TCP/HTTP/GRPC/Cmd / Client Beat
負載均衡 權重/DSL/metadata/CMDB Ribbon Fabio RR /
雪崩保護 支持 支持 不支持 不支持 不支持
自動註銷 支持 支持 不支持 不支持 不支持
訪問協議 HTTP/DNS/UDP HTTP HTTP/DNS DNS TCP
監聽支持 支持 支持 支持 不支持 支持
多數據中心 支持 支持 支持 不支持 不支持
跨註冊中心 支持 不支持 支持 不支持 不支持
SpringCloud集成 支持 不支持 不支持 不支持 支持
Dubbon集成 支持 不支持 不支持 不支持 支持
K8s集成 支持 不支持 支持 支持 不支持

Nacos 服務發現實例模型

Nacos 支持AP和CP模式的切換

C 是所有節點在同一時間看到的數據是一致的;而 A 的定義是所有的請求都會收到響應。

何時選擇使用何種模式?

一般來說,如果不需要存儲服務級別的信息且服務實例是通過nacos-client註冊,並能夠保持心跳上報,那麼就可以選擇AP模式。當前主流的服務如 Spring cloud 和 Dubbo 服務,都適用於AP模式,AP模式為了服務的可能性而減弱了一致性,因此AP模式下只支持註冊臨時實例。

如果需要在服務級別編輯或者存儲配置信息,那麼 CP 是必須,K8S服務和DNS服務則適用於CP模式。
CP模式下則支持註冊持久化實例,此時則是以 Raft 協議為集群運行模式,該模式下註冊實例之前必須先註冊服務,如果服務不存在,則會返回錯誤。

curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

Nacos服務配置中心

基礎配置

  1. 新建 module:cloudalibaba-config-nacos-client3377
  2. 改 POM
<dependencies>
        <!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web + actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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>
  1. 寫 YML

    • bootstrap
    # nacos配置
    server:
      port: 3377
    
    spring:
      application:
        name: nacos-config-client
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #Nacos服務註冊中心地址
          config:
            server-addr: localhost:8848 #Nacos作為配置中心地址
            file-extension: yaml #指定yaml格式的配置
     
     
    # ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
    
    • application
    spring:
      profiles:
        active: dev # 表示開發環境
    
  2. 主啟動

@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377
{
    public static void main(String[] args) {
            SpringApplication.run(NacosConfigClientMain3377.class, args);
    }
}
  1. 業務類

    • controller
    @RestController //通過Spring Cloud原生註解@RefreshScope實現配置自動更新
    @RefreshScope //在控制器類加入@RefreshScope註解使當前類下的配置支持Nacos的動態刷新功能。
    public class ConfigClientController
    {
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping("/config/info")
        public String getConfigInfo() {
            return configInfo;
        }
    }
    
  2. 在 Nacos 中添加配置信息

    Nacos中的匹配規則:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

    設置DataId:\({spring.application.name}-\){spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

    • prefix 預設為 spring.application.name 的值;
    • spring.profile.active 即為當前環境對應的 profile,可以通過配置項 spring.profile.active 來配置;
    • file-exetension 為配置內容的數據格式,可以通過配置項 spring.cloud.nacos.config.file-extension 來配置

    Nacos 會記錄配置文件的歷史版本預設保留30天,此外還有一鍵回滾功能,回滾操作將會觸發配置更新。

image-20220822225618049

  1. 測試
    • 啟動前需要在nacos客戶端-配置管理-配置管理欄目下有對應的yaml配置文件;
    • 運行cloud-config-nacos-client3377的主啟動類;
    • 調用介面查看配置信息:http://localhost:3377/config/info
    • 修改下 Nacos 中的yaml配置文件,再次調用查看配置的介面,就會發現配置已經刷新

分類配置

多環境多項目管理中面臨的問題:

  1. 實際開發中,通常一個系統會準備 dev開發環境、test測試環境、prod生產環境。如何保證指定環境啟動時服務能正確讀取到Nacos上相應環境的配置文件呢?
  2. 一個大型分散式微服務系統會有很多微服務子項目,每個微服務項目又都會有相應的開發環境、測試環境、預發環境、正式環境......
    那怎麼對這些微服務配置進行管理呢?

Nacos 的圖形化管理界面

image-20220828193156061

Namespace+Group+Data ID三者關係

image-20220828193307419

預設情況:Namespace=public,Group=DEFAULT_GROUP, 預設Cluster是DEFAULT

Nacos 預設的命名空間是 public,Namespace 主要用來實現隔離。比方說我們現在有三個環境:開發、測試、生產環境,我們就可以創建三個Namespace,不同的Namespace之間是隔離的。

Group 預設是 DEFAULT_GROUP,Group 可以把不同的微服務劃分到同一個分組裡面去。

Service 就是微服務;一個Service可以包含多個Cluster(集群),Nacos 預設 Cluster 是 DEFAULT,Cluster 是對指定微服務的一個虛擬劃分。比方說為了容災,將 Service 微服務分別部署在了杭州機房和廣州機房,這時就可以給杭州機房的 Service 微服務起一個集群名稱(HZ),給廣州機房的Service微服務起一個集群名稱(GZ),還可以儘量讓同一個機房的微服務互相調用,以提升性能。

最後是 Instance,就是微服務的實例。

三種方案載入配置

  • DataID方案:指定spring.profile.active和配置文件的DataID來使不同環境下讀取不同的配置。

    1. 新建 dev 配置 DataID

    image-20220828194145448

    1. 同上,新建 test 配置 DataID
    2. 通過spring.profile.active屬性就能進行多環境下配置文件的讀取

    image-20220828194351544

    1. 測試,訪問:http://localhost:3377/config/info,返回配置內容
  • Group方案:通過Group實現環境區分

    1. 新建 Group,在 nacos 圖形界面控制臺上面新建配置文件DataID

    image-20220828194558137

    1. 在config下增加一條group的配置即可。可配置為 DEV_GROUP 或 TEST_GROUP

    image-20220828195710576

    1. 測試,訪問:http://localhost:3377/config/info,返回配置內容
  • Namespace方案

    1. 新建dev/test的Namespace

    image-20220828202442040

    1. 回到服務管理-服務列表查看

    image-20220828202510990

    1. 按照功能變數名稱配置填寫

    image-20220828202544924

    1. 修改 YML

      • bootstrap:config 添加 namespace 配置
      config:
              server-addr: localhost:8848 #Nacos作為配置中心地址
              file-extension: yaml #這裡我們獲取的yaml格式的配置
              namespace: 5da1dccc-ee26-49e0-b8e5-7d9559b95ab0
              #group: DEV_GROUP
              group: TEST_GROUP
      
      • application
      # Nacos註冊配置,application.yml
      spring:
        profiles:
          #active: test
          active: dev
          #active: info
      
    2. 測試,訪問:http://localhost:3377/config/info,返回配置內容

Nacos集群和持久化配置

官網說明

官方文檔:https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html

image-20220828211246075

預設Nacos使用嵌入式資料庫實現數據的存儲。所以,如果啟動多個預設配置下的Nacos節點,數據存儲是存在一致性問題的。
為瞭解決這個問題,Nacos採用了集中式存儲的方式來支持集群化部署,目前只支持MySQL的存儲。

image-20220828211542707

image-20220828211638243

查看官網文檔說明:https://nacos.io/zh-cn/docs/deployment.html

Nacos持久化配置

Nacos預設自帶的是嵌入式資料庫derby,說明:https://github.com/alibaba/nacos/blob/develop/config/pom.xml

切換配置 MySQL 步驟

  1. 新建 nacos 資料庫,在 nacos-server-1.1.4\nacos\conf 目錄下找到 sql 腳本,執行:
create database nacos;
use nacos;
source D:\Devware\nacos-server-2.1.0-BETA\conf\nacos-mysql.sql
  1. nacos-server-1.1.4\nacos\conf 目錄下找到 application.properties,修改資料庫配置
#*************** 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://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root
  1. 啟動Nacos,可以看到是個全新的空記錄界面,以前是記錄進derby

Linux版Nacos+MySQL、生產環境配置

  1. 環境準備

    tar -xzvf /opt/ nacos-server-1.1.4.tar.gz
    
  2. 集群配置

    • 新建 nacos 資料庫,將 nacos 安裝目錄里的 nacos-mysql.sql 導入到 mysql 資料庫中
    create database nacos;
    use nacos;
    source /opt/nacos/confnacos-mysql.sql
    
    • 修改 application.properties 配置
    cp application.properties.example application.properties
    vim application.properties
    

    image-20220830214401415

    • Linux伺服器上nacos的集群配置 cluster.conf
    cp cluster.conf.example cluster.conf
    vim cluster.conf
    

    image-20220901221836125

    • 編輯Nacos的啟動腳本 startup.sh,使它能夠接受不同的啟動埠
    cd /opt/nacos/bin
    vim startup.sh
    

    image-20220830215410645

    image-20220902002128610

    #執行方式
    ./startup.sh -p 3333
    ./startup.sh -p 4444
    
    • Nginx的配置,由它作為負載均衡器
    vim /usr/local/nginx/conf
    

    配置內容

    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;
    }
    ......
    

    啟動 nginx,執行: ./nginx -C /usr/local/nginx/conf/nginx.conf

  3. 測試

    • 修改 cloudablibaba-provider-payment9002 yml
    server-addr: 192.168.111.144:1111
    
    • 微服務 cloudalibaba-provider-payment9002 啟動,註冊進 nacos 集群

    image-20220830220420634

Sentinel實現熔斷與限流

Sentinel簡介

GitHub:https://github.com/alibaba/Sentinel

Sentinel 是一款功能強大的流量控制組件,以 flow 為突破點,覆蓋流量控制、併發限制、斷路、自適應系統保護等多個領域,保障微服務的可靠性。

image-20220824195439848

使用手冊:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

Sentinel安裝

Sentinel 分為兩個部分:

  • 核心庫(Uava客戶端):不依賴任何框架/庫,能夠運行於所有ava運行時環境,同時對 Dubbo/Spring Cloud 等框架也有較好的支特。
  • 控制台(Dashboard):基於Spring Boot開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。
  1. 下載:https://github.com/alibaba/Sentinel/releases
  2. 保證 Java8 環境且 8080 埠不被占用,運行 java -jar sentinel-dashboard-1.7.0.jar
  3. 訪問sentinel管理界面:http://localhost:8080 ,登錄賬號密碼均為 sentinel

初始化工程

  1. 新建 module,cloudalibaba-sentinel-service8401
  2. 改 POM
<dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 後續做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web組件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </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>
  1. 寫 YML
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服務註冊中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #預設8719埠,假如被占用會自動從8719開始依次+1掃描,直至找到未被占用的埠
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主啟動
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
  1. controller
@RestController
@Log4j2
public class FlowLimitController
{

    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        return "------testB";
    }
}
  1. 測試

image-20220824201256133

Sentinel 採用的懶載入方式,只有在微服務被訪問之後 Sentienl 才進行監測。

流控規則

image-20220824201540069

  • 資源名:唯一名稱,預設請求路徑
  • 針對來源:Sentinel可以針對調用者進行限流,填寫微服務名,預設default(不區分來源)
  • 調值類型單機闊值:
    • QPS(每秒鐘的請求數量):當調用該 API 的 QPS 達到閾值的時候,進行限流
    • 線程數:當調用該p的線程數達到闊值的時候,進行限流
  • 是否集群:不需要集群
  • 流控模式:
    • 直接:API 達到限流條件時,直接限流
    • 關聯:當關聯的資源達到閾值時,就限流自己
  • 鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進來的流量,如果達到城值,就進行限流)【 API 級別的針對來源】
  • 流控效果:
    • 快速失敗:直接失敗,拋異常
    • warm Up:根據 codeFactor (冷載入因數,預設3) 的值,從闊值/codeFactor,經過預熱時長,才達到設置的QPS闊值
    • 排隊等待:勻速排隊,讓請求以勻速的速度通過,閾值類型必須設置為QPS,否則無效

流量模式

  • 直接模式(預設):直接->快速失敗

image-20220824205931469

表示1秒鐘內查詢1次就是OK,若超過次數1,就直接-快速失敗,報預設錯誤。

​ 快速點擊訪問:http://localhost:8401/testA,結果 Blocked by Sentinel (flow limiting)

  • 關聯模式:當關聯的資源達到閾值時,就限流自己

image-20220828111029179

postman 模擬併發密集訪問 testB,大批量線程高併發訪問B,導致A失效了

image-20220824210538330

  • 鏈路模式:多個請求調用了同一個微服務

流控效果

  • 預設的流控處理:直接->快速失敗

    源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

  • 預熱:閾值除以coldFactor(預設值為3),經過預熱時長後才會達到閾值

    image-20220824211142224

文檔:https://github.com/alibaba/Sentinel/wiki/流量控制

源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

例如:系統初始化的閥值為10 / 3 約等於3,即閥值剛開始為3;然後過了5秒後閥值才慢慢升高恢復到10

image-20220824211315336

測試:多次點擊:http://localhost:8401/testB,剛開始不行,後續慢慢OK

運用場景如:秒殺系統在開啟的瞬間,會有很多流量上來,很有可能把系統打死,預熱方式就是把為了保護系統,可慢慢的把流量放進來,慢慢的把閥值增長到設置的閥值。

  • 等待排隊:勻速排隊,讓請求以均勻的速度通過,閥值類型必須設成QPS,否則無效。

官網:https://github.com/alibaba/Sentinel/wiki/流量控制

源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

測試

image-20220824211757086

降級規則

官網:https://github.com/alibaba/Sentinel/wiki/熔斷降級

Sentinel 熔斷降級會在調用鏈路中某個資源出現不穩定狀態時(例如調用超時或異常比例升高),對這個資源的調用進行限制,
讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤。

當資源被降級後,在接下來的降級時間視窗之內,對該資源的調用都自動熔斷(預設行為是拋出 DegradeException)。

註意:Sentinel的斷路器是沒有半開狀態的

image-20220824212037295

降級策略實戰

  1. RT(平均響應時間,秒級):平均響應時間 超出閾值在時間視窗內通過的請求>=5,兩個條件同時滿足後觸發降級。視窗期過後關閉斷路器,RT最大4900(更大的需要通過-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)。

    • 代碼
    @GetMapping("/testD")
    public String testD()
    {
        //暫停幾秒鐘線程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        log.info("testD 測試RT");
        return "------testD";
    }
    
    • 配置

    image-20220824212726686

    • jmeter壓測

    image-20220824212803736

    • 結論

      永遠一秒鐘打進來10個線程(大於5個了)調用testD,我們希望200毫秒處理完本次任務,如果超過200毫秒還沒處理完,在未來1秒鐘的時間視窗內,斷路器打開(保險絲跳閘)微服務不可用,保險絲跳閘斷電了。後續我停止jmeter,沒有這麼大的訪問量了,斷路器關閉(保險絲恢復),微服務恢復OK。

  2. 異常比列(秒級):QPS >= 5 且異常比例(秒級統計)超過閾值時,觸發降級;時間視窗結束後,關閉降級。

    • 代碼
    @GetMapping("/testD")
    public String testD()
    {
        log.info("testD 測試RT");
        int age = 10/0;
        return "------testD";
    }
    
    • 配置

    image-20220824213006765

    • jmeter壓測

    image-20220824213040944

    • 結論

      開啟jmeter後,直接高併發發送請求,多次調用達到我們的配置條件了。斷路器開啟(保險絲跳閘),微服務不可用了,不再報錯error而是服務降級了。

  3. 異常數(分鐘級):異常數(分鐘統計)超過閾值時,觸發降級;時間視窗結束後,關閉降級。

    • 代碼
    @GetMapping("/testE")
    public String testE()
    {
        log.info("testE 測試異常比例");
        int age = 10/0;
        return "------testE 測試異常比例";
    }
    
    • 配置

    image-20220824214033195

    http://localhost:8401/testE,第一次訪問絕對報錯,因為除數不能為零,我們看到error視窗,但是達到5次報錯後,進入熔斷後降級。

    • jmeter壓測

    image-20220824214151002

熱點key限流

官網:https://github.com/alibaba/Sentinel/wiki/熱點參數限流

熱點即經常訪問的數據,很多時候我們希望統計或者限制某個熱點數據中訪問頻次最高的TopN數據,並對其訪問進行限流或者其它操作。

@SentinelResource

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1, 
                         @RequestParam(value = "p2",required = false) String p2){
    return "------testHotKey";
}
public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
{
    return "-----dealHandler_testHotKey";
}

image-20220824214631462

限流模式只支持QPS模式,固定寫死了(這才叫熱點)。@SentinelResource註解的方法參數索引,0代表第一個參數,1代表第二個參數,以此類推單機閥值以及統計視窗時長表示在此視窗時間超過閥值就限流。上面的抓圖就是第一個參數有值的話,1秒的QPS為1,超過就限流,限流後調用dealHandler_testHotKey支持方法。

測試:

參數例外項

我們期望p1參數當它是某個特殊值時,它的限流值和平時不一樣。假如當p1的值等於5時,它的閾值可以達到200

image-20220824215205219

註意:熱點參數的註意點,參數必須是基本類型或者String

系統規則

官網:https://github.com/alibaba/Sentinel/wiki/系統自適應限流

系統保護規則是從應用級別的入口流量進行控制,從單台機器的Iod、CPU使用率、平均RT、入口QPS和併發線程數等幾個維度監控應用指標,讓系統儘可能跑在最大吞吐量的同時保證系統整體的穩定性。

系統保護規則是應用整體維度的,而不是資源維度的,並且僅對入口流量生效。入口流量指的是進入應用的流量(EntryType.IW),比如Web服務或Dubbo服務端接收的請求,都屬於入口流量。

系統規則支持以下的模式:

  • Load自適應(僅對Linux/Unix-ike機器生效):系統的load1作為啟髮指標,進行自適應系統保護。當系統Ioād1超過設定的啟發值,且系統當前的併發線程數超過估算的系統容量時才會觸發系統保護(BBR階段)。系統容量由系統的maxQps*mit估算得出。設定參考值一般是CPU cores 2.5。
  • CPU usage(1.5.0+版本):當系統CPU使用率超過閾值即觸發系統保護(取值範圍0.0-1.0),比較靈敏。
  • 平均T:當單台機器上所有入口流量的平均T達到闊值即觸發系統保護,單位是毫秒。
  • 併發線程數:當單台機器上所有入口流量的併發線程數達到闊值即觸發系統保護。
  • 入口QPS:當單台機器上所有入口流量的QPS達到閾值即觸發系統保護。

@SentinelResource

按資源名限流+後續處理

啟動 Nacos,執行:startup.cmd -m standalone,訪問:http://localhost:8848/nacos/#/login 測試

啟動 Sentinel,執行:java -jar sentinel-dashboard-1.7.0.jar

修改 cloudablibaba-sentinel-service8401

  1. 改 POM,添加以依賴
<dependencies>
    <dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
        <groupId>com.xiaobai.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>
  1. controller,新建 RateLimitController
@RestController
public class RateLimitController
{
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按資源名稱限流測試OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服務不可用");
    }
}
  1. 流控規則配置

    • 配置步驟

    image-20220827225436433

    • 圖形配置與代碼關係

    image-20220827225502196

  2. 測試,啟動 8401,訪問:http://localhost:8401/byResource,間隔時間大於等於 1s 訪問成功,間隔時間小於 1s 返回自定義的限流處理信息。

遺留問題: 當 8401 服務關閉,Sentinel 流量控制規則消失。

按Url地址限流+後續處理

  1. 修改 controller,添加如下方法
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
    return new CommonResult(200,"按url限流測試OK",new Payment(2020L,"serial002"));
}
  1. 初步測試,訪問:http://localhost:8401/rateLimit/byUrl,訪問成功
  2. 配置流控規則

image-20220827225918925

  1. 二次測試,連續訪問:http://localhost:8401/rateLimit/byUrl,返回 Sentinel 自帶的限流處理結果

上述兜底方案面臨的問題:

  1. 系統預設的,沒有體現我們自己的業務要求。
  2. 依照現有條件,我們自定義的處理方法又和業務代碼耦合在一塊,不直觀。
  3. 每個業務方法都添加一個兜底的,那代碼膨脹加劇。
  4. 全局統一的處理方法沒有體現。

客戶自定義限流處理邏輯

  1. 創建 CustomerBlockHandler 類用於自定義限流處理邏輯
public class CustomerBlockHandler
{
    public static CommonResult handleException(BlockException exception){
        return new CommonResult(2020,"自定義的限流處理信息......CustomerBlockHandler-----1");
    }
    
    public static CommonResult handleException2(BlockException exception){
        return new CommonResult(2020,"自定義的限流處理信息......CustomerBlockHandler------2");
    }
}
  1. RateLimitController 添加自定義限流處理邏輯
   /**
     * 自定義通用的限流處理邏輯,
     * blockHandlerClass = CustomerBlockHandler.class
     * blockHandler = handleException2
     * 上述配置:找CustomerBlockHandler類里的handleException2方法進行兜底處理
     */
    /**
     * 自定義通用的限流處理邏輯
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客戶自定義限流處理邏輯");
    }
  1. 啟動微服務後調用:http://localhost:8401/rateLimit/customerBlockHandler
  2. Sentinel 控制台添加配置

image-20220827230635488

  1. 再次調用:http://localhost:8401/rateLimit/customerBlockHandler

服務熔斷

Ribbon系列

服務提供者9003/9004

  1. 新建cloudalibaba-provider-payment9003/9004
  2. 改 POM
<dependencies>
    <!--SpringCloud ailibaba nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
        <groupId>com.xiaobai.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!-- SpringBoot整合Web組件 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--日常通用jar包配置-->
    <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>
  1. 寫 YML(記得該埠號)
server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主啟動
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003
{
    public static void main(String[] args) {
            SpringApplication.run(PaymentMain9003.class, args);
    }
}
  1. 業務類
@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long,Payment> hashMap = new HashMap<>();
    static
    {
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
    {
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }
}
  1. 測試,訪問:http://localhost:9003/paymentSQL/1

服務消費者84

  1. 新建 cloudalibaba-consumer-nacos-order84
  2. 改 POM
<dependencies>
    <!--SpringCloud ailibaba nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>com.xiaobai.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!-- SpringBoot整合Web組件 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--日常通用jar包配置-->
    <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>
  1. 寫 YML
server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #預設8719埠,假如被占用會自動從8719開始依次+1掃描,直至找到未被占用的埠
        port: 8719

#消費者將要去訪問的微服務名稱(註冊成功進nacos的微服務提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider
  1. 主啟動
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84
{
    public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain84.class, args);
    }
}
  1. 配置類
@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
  1. 業務類
@RestController
@Slf4j
public class CircleBreakerController
{
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback") 
     public CommonResult<Payment> fallback(@PathVariable Long id)
    {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近在開發時,遇到相同的頁面,很多函數和佈局也大差不多,所以向在路由註冊時就給他們分配不同的路由,通過一些判斷走不同的邏輯獲取數據。 ...
  • /** * 替換字元串,預設替換 ""。傳遞 regExps,一個正則表達式數組。 * * @param source 被修剪的字元串 * @param regExps 正則表達式,找到匹配的字元串,然後替換掉 * @param replacement 不傳遞,預設被替換的字元串是 ""。傳遞的數組 ...
  • 作為後端程式員,瞭解和掌握一些前端知識也是必不可少的,本章就和大家分享Vue的一些基礎知識,希望能夠對Vue小白有所幫助。話不多說,下麵我們直接進入主題。 一、Vue簡介 Vue簡介:1、JavaScript框架;2、簡化Dom操作;3、響應式的數據驅動(頁面是由數據來生成的,當數據改變以後頁面會同 ...
  • JQuery04 6.jQuery的DOM操作02 6.9常用遍歷節點方法 取得匹配元素的所有子元素組成的集合:children(),該方法只考慮子元素而不考慮任何後代元素 取得匹配元素後面的同輩元素的集合:next()/nextAll() 如果是next方法,就是拿到指定元素後面的一個元素,如果是 ...
  • 在 javascript 中內置了一個 Date 對象,可用於實現一些日期和時間的操作。 本文整理 js 日期對象的詳細功能,使用 js 日期對象獲取具體日期、昨天、今天、明天、每月天數、時間戳等,以及常用的日期時間處理方法。 ...
  • 在如今,很多網頁已經可以手動切換明亮模式和黑暗模式,網頁的主題切換已經成為了一個常用的需求,因此,本文將從常見框架的處理方式總結一些相關的操作,並探究其本質。 ...
  • Nginx (Engine X)是一個輕量級的Web伺服器 、反向代理伺服器及電子郵件(IMAP/POP3)代理伺服器、高性能的HTTP伺服器,它以高穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名。 ...
  • 如果你接手了別人的代碼工程,卻發現對方使用的 python 版本或者依賴庫都和你的環境不相容時,怎麼辦?打算卸掉自己原來的那一套環境再重來嗎?真麻煩! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...