<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      微服務(wù):解決復(fù)雜業(yè)務(wù)的妙方

      1 微服務(wù)介紹

      1)什么是微服務(wù)

      ? 微服務(wù)(Microservices)是一種軟件架構(gòu)風(fēng)格,它將一個(gè)大型應(yīng)用程序拆分成許多較小的、松散耦合的、獨(dú)立運(yùn)行的服務(wù)。這些服務(wù)通常圍繞特定功能或業(yè)務(wù)領(lǐng)域組織,可以獨(dú)立開發(fā)、部署、擴(kuò)展和更新。微服務(wù)之間通過輕量級(jí)的通信協(xié)議(如HTTP/REST、消息隊(duì)列等)相互協(xié)作。

      ? 采用微服務(wù)架構(gòu)的優(yōu)點(diǎn)包括:

      1. 可擴(kuò)展性:每個(gè)服務(wù)都可以根據(jù)需求單獨(dú)進(jìn)行擴(kuò)展。
      2. 敏捷開發(fā):團(tuán)隊(duì)可以獨(dú)立開發(fā)和部署各自負(fù)責(zé)的服務(wù),加快開發(fā)速度。
      3. 容錯(cuò)性:當(dāng)某個(gè)服務(wù)出現(xiàn)問題時(shí),不會(huì)影響整個(gè)系統(tǒng)的正常運(yùn)行。
      4. 技術(shù)棧靈活性:可以針對(duì)具體任務(wù)選擇最佳技術(shù)和編程語言,而不受整體約束。

      ? 然而,微服務(wù)架構(gòu)也存在一些挑戰(zhàn),例如網(wǎng)絡(luò)延遲、數(shù)據(jù)一致性和服務(wù)間通信復(fù)雜性等問題。在實(shí)踐中,需要根據(jù)項(xiàng)目需求審慎權(quán)衡是否采用微服務(wù)架構(gòu)。

      2)什么是分布式

      ? 分布式(Distributed)是指一個(gè)系統(tǒng)的組件分散在不同的網(wǎng)絡(luò)節(jié)點(diǎn)上,這些組件協(xié)同工作以完成整個(gè)系統(tǒng)的任務(wù)。分布式系統(tǒng)可以提高可擴(kuò)展性、容錯(cuò)能力和資源利用率。由于組件在物理上分隔,分布式系統(tǒng)需要處理諸如數(shù)據(jù)一致性、通信延遲和故障恢復(fù)等問題。

      ? 微服務(wù)是一種特定的分布式系統(tǒng)架構(gòu)風(fēng)格,它強(qiáng)調(diào)將應(yīng)用程序拆分為許多較小的、松散耦合的、獨(dú)立運(yùn)行的服務(wù)。這些服務(wù)圍繞特定功能或業(yè)務(wù)領(lǐng)域組織,并通過輕量級(jí)通信協(xié)議進(jìn)行交互。

      3)分布式和微服務(wù)的區(qū)別:

      1. 范圍:分布式是更廣泛的概念,涵蓋了各種類型的分布式系統(tǒng);而微服務(wù)是一種具體的分布式架構(gòu)風(fēng)格。
      2. 設(shè)計(jì)原則:微服務(wù)強(qiáng)調(diào)每個(gè)服務(wù)的獨(dú)立性、職責(zé)單一、松耦合和自治性,這使得微服務(wù)更容易適應(yīng)不斷變化的需求。而其他類型的分布式系統(tǒng)可能沒有這些特性。
      3. 技術(shù)實(shí)現(xiàn):雖然兩者都涉及跨多個(gè)節(jié)點(diǎn)的組件,但實(shí)現(xiàn)方式可能有所不同。微服務(wù)通常使用HTTP/REST、消息隊(duì)列等輕量級(jí)通信協(xié)議,而其他分布式系統(tǒng)可能使用RPC、一致性算法等技術(shù)。

      ? 總之,微服務(wù)是分布式系統(tǒng)中的一種特殊類型。雖然它們?cè)诟拍钌嫌兄丿B,但它們?cè)谠O(shè)計(jì)原則和實(shí)現(xiàn)細(xì)節(jié)上有所不同。

      image

      2 springcloud介紹

      1)springcloud組件

      ? Spring Cloud是一個(gè)基于Spring Boot的微服務(wù)框架,旨在簡化分布式系統(tǒng)中的開發(fā)、部署和管理工作。它提供了一系列模塊和工具,可以幫助開發(fā)者快速搭建彈性、可擴(kuò)展且易于維護(hù)的微服務(wù)應(yīng)用。以下是一些常見的Spring Cloud組件:

      1. Spring Cloud Config:分布式配置中心,允許您在集中位置管理所有服務(wù)的配置,并實(shí)時(shí)更新。
      2. Spring Cloud Netflix Eureka:服務(wù)注冊(cè)與發(fā)現(xiàn)組件,提供了自動(dòng)化的服務(wù)注冊(cè)、注銷和查找功能,支持負(fù)載均衡。
      3. Spring Cloud Netflix Ribbon:客戶端負(fù)載均衡器,可以在調(diào)用其他服務(wù)時(shí)為請(qǐng)求選擇合適的實(shí)例,提高系統(tǒng)的可用性。
      4. Spring Cloud Netflix Hystrix:熔斷器和隔離組件,用于防止故障級(jí)聯(lián)和提供降級(jí)處理。
      5. Spring Cloud Netflix Zuul:API網(wǎng)關(guān), 責(zé)處理客戶端請(qǐng)求并將其轉(zhuǎn)發(fā)到適當(dāng)?shù)膬?nèi)部服務(wù) 。
      6. Spring Cloud Gateway:API網(wǎng)關(guān),負(fù)責(zé)轉(zhuǎn)發(fā)請(qǐng)求、聚合響應(yīng)、路由、認(rèn)證授權(quán)和限流等功能。
      7. Spring Cloud Sleuth 和 Zipkin:分布式追蹤組件,用于監(jiān)控和診斷跨服務(wù)的請(qǐng)求鏈路。
      8. Spring Cloud Stream:基于消息驅(qū)動(dòng)的微服務(wù)通信組件,支持異步處理和解耦服務(wù)間的通信。
      9. Spring Cloud Security:安全性模塊,提供了一些基本的安全措施,如認(rèn)證、授權(quán)和API保護(hù)等功能。
      10. Spring Cloud Bus:事件總線,用于實(shí)現(xiàn)服務(wù)間消息傳遞和廣播配置更新等功能。
      11. Spring Cloud OpenFeign:聲明式HTTP客戶端,簡化了RESTful服務(wù)之間的通信。

      ? 由于Netflix公司已經(jīng)停止了對(duì)Spring Cloud Netflix組件的維護(hù)和更新工作, 所以Netflix 相關(guān)的組件已經(jīng)目前已經(jīng)有對(duì)應(yīng)的替代組件:

      ? Eureka --> Nacos; Ribbon --> LoadBalancer; Zuul --> Gateway; Hystrix --> Sentinel

      2)springcloud alibaba

      ? Spring Cloud Alibaba 是一個(gè)基于 Spring Cloud 的微服務(wù)開發(fā)框架,它提供了與 Alibaba 相關(guān)組件(如 Nacos、Sentinel、RocketMQ 等)的集成。Spring Cloud Alibaba 旨在簡化開發(fā)者構(gòu)建分布式應(yīng)用的過程,并幫助實(shí)現(xiàn)高可用、彈性伸縮和快速故障恢復(fù)等目標(biāo)。

      主要功能包括:

      1. 服務(wù)注冊(cè)與發(fā)現(xiàn):Spring Cloud Alibaba 集成了阿里巴巴的 Nacos 作為服務(wù)注冊(cè)中心,支持針對(duì)各種場(chǎng)景的服務(wù)管理。
      2. 分布式配置管理:通過 Nacos 提供統(tǒng)一的配置管理服務(wù),實(shí)現(xiàn)配置的動(dòng)態(tài)更新和版本控制。
      3. 服務(wù)熔斷與限流:集成阿里巴巴的 Sentinel 組件,提供流量控制、熔斷降級(jí)和系統(tǒng)負(fù)載保護(hù)等功能,保證服務(wù)的穩(wěn)定性。
      4. 消息隊(duì)列:集成阿里巴巴的 RocketMQ,提供分布式消息隊(duì)列服務(wù),實(shí)現(xiàn)異步通信、解耦和削峰填谷等功能。
      5. 分布式事務(wù):通過 Seata 組件提供分布式事務(wù)處理能力,幫助解決微服務(wù)架構(gòu)下的數(shù)據(jù)一致性問題。
      6. 鏈路追蹤:集成阿里巴巴的 Arthas 和 SkyWalking,實(shí)現(xiàn)鏈路追蹤和性能監(jiān)控等功能。

      通過使用 Spring Cloud Alibaba,開發(fā)者可以更輕松地基于阿里巴巴的技術(shù)棧構(gòu)建微服務(wù)應(yīng)用,并充分利用其豐富的功能和穩(wěn)定性。

      3)版本對(duì)應(yīng)關(guān)系

      spring boot和spring cloud以及 spring cloud alibaba的版本對(duì)應(yīng)關(guān)系;

      Spring Cloud Alibaba Version Spring Cloud Version Spring Boot Version
      2.2.10-RC1* Spring Cloud Hoxton.SR12 2.3.12.RELEASE
      2.2.9.RELEASE Spring Cloud Hoxton.SR12 2.3.12.RELEASE
      2.2.8.RELEASE Spring Cloud Hoxton.SR12 2.3.12.RELEASE
      2.2.7.RELEASE Spring Cloud Hoxton.SR12 2.3.12.RELEASE
      2.2.6.RELEASE Spring Cloud Hoxton.SR9 2.3.2.RELEASE
      2.2.1.RELEASE Spring Cloud Hoxton.SR3 2.2.5.RELEASE
      2.2.0.RELEASE Spring Cloud Hoxton.RELEASE 2.2.X.RELEASE
      2.1.4.RELEASE Spring Cloud Greenwich.SR6 2.1.13.RELEASE
      2.1.2.RELEASE Spring Cloud Greenwich 2.1.X.RELEASE
      2.0.4.RELEASE(停止維護(hù),建議升級(jí)) Spring Cloud Finchley 2.0.X.RELEASE
      1.5.1.RELEASE(停止維護(hù),建議升級(jí)) Spring Cloud Edgware 1.5.X.RELEASE

      spring cloud alibaba組件之間的對(duì)應(yīng)關(guān)系

      Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Version Dubbo Version Seata Version
      2022.0.0.0-RC2 1.8.6 2.2.1 4.9.4 ~ 1.7.0-native-rc2
      2021.0.5.0 1.8.6 2.2.0 4.9.4 ~ 1.6.1
      2.2.10-RC1 1.8.6 2.2.0 4.9.4 ~ 1.6.1
      2022.0.0.0-RC1 1.8.6 2.2.1-RC 4.9.4 ~ 1.6.1
      2.2.9.RELEASE 1.8.5 2.1.0 4.9.4 ~ 1.5.2
      2021.0.4.0 1.8.5 2.0.4 4.9.4 ~ 1.5.2
      2.2.8.RELEASE 1.8.4 2.1.0 4.9.3 ~ 1.5.1
      2021.0.1.0 1.8.3 1.4.2 4.9.2 ~ 1.4.2
      2.2.7.RELEASE 1.8.1 2.0.3 4.6.1 2.7.13 1.3.0
      2.2.6.RELEASE 1.8.1 1.4.2 4.4.0 2.7.8 1.3.0
      2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE 1.8.0 1.4.1 4.4.0 2.7.8 1.3.0
      2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE 1.8.0 1.3.3 4.4.0 2.7.8 1.3.0
      2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE 1.7.1 1.2.1 4.4.0 2.7.6 1.2.0
      2.2.0.RELEASE 1.7.1 1.1.4 4.4.0 2.7.4.1 1.0.0
      2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE 1.7.0 1.1.4 4.4.0 2.7.3 0.9.0
      2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE 1.6.3 1.1.1 4.4.0 2.7.3 0.7.1

      3 服務(wù)注冊(cè)和發(fā)現(xiàn)

      ? 在 Java 微服務(wù)架構(gòu)中,服務(wù)注冊(cè)與發(fā)現(xiàn)是一種關(guān)鍵的設(shè)計(jì)模式,它允許各個(gè)微服務(wù)實(shí)例自動(dòng)注冊(cè)、發(fā)現(xiàn)其他服務(wù)和負(fù)載均衡。這樣做的優(yōu)勢(shì)主要包括:

      1. 簡化服務(wù)調(diào)用:服務(wù)間可以通過服務(wù)名而非硬編碼的 IP 地址或端口號(hào)進(jìn)行相互調(diào)用。

      2. 動(dòng)態(tài)伸縮:支持自動(dòng)添加或刪除服務(wù)實(shí)例,無需手動(dòng)維護(hù)服務(wù)列表。

      3. 負(fù)載均衡:根據(jù)某種策略(如輪詢或最少連接)將請(qǐng)求分發(fā)到多個(gè)服務(wù)實(shí)例,從而提高系統(tǒng)整體容錯(cuò)性和可用性。

      image

      在 Java 生態(tài)中,常見的服務(wù)注冊(cè)與發(fā)現(xiàn)解決方案有以下幾種:

      1. Eureka:Eureka 是 Netflix 開源的一款服務(wù)注冊(cè)與發(fā)現(xiàn)組件,它基于 RESTful API,具有較好的可擴(kuò)展性和容錯(cuò)能力。與 Spring Cloud 配合使用時(shí),只需簡單的配置即可實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn)功能。
      2. Consul:Consul 是由 HashiCorp 開發(fā)的一款服務(wù)網(wǎng)格解決方案,提供服務(wù)注冊(cè)與發(fā)現(xiàn)、配置管理和服務(wù)分段等功能。同樣可以與 Spring Cloud 集成,便于構(gòu)建微服務(wù)應(yīng)用。
      3. Nacos:阿里巴巴開源的 Nacos 提供了服務(wù)注冊(cè)與發(fā)現(xiàn)以及配置管理功能,可以與 Spring Cloud Alibaba 集成使用。Nacos 支持多種服務(wù)注冊(cè)方式(如域名、IP 等),并提供豐富的負(fù)載均衡策略和健康檢查機(jī)制。
      4. Zookeeper:Apache ZooKeeper 是一個(gè)分布式協(xié)調(diào)服務(wù),雖然它并非專為服務(wù)注冊(cè)與發(fā)現(xiàn)而設(shè)計(jì),但由于其強(qiáng)大的分布式一致性能力,被廣泛用于實(shí)現(xiàn)服務(wù)注冊(cè)與發(fā)現(xiàn)功能。通過 Curator 客戶端庫,可以方便地與 Spring Cloud 集成。

      1)nacos介紹

      ? Nacos(Naming and Configuration Service)是阿里巴巴開源的一款用于服務(wù)注冊(cè)與發(fā)現(xiàn)、配置管理的中間件。它具有易用性、高可用性和強(qiáng)大的功能,旨在幫助開發(fā)者構(gòu)建動(dòng)態(tài)、可擴(kuò)展的分布式系統(tǒng)。以下是 Nacos 的主要特點(diǎn)和功能:

      1. 服務(wù)注冊(cè)與發(fā)現(xiàn):Nacos 提供了一個(gè)基于 DNS 和 HTTP 的服務(wù)注冊(cè)與發(fā)現(xiàn)框架,支持多種服務(wù)注冊(cè)方式(如域名、IP 地址等),并提供豐富的負(fù)載均衡策略和健康檢查機(jī)制。

      2. 動(dòng)態(tài)配置管理:Nacos 支持配置信息的實(shí)時(shí)推送和更新,以滿足應(yīng)用程序在運(yùn)行過程中對(duì)配置數(shù)據(jù)的需求。通過其 UI 控制臺(tái),使用者可以輕松管理不同環(huán)境、集群和命名空間下的配置。

      3. 分組及分區(qū):Nacos 支持根據(jù)服務(wù)實(shí)例元數(shù)據(jù)進(jìn)行分組和分區(qū),從而實(shí)現(xiàn)精細(xì)化的服務(wù)治理。

      4. 高可用和容錯(cuò):Nacos 具有良好的高可用設(shè)計(jì),支持集群部署,保證在節(jié)點(diǎn)故障的情況下也能正常提供服務(wù)。此外,Nacos 還提供了臨時(shí)存儲(chǔ),以確保用戶在網(wǎng)絡(luò)狀況不佳的情況下仍然能夠訪問配置。

      5. 多環(huán)境支持:Nacos 支持多環(huán)境、多集群的管理,方便用戶在不同的場(chǎng)景下使用 Nacos。

      6. 易于集成:Nacos 可以輕松與其他 Java 微服務(wù)框架(如 Spring Cloud、Dubbo 等)集成。在 Spring Cloud Alibaba 體系下,只需簡單的配置就可以實(shí)現(xiàn) Nacos 與應(yīng)用程序的無縫對(duì)接。

      7. 社區(qū)活躍:作為阿里巴巴開源的項(xiàng)目,Nacos 擁有活躍的社區(qū)和豐富的文檔資源,方便開發(fā)者快速上手和入門。

      Nacos = Spring Cloud Eureka + Spring Cloud Config

      ?

      2)nacos基本運(yùn)行

      ?

      image

      Nacos 依賴 Java 環(huán)境來運(yùn)行。所以需要安裝jdk1.8+以及配置環(huán)境變量;

      2.1 nacos-server下載和啟動(dòng)

      ? 根據(jù)spring-cloud-alibaba中的版本說明, nacos我們下載使用2.1.0;

      ? 如果在github上下載太慢, 可以在gitee上下載源碼, 然后使用maven打包, 安裝; (maven需配置環(huán)境變量)

      mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
      

      ? 運(yùn)行nacos:

      ? 1) 使用cmd, 跳轉(zhuǎn)到nacos下的bin文件下,

      ? 2) 單機(jī)運(yùn)行指令: startup.cmd -m standalone

      image

      ? 3)nacos后臺(tái)管理: http://127.0.0.1:8848/nacos/,

      ? 輸入賬號(hào): nacos 密碼: nacos

      image

      ?

      image

      2.2 創(chuàng)建聚合項(xiàng)目

      創(chuàng)建聚合項(xiàng)目進(jìn)行依賴的版本管理;

      pom.xml文件
      
      <packaging>pom</packaging>
      
      	<properties>
      		<maven.compiler.source>8</maven.compiler.source>
      		<maven.compiler.target>8</maven.compiler.target>
      		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      		<spring-boot-version>2.3.12.RELEASE</spring-boot-version>
      		<spring-cloud-version>Hoxton.SR12</spring-cloud-version>
      		<spring-cloud-alibaba-version>2.2.9.RELEASE</spring-cloud-alibaba-version>
      	</properties>
      	<dependencyManagement>
              <dependencies>
                  <dependency>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-dependencies</artifactId>
                      <version>${spring-boot-version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
                  <dependency>
                      <groupId>org.springframework.cloud</groupId>
                      <artifactId>spring-cloud-dependencies</artifactId>
                      <version>${spring-cloud-version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
                  <dependency>
                      <groupId>com.alibaba.cloud</groupId>
                      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                      <version>${spring-cloud-alibaba-version}</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>
              </dependencies>
          </dependencyManagement>
      

      2.3 訂單服務(wù)

      POM文件

      	<parent>
      		<groupId>com.qs.cloud</groupId>
      		<artifactId>cloud-117</artifactId>
      		<version>1.0-SNAPSHOT</version>
      	</parent>
      	<artifactId>order-server</artifactId>
      	<properties>
      		<maven.compiler.source>8</maven.compiler.source>
      		<maven.compiler.target>8</maven.compiler.target>
      		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      	</properties>
      	<dependencies>
      		<dependency>
      			<groupId>org.springframework.boot</groupId>
      			<artifactId>spring-boot-starter-web</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>
      	</dependencies>
      

      啟動(dòng)類:

      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      public class OrderApp {
          public static void main(String[] args) {
              SpringApplication.run(OrderApp.class);
          }
      }
      

      配置文件:

      spring.application.name=order-server
      server.port=9001
      spring.cloud.nacos.discovery.server-addr=http://127.0.0.1:8848
      

      feign接口:

      @FeignClient("stock-server")
      public interface StockFeign {
          @GetMapping("index")
          String index();
      }
      

      controller:

      @RestController
      public class OrderController {
          @Autowired
          StockFeign stockFeign;
          @GetMapping("/index")
          public String index(){
              String index = stockFeign.index();
              return index;
          }
      }
      

      4)配置中心

      nacos除了作為注冊(cè)中心以外, 同時(shí)也可以作為配置中心來使用;

      1)配置中心的基本使用

      導(dǎo)入依賴:

      <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
      </dependency>
      

      創(chuàng)建項(xiàng)目的bootstrap.properties文件

      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
      spring.application.name=order-server
      

      在nacos配置中心發(fā)布改項(xiàng)目的配置文件:

      image

      dataId 的完整格式如下:

      服務(wù)名稱-運(yùn)行環(huán)境.后綴名
      
      • 服務(wù)名稱: 默認(rèn)為所屬項(xiàng)目配置spring.application.name 的值(即:order-server)
      • 運(yùn)行環(huán)境: 即為當(dāng)前環(huán)境對(duì)應(yīng)的 profile,配置文件中spring.profiles.active設(shè)置的值:當(dāng) 這個(gè)值為空時(shí),對(duì)應(yīng)的連接符 - 也將不存
      • 后綴名: 為配置內(nèi)容的數(shù)據(jù)格式,可以在項(xiàng)目配置文件中通過配置項(xiàng) spring.cloud.nacos.config.file-extension 來配置。目前只支持 propertiesyaml 類型。

      總結(jié):配置所屬工程的spring.application.name的值 + "." + properties/yml

      2)使用命名空間

      Nacos配置中心的命名空間,它用來隔離不同的配置信息,類似于不同的環(huán)境或應(yīng)用程序之間的劃分。通過使用不同的命名空間,可以在不同的場(chǎng)景下管理和控制配置信息,實(shí)現(xiàn)配置的靈活性和可維護(hù)性。每個(gè)命名空間都有自己獨(dú)立的配置集合,可以設(shè)置不同的權(quán)限和訪問控制,方便團(tuán)隊(duì)協(xié)作和管理配置的版本控制。

      image

      nacos配置中心新建配置文件:order-server-dev.yml

      image

      myName: 趙六
      server:
          port: 9001
      spring:
          cloud:
              nacos:
                  discovery:
                      server-addr: 127.0.0.1:8848
      

      項(xiàng)目bootstrap.properties中指定命名空間和運(yùn)行環(huán)境:

      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
      spring.application.name=order-server
      spring.cloud.nacos.config.file-extension=yml
      spring.cloud.nacos.config.namespace=b49888df-e80a-4e7b-a4eb-c128a41c16e6
      spring.profiles.active=dev
      

      以上是專門為dev運(yùn)行環(huán)境創(chuàng)建命名空間和配置文件, 也可以為其他prod,test等生產(chǎn)環(huán)境創(chuàng)建命名空間.

      3)使用組名

      分組(Group)用于對(duì)配置進(jìn)行邏輯上的分類和管理。通過將不同項(xiàng)目的配置歸屬到不同的分組中,可以方便地對(duì)配置進(jìn)行組織、查找和管理.

      nacos中新建配置文件:

      image

      項(xiàng)目的bootstrap.properties文件中加入組的配置:

      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
      spring.application.name=order-server
      spring.cloud.nacos.config.file-extension=yml
      spring.cloud.nacos.config.namespace=b49888df-e80a-4e7b-a4eb-c128a41c16e6
      spring.cloud.nacos.config.group=jingdong
      spring.profiles.active=dev
      

      4)配置自動(dòng)刷新

      image

      5)加載多配置文件

      在不同的組創(chuàng)建兩個(gè)配置文件, 文件的命名也沒有按照之前的命名規(guī)則:

      image

      配置文件內(nèi)容分別為: redis: 1234, mysql: 3306;

      bootstrap.properties

      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
      spring.application.name=order-server
      spring.cloud.nacos.config.file-extension=yml
      spring.cloud.nacos.config.namespace=b49888df-e80a-4e7b-a4eb-c128a41c16e6
      spring.cloud.nacos.config.extension-configs[0].data-id=redis.yml
      spring.cloud.nacos.config.extension-configs[1].data-id=mysql.yml
      spring.cloud.nacos.config.extension-configs[1].group=taobao
      

      多配置文件刷新需要加上:

      spring.cloud.nacos.config.extension-configs[0].refresh=true
      

      5 服務(wù)之間的遠(yuǎn)程調(diào)用

      1. HTTP/REST:使用HTTP協(xié)議進(jìn)行通信,通過RESTful API進(jìn)行數(shù)據(jù)交換。每個(gè)微服務(wù)可以作為獨(dú)立的服務(wù)端和客戶端。
      2. 消息隊(duì)列:使用消息隊(duì)列系統(tǒng)(如RabbitMQ、Kafka)來實(shí)現(xiàn)異步通信。微服務(wù)之間通過發(fā)布和訂閱消息來進(jìn)行通信。
      3. RPC(遠(yuǎn)程過程調(diào)用):微服務(wù)之間直接調(diào)用對(duì)方提供的方法,就像本地方法調(diào)用一樣??梢允褂每蚣苋鏶RPC、Thrift、Dubbo等來簡化遠(yuǎn)程調(diào)用過程。
      4. 事件驅(qū)動(dòng)架構(gòu):微服務(wù)之間通過發(fā)布和訂閱事件進(jìn)行通信。一個(gè)微服務(wù)可以產(chǎn)生事件并將其發(fā)布到事件總線,其他微服務(wù)可以訂閱感興趣的事件并做出響應(yīng)。
      5. Service Mesh:使用Service Mesh框架(如Istio、Linkerd)來管理和控制微服務(wù)之間的通信。它在微服務(wù)之間插入代理,提供了流量管理、安全性、故障恢復(fù)等功能。

      1)openfeign的使用

      實(shí)現(xiàn): 訂單服務(wù)遠(yuǎn)程調(diào)用庫存服務(wù)

      導(dǎo)入依賴:

      <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      

      Feign接口:

      @FeignClient("stock-server")
      public interface StockFeign {
          @GetMapping("index")
          String index();
      }
      

      OrderController:

      @RestController
      public class OrderController {
          @Autowired
          StockFeign stockFeign;
          @GetMapping("/index")
          public String index(){
              String index = stockFeign.index();
              return index;
          }
      }
      

      StockController:

      @RestController
      public class StockController {
      
          @Value("${server.port}")
          Integer port;
          @GetMapping("/index")
          public String index(){
              return "這里是stock........."+port;
          }
      }
      

      2)傳值

      3)ribbon負(fù)載均衡的配置

      openfeign默認(rèn)使用的負(fù)載均衡是ribbon, 而ribbon默認(rèn)的負(fù)載均衡策略是輪詢機(jī)制:

      啟動(dòng)2個(gè)stock-server, 端口號(hào)分別為:9002,9003;

      image

      當(dāng)訪問order-server中controller時(shí), 會(huì)發(fā)現(xiàn)9002和9003的stock-server時(shí)輪流訪問的;

      ribbon自帶的負(fù)載均衡策略有:

      1)輪詢策略: RoundRobinRule,按照一定的順序依次調(diào)用服務(wù)實(shí)例。比如一共有 3 個(gè)服務(wù),第一次調(diào)用服務(wù) 1,第二次調(diào)用服務(wù) 2,第三次調(diào)用服務(wù)3,依次類推.

      2)權(quán)重策略: WeightedResponseTimeRule,根據(jù)每個(gè)服務(wù)提供者的響應(yīng)時(shí)間分配一個(gè)權(quán)重,響應(yīng)時(shí)間越長,權(quán)重越小,被選中的可能性也就越低。 它的實(shí)現(xiàn)原理是,剛開始使用輪詢策略并開啟一個(gè)計(jì)時(shí)器,每一段時(shí)間收集一次所有服務(wù)提供者的平均響應(yīng)時(shí)間,然后再給每個(gè)服務(wù)提供者附上一個(gè)權(quán)重,權(quán)重越高被選中的概率也越大.

      3)隨機(jī)策略: RandomRule,從服務(wù)提供者的列表中隨機(jī)選擇一個(gè)服務(wù)實(shí)例.

      4)最小連接數(shù)策略: BestAvailableRule,也叫最小并發(fā)數(shù)策略,它是遍歷服務(wù)提供者列表,選取連接數(shù)最小的?個(gè)服務(wù)實(shí)例。如果有相同的最小連接數(shù),那么會(huì)調(diào)用輪詢策略進(jìn)行選取

      5)重試策略: RetryRule,按照輪詢策略來獲取服務(wù),如果獲取的服務(wù)實(shí)例為 null 或已經(jīng)失效,則在指定的時(shí)間之內(nèi)不斷地進(jìn)行重試來獲取服務(wù),如果超過指定時(shí)間依然沒獲取到服務(wù)實(shí)例則返回 null

      6)可用性敏感策略: AvailabilityFilteringRule,先過濾掉非健康的服務(wù)實(shí)例,然后再選擇連接數(shù)較小的服務(wù)實(shí)例.

      7)區(qū)域敏感策略: ZoneAvoidanceRule,根據(jù)服務(wù)所在區(qū)域(zone)的性能和服務(wù)的可用性來選擇服務(wù)實(shí)例,在沒有區(qū)域的環(huán)境下,該策略和輪詢策略類似.

      配置負(fù)載均衡策略有以下兩種方式:

      1)使用配置文件配置負(fù)載均衡策略:

      # 格式:  服務(wù)名稱.ribbon.NFLoadBalancerRuleClassName=負(fù)載均衡策略
      stock-server.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
      

      2)java類中配置負(fù)載均衡策略:

      @Configuration
      public class MyConfig {
          @Bean
          public IRule loadBalancedRule(){
              return new RandomRule()
          }
      }
      

      3)自定義負(fù)載均衡策略:

      public class MyRule implements IRule {
          private ILoadBalancer lb;
          private List<Integer> excludePorts;
          public MyRule() {
          }
          public MyRule(List<Integer> excludePorts) {
              this.excludePorts = excludePorts;
          }
          
          @Override
          public Server choose(Object o) {
              List<Server> allServers = lb.getAllServers();
              Random random = new Random();
              return allServers.get( random.nextInt(allServers.size()) );
          }
          @Override
          public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
              this.lb = iLoadBalancer;
          }
          @Override
          public ILoadBalancer getLoadBalancer() {
              return lb;
          }
      }
      
      @Configuration
      public class MyConfig {
          @Bean
          public IRule loadBalancedRule(){
              return new MyRule();
          }
      }
      

      ?

      3)SpringCloudLoadBalancer

      由于Netflix公司已經(jīng)停止了對(duì)Spring Cloud Netflix組件的維護(hù)和更新工作, 所以Netflix 相關(guān)的組件已經(jīng)目前已經(jīng)有對(duì)應(yīng)的替代組件:

      所以Ribbon逐漸被LoadBalancer給替換;

      SpringCloudLoadBalancer官方文檔:Cloud Native Applications (spring.io)

      導(dǎo)入依賴:

      <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-loadbalancer</artifactId>
      </dependency>
      

      關(guān)閉對(duì)ribbon的支持:

      spring.cloud.loadbalancer.ribbon.enabled=false
      
      

      SpringCloudLoadBalancer自帶的負(fù)載均衡策略有2中:

      ? 1)輪詢策略:RoundRobinLoadBalancer (默認(rèn))

      ? 2)隨機(jī)策略:RandomLoadBalancer

      可以使用以下方式設(shè)置改變負(fù)載均衡策略:

      @Configuration
      public class MyConfig {
          @Bean
          ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                                  LoadBalancerClientFactory loadBalancerClientFactory) {
              String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
              return new RandomLoadBalancer(loadBalancerClientFactory
                      .getLazyProvider(name, ServiceInstanceListSupplier.class),
                      name);
          }
      }
      
      @SpringBootApplication
      @EnableDiscoveryClient
      @EnableFeignClients
      @LoadBalancerClients(defaultConfiguration = {MyConfig.class})
      public class OrderApp {
          public static void main(String[] args) {
              SpringApplication.run(OrderApp.class);
          }
      }
      

      6 微服務(wù)網(wǎng)關(guān)

      image

      1)網(wǎng)關(guān)介紹:

      Java微服務(wù)是一種用于構(gòu)建和管理微服務(wù)架構(gòu)的核心組件。它充當(dāng)了系統(tǒng)的入口點(diǎn),負(fù)責(zé)接收來自客戶端的請(qǐng)求,并將其轉(zhuǎn)發(fā)到適當(dāng)?shù)奈⒎?wù)實(shí)例進(jìn)行處理.

      ? 主要功能和優(yōu)勢(shì):

      1. 路由和負(fù)載均衡:網(wǎng)關(guān)可以根據(jù)請(qǐng)求的URL、路徑或其他條件,將請(qǐng)求路由到相應(yīng)的微服務(wù)實(shí)例。同時(shí),它還可以通過負(fù)載均衡算法,將請(qǐng)求分發(fā)給多個(gè)實(shí)例,實(shí)現(xiàn)高可用和性能優(yōu)化。
      2. 安全認(rèn)證和授權(quán):網(wǎng)關(guān)可以集成各種安全機(jī)制,例如基于令牌的身份驗(yàn)證、OAuth、JWT等,對(duì)請(qǐng)求進(jìn)行認(rèn)證和授權(quán)。這樣可以確保只有經(jīng)過驗(yàn)證的用戶才能訪問受保護(hù)的微服務(wù)。
      3. 請(qǐng)求轉(zhuǎn)換和協(xié)議適配:網(wǎng)關(guān)可以在前后端之間進(jìn)行請(qǐng)求和響應(yīng)的轉(zhuǎn)換,使不同的客戶端能夠使用適合的協(xié)議和數(shù)據(jù)格式進(jìn)行通信。例如,將RESTful請(qǐng)求轉(zhuǎn)換為SOAP請(qǐng)求,或者將JSON請(qǐng)求轉(zhuǎn)換為Protobuf請(qǐng)求等。
      4. 緩存和性能優(yōu)化:網(wǎng)關(guān)可以對(duì)某些請(qǐng)求進(jìn)行緩存,以減少對(duì)后端微服務(wù)的請(qǐng)求次數(shù),提供更快的響應(yīng)速度。此外,它還可以進(jìn)行請(qǐng)求的壓縮、合并和優(yōu)化,減少網(wǎng)絡(luò)傳輸量,提高性能。
      5. 監(jiān)控和日志:網(wǎng)關(guān)可以收集和記錄請(qǐng)求的統(tǒng)計(jì)信息、異常情況和日志,方便進(jìn)行系統(tǒng)的監(jiān)控和分析。這對(duì)于故障排除、性能優(yōu)化和安全審計(jì)非常有幫助。
      6. 灰度發(fā)布和路由策略:網(wǎng)關(guān)可以支持灰度發(fā)布和路由策略,使得可以逐步將流量從舊版本的微服務(wù)遷移到新版本,同時(shí)還能夠根據(jù)一些規(guī)則對(duì)請(qǐng)求進(jìn)行動(dòng)態(tài)路由。

      常見的Java微服務(wù)網(wǎng)關(guān)包括Netflix Zuul、Spring Cloud Gateway, 由于Netflix 已經(jīng)停止維護(hù), 所以目前常用的微服務(wù)官網(wǎng)Gateway.

      2)基本使用

      導(dǎo)入依賴:

      <dependencies>
             <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-gateway</artifactId>
             </dependency>
      </dependencies>
      

      配置文件:

      server.port=9000
      spring.application.name=gateway-server
      spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
      
      spring:
          cloud:
              gateway:
                  routes:
                      - id: order-server
                        uri: http://127.0.0.1:9001
                        predicates:
                          - Path=/order/**
      

      order-server:

      @GetMapping("/order/index")
      public String index(){
          return "hello"+redis+"+++"+mysql;
      }
      

      瀏覽器訪問: 127.0.0.1:9000/order/index, 會(huì)直接訪問到order-server里面;

      3)路由規(guī)則

      以上的配置中routes就是網(wǎng)關(guān)的路由配置,路由是一個(gè)List的集合, 而每一個(gè)RouteDefinition都包含以下幾條屬性:

      id: 服務(wù)器唯一標(biāo)識(shí);

      uri: 服務(wù)器的地址;

      predicates: 斷言集合; 用于匹配請(qǐng)求的路徑、方法、頭部等信息,從而確定該請(qǐng)求是否應(yīng)該被路由到某個(gè)目標(biāo)服務(wù)。

      filters: 過濾器集合; 用于匹配請(qǐng)求的路徑、方法、頭部等信息,從而確定該請(qǐng)求是否應(yīng)該被路由到某個(gè)目標(biāo)服務(wù)。

      路由根據(jù)斷言進(jìn)行匹配,匹配成功就會(huì)轉(zhuǎn)發(fā)請(qǐng)求給服務(wù)器URI,在轉(zhuǎn)發(fā)請(qǐng)求之前或者之后可以添加過濾器。

      3.1)斷言工廠

      斷言用于匹配請(qǐng)求的條件,以確定是否應(yīng)該將請(qǐng)求路由到某個(gè)目標(biāo)服務(wù)。Spring Cloud Gateway提供了多種類型的斷言,可以根據(jù)請(qǐng)求的路徑、方法、頭部等信息進(jìn)行匹配。

      Spring Cloud Gateway包含許多內(nèi)置的斷言工廠:

      image

      以下是一些常用且需要掌握的斷言類型及其示例:

      1. Path斷言:根據(jù)請(qǐng)求的路徑進(jìn)行匹配。

        1.簡單的路徑匹配:
        	Path=/foo:匹配完整的路徑為/foo的請(qǐng)求。
        	Path=/foo/**:匹配以/foo/開頭的路徑。
        
        2.使用正則表達(dá)式進(jìn)行路徑匹配:
        	Path=^/foo/\\d+$:匹配路徑以/foo/開頭,并且后面跟著一個(gè)或多個(gè)數(shù)字的請(qǐng)求。
        
        3.使用Ant風(fēng)格的路徑匹配:
        	Path=/foo/*:匹配以/foo/開頭的任意一級(jí)路徑。
        	Path=/foo/**/bar:匹配以/foo/開頭,最后一級(jí)路徑為/bar的請(qǐng)求。
        
        4.使用路徑變量進(jìn)行匹配:
        	Path=/foo/{id}:匹配以/foo/開頭,并且后面跟著任意值的請(qǐng)求,將匹配的部分作為路徑變量id傳遞給下游服務(wù)。 
        
      2. Method斷言:根據(jù)請(qǐng)求的HTTP方法進(jìn)行匹配。

        predicates:
          - Method=GET
          
        匹配所有使用GET方法的請(qǐng)求
        
      3. Header斷言:根據(jù)請(qǐng)求的頭部信息進(jìn)行匹配。

        1.簡單的Header匹配:
        	Header=X-Custom-Header, custom-value:
        	匹配請(qǐng)求頭X-Custom-Header的值為custom-value的請(qǐng)求。
        
        2.使用正則表達(dá)式進(jìn)行Header匹配:
        	Header=Content-Type, application/json.*:
        	匹配請(qǐng)求頭Content-Type的值以application/json開頭的請(qǐng)求。
        
        3.多個(gè)Header條件的匹配:
        	Header=X-Custom-Header, custom-value && Authorization, Bearer .*:
        	同時(shí)匹配請(qǐng)求頭X-Custom-Header的值為custom-value和Authorization的值以Bearer開頭的請(qǐng)求。
        
        4.忽略大小寫的Header匹配:
        	Header=X-Custom-Header, custom-value, true:
        	匹配請(qǐng)求頭X-Custom-Header的值為custom-value,忽略大小寫的請(qǐng)求
        
      4. Query斷言:根據(jù)請(qǐng)求的查詢參數(shù)進(jìn)行匹配。

        1.簡單的查詢參數(shù)匹配:
        	Query=param,value:
        	匹配查詢參數(shù)param的值為value的請(qǐng)求。
        	
        2.使用正則表達(dá)式進(jìn)行查詢參數(shù)匹配:
        	Query=param,^\d+$:
        	匹配查詢參數(shù)param的值為一個(gè)或多個(gè)數(shù)字的請(qǐng)求。
        
        3.多個(gè)查詢參數(shù)條件的匹配:
        	Query=param1,value1
        	Query=param2,value2
        	同時(shí)匹配查詢參數(shù)param1的值為value1和param2的值為value2的請(qǐng)求。
        
        4.忽略大小寫的查詢參數(shù)匹配:
        	Query=param,value, case-insensitive,true:
        	匹配查詢參數(shù)param的值為value,忽略大小寫的請(qǐng)求。
        
        5.查詢參數(shù)存在性的匹配:
        	Query=param-exists,true:
        	匹配包含名為param的查詢參數(shù)的請(qǐng)求
        
      5. Cookie斷言:根據(jù)請(qǐng)求的Cookie信息進(jìn)行匹配

        1.簡單的Cookie匹配:
        	Cookie=cookieName,value:
        	匹配名為cookieName且值為value的Cookie。
        
        2.使用正則表達(dá)式進(jìn)行Cookie匹配:
        	Cookie=cookieName, ^\d+$:
        	匹配名為cookieName且值為一個(gè)或多個(gè)數(shù)字的Cookie。
        
        3.多個(gè)Cookie條件的匹配:
        	Cookie=cookie1,value1
        	Cookie=cookie2,value2
        	同時(shí)匹配名為cookie1且值為value1以及名為cookie2且值為value2的Cookie。
        
        4.忽略大小寫的Cookie匹配:
        	Cookie=cookieName,value, case-insensitive=true:
        	匹配名為cookieName且值為value,忽略大小寫的Cookie。
        
        5.Cookie存在性的匹配:
        	Cookie=cookieName-exists,true:
        	匹配包含名為cookieName的Cookie的請(qǐng)求。
        
         
         
      
      ### 3.2)過濾器工廠
      
      過濾器用于對(duì)請(qǐng)求和響應(yīng)進(jìn)行處理和修改。它們可以在路由前、路由后或者錯(cuò)誤處理階段執(zhí)行各種操作,例如鑒權(quán)、請(qǐng)求轉(zhuǎn)發(fā)、日志記錄等;
      
      Spring Cloud Gateway提供了兩種類型的過濾器:全局過濾器和路由過濾器。
      
      **全局過濾器(Global Filter)**: 全局過濾器適用于所有的路由規(guī)則,它們能夠?qū)λ羞M(jìn)入網(wǎng)關(guān)的請(qǐng)求進(jìn)行統(tǒng)一處理??梢酝ㄟ^實(shí)現(xiàn)GlobalFilter接口或使用GatewayFilterFactory來創(chuàng)建自定義的全局過濾器。
      
      ?```java
      @Component
      public class CustomGlobalFilter implements GlobalFilter, Ordered {
          @Override
          public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
              //從請(qǐng)求頭中獲取token
       		String token = exchange.getRequest().getHeaders().getFirst("token");
              //如果請(qǐng)求頭中沒有token就返回權(quán)限不足
              if(StringUtils.isEmpty(token)){
                  exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                  return exchange.getResponse().setComplete();
              }else{
                  return chain.filter(exchange);
              }
          }
      
          @Override
          public int getOrder() {
              return 0; // 過濾器的執(zhí)行順序,值越小優(yōu)先級(jí)越高
          }
      }
      

      路由過濾器: 是指應(yīng)用于特定路由規(guī)則的過濾器。這些過濾器只會(huì)對(duì)匹配該路由規(guī)則的請(qǐng)求進(jìn)行處理。可以通過在路由配置中添加filters屬性來為特定路由規(guī)則定義過濾器鏈。filters屬性是一個(gè)列表,其中包含要應(yīng)用于該路由規(guī)則的多個(gè)過濾器

      Spring Cloud Gateway包含許多內(nèi)置的過濾器工廠:

      image

      以下是一些常用且需要掌握的過濾工廠類型及其示例:

      1.AddRequestHeader:用于向請(qǐng)求頭部添加指定的頭信息;

      filters:
        - AddRequestHeader=X-Custom-Header, foo
        
      在請(qǐng)求中添加一個(gè)名為X-Custom-Header的頭部,值為foo。
      

      2.RewritePath:用于修改請(qǐng)求路徑。

      filters:
        - RewritePath=/oldPath/(?<segment>.*), /newPath/$\{segment}
      
      將匹配/oldPath/開頭的請(qǐng)求路徑,并將其中的/oldPath/替換為/newPath/。
      

      3.SetRequestHeader:用于設(shè)置請(qǐng)求頭部的值

      filters:
        - SetRequestHeader=X-Forwarded-Host, example.com
      
      將請(qǐng)求頭部中的X-Forwarded-Host設(shè)置為example.com
      

      4.RewriteResponseHeader:用于修改響應(yīng)頭部

      filters:
        - RewriteResponseHeader=X-Original-Header, X-New-Header
      
      將響應(yīng)頭部中的X-Original-Header替換為X-New-Header
      

      5.RequestRateLimiter:用于實(shí)現(xiàn)請(qǐng)求速率限制

      filters:
        - RequestRateLimiter=redis-rate-limiter, key-resolver: "#{@userKeyResolver}"
      
      使用Redis作為限流存儲(chǔ),使用自定義的Ke-Resolver來解析限流的鍵
      

      3.3)負(fù)載均衡

      spring:
          cloud:
              gateway:
                  routes:
                      - id: order-server
                        uri: http://127.0.0.1:9001
                        predicates:
                          - Path=/order/**
      

      由于上述代碼中, 將order-server的uri地址寫死了, 所以每次訪問order-server的時(shí)候, 都只會(huì)轉(zhuǎn)發(fā)到指定寫死的uri地址, 如果要做到負(fù)載均衡,則必須把網(wǎng)關(guān)工程注冊(cè)到nacos注冊(cè)中心,然后通過服務(wù)名訪問;

      將網(wǎng)關(guān)服務(wù)注冊(cè)到nacos中, 使用nacos作為配置中心保存網(wǎng)關(guān)服務(wù)器的配置文件, 參見nacos章節(jié);

      修改網(wǎng)關(guān)服務(wù)的配置文件, 使用服務(wù)名稱替換掉寫死的uri地址.

      spring:
          cloud:
              gateway:
                  routes:
                      - id: order-server
                        uri: lb://order-server
                        predicates:
                          - Path=/order/**
      

      啟動(dòng)兩個(gè)order-server, 端口號(hào)分別為 9001,和9002.

      @RestController
      public class OrderController {
          @Value("${server.port}")
          Integer port;
          @GetMapping("/order/index")
          public String index(){
              return "hello:"+port;
          }
      }
      

      通過官網(wǎng)訪問order-server, 頁面上輪流顯示9001和9002.

      7 Sentinel服務(wù)熔斷和限流

      1)Sentinel

      隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來越重要, 一個(gè)服務(wù)如果不限流控制, 就會(huì)導(dǎo)至這個(gè)服務(wù)越來越擁堵, 甚至宕機(jī), 當(dāng)一個(gè)服務(wù)如果出現(xiàn)問題, 如果不加以處理, 那么就會(huì)逐漸蔓延到其他跟該服務(wù)相關(guān)的其他服務(wù), 而Sentinel是一個(gè)開源的流量控制和熔斷降級(jí)框架, 它就是在幫助開發(fā)人員解決分布式系統(tǒng)中的高并發(fā)、限流、熔斷等問題, 以保證微服務(wù)的穩(wěn)定運(yùn)行.

      Sentinel是由阿里巴巴開發(fā)和維護(hù)的開源項(xiàng)目, 它是阿里巴巴技術(shù)團(tuán)隊(duì)在處理大規(guī)模分布式系統(tǒng)中的流量控制和熔斷降級(jí)等問題時(shí)所積累的經(jīng)驗(yàn)的產(chǎn)物.

      • 2012 年,Sentinel 誕生,主要功能為入口流量控制。
      • 2013-2017 年,Sentinel 在阿里巴巴集團(tuán)內(nèi)部迅速發(fā)展,成為基礎(chǔ)技術(shù)模塊,覆蓋了所有的核心場(chǎng)景。Sentinel 也因此積累了大量的流量歸整場(chǎng)景以及生產(chǎn)實(shí)踐。
      • 2018 年,Sentinel 開源,并持續(xù)演進(jìn)。
      • 2019 年,Sentinel 朝著多語言擴(kuò)展的方向不斷探索,推出 C++ 原生版本,同時(shí)針對(duì) Service Mesh 場(chǎng)景也推出了 Envoy 集群流量控制支持,以解決 Service Mesh 架構(gòu)下多語言限流的問題。
      • 2020 年,推出 Sentinel Go 版本,繼續(xù)朝著云原生方向演進(jìn)。

      Sentinel 分為兩個(gè)部分:

      • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境,同時(shí)對(duì) Dubbo / Spring Cloud 等框架也有較好的支持。
      • 控制臺(tái)(Dashboard)基于 Spring Boot 開發(fā),打包后可以直接運(yùn)行,不需要額外的 Tomcat 等應(yīng)用容器。

      Sentinel 可以簡單的分為 Sentinel 核心庫和 Dashboard。核心庫不依賴 Dashboard,但是結(jié)合 Dashboard 可以取得最好的效果。

      2)基本概念

      資源:是 Sentinel 的關(guān)鍵概念。它可以是 Java 應(yīng)用程序中的任何內(nèi)容,例如,由應(yīng)用程序提供的服務(wù),或由應(yīng)用程序調(diào)用的其它應(yīng)用提供的服務(wù),甚至可以是一段代碼。在接下來的文檔中,我們都會(huì)用資源來描述代碼塊。

      只要通過 Sentinel API 定義的代碼,就是資源,能夠被 Sentinel 保護(hù)起來。大部分情況下,可以使用方法簽名,URL,甚至服務(wù)名稱作為資源名來標(biāo)示資源。

      規(guī)則:圍繞資源的實(shí)時(shí)狀態(tài)設(shè)定的規(guī)則,可以包括流量控制規(guī)則、熔斷降級(jí)規(guī)則以及系統(tǒng)保護(hù)規(guī)則。所有規(guī)則可以動(dòng)態(tài)實(shí)時(shí)調(diào)整。

      主要作用:

      1. 流量控制
      2. 熔斷降級(jí)
      3. 系統(tǒng)負(fù)載保護(hù)

      使用 Sentinel 來進(jìn)行資源保護(hù),主要分為幾個(gè)步驟:

      1. 定義資源
      2. 定義規(guī)則
      3. 檢驗(yàn)規(guī)則是否生效

      先把可能需要保護(hù)的資源定義好,之后再配置規(guī)則。也可以理解為,只要有了資源,我們就可以在任何時(shí)候靈活地定義各種流量控制規(guī)則。在編碼的時(shí)候,只需要考慮這個(gè)代碼是否需要保護(hù),如果需要保護(hù),就將之定義為一個(gè)資源。

      3)基本使用

      1)下載指定版本的控制臺(tái) jar 包。https://github.com/alibaba/Sentinel/releases

      2)cmd跳轉(zhuǎn)到該目錄下: 使用指令運(yùn)行:
      java -Dserver.port=8888 -jar sentinel-dashboard-1.8.5.jar
      默認(rèn)端口為:8080, -Dserver.port=8888設(shè)置端口.

      3)在瀏覽器中訪問sentinel控制臺(tái),進(jìn)入登錄頁面,管理頁面用戶名和密碼:sentinel/sentinel

      ? image

      image

      此時(shí)頁面為空,這是因?yàn)檫€沒有監(jiān)控任何服務(wù)。另外,sentinel是懶加載的,如果服務(wù)沒有被訪問,也看不到該服務(wù)信息。

      修改order-server服務(wù)

      增加依賴:

      <dependency>
      		<groupId>com.alibaba.cloud</groupId>
      		<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      </dependency>
      

      配置文件:

      spring.cloud.sentinel.eager=true
      spring.cloud.sentinel.transport.port=8719
      # dashboard 地址
      spring.cloud.sentinel.transport.dashboard=127.0.0.1:8888
      

      集群方式啟動(dòng)兩個(gè)order-server, 9001和9002;

      然后刷新訪問幾次該服務(wù), 再進(jìn)入到sentinel后臺(tái)查看:

      image

      QPS: 每秒請(qǐng)求數(shù),就是說服務(wù)器在一秒的時(shí)間內(nèi)處理了多少個(gè)請(qǐng)求。

      3.1)流控規(guī)則

      ? image

      ? 資源名: 當(dāng)前服務(wù)需要顯示訪問的接口, 可以是controller中的某個(gè)方法也可以是service中的某個(gè)方法

      ? 閥值類型: QPS是控制每秒訪問的次數(shù), 并發(fā)線程數(shù)是限制同時(shí)訪問的線程數(shù);

      ? 單機(jī)閥值: 當(dāng)選擇的是QPS時(shí), 閾值時(shí)1秒鐘內(nèi)訪問的次數(shù), 當(dāng)選擇的是并發(fā)線程數(shù)時(shí), 閾值是同時(shí)訪問的線程數(shù)

      ? 流控模式: 直接:接口達(dá)到限流條件時(shí),直接限流, 就是單純的對(duì)當(dāng)前資源的流量控制. 關(guān)聯(lián):當(dāng)關(guān)聯(lián)的資源達(dá)到閾值時(shí),就限流自己. 只記錄指定鏈路上的流量(指定資源從入口資源進(jìn)來的流量,如果達(dá)到閾值,就可以限流)[api級(jí)別的針對(duì)來源]

      ? 流控效果: 快速失敗,Sentinel會(huì)直接拒絕后續(xù)的請(qǐng)求,返回錯(cuò)誤信息。這種模式適用于對(duì)系統(tǒng)資源要求較高、不希望超過一定限制的場(chǎng)景; 預(yù)熱模式(Warm Up):預(yù)熱模式在系統(tǒng)剛啟動(dòng)或流量突增時(shí),允許請(qǐng)求的速率緩慢增加,以避免系統(tǒng)被突發(fā)流量壓垮。這種模式適用于系統(tǒng)冷啟動(dòng)或者持續(xù)高流量的場(chǎng)景。排隊(duì)等待模式(QPS/Thread Model):該模式通過隊(duì)列來限制請(qǐng)求處理的并發(fā)數(shù),當(dāng)并發(fā)請(qǐng)求數(shù)達(dá)到設(shè)定的閾值時(shí),多余的請(qǐng)求將會(huì)被放入隊(duì)列中等待處理。這種模式適用于對(duì)系統(tǒng)并發(fā)數(shù)有限制需求的場(chǎng)景,可以平滑處理突發(fā)流量。

      3.2)熔斷降級(jí)規(guī)則

      ? Sentinel除了流量控制以外,對(duì)調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級(jí)也是保障高可用的重要措施之一。由于調(diào)用關(guān)系的復(fù)雜性,如果調(diào)用鏈路中的某個(gè)資源不穩(wěn)定,最終會(huì)導(dǎo)致請(qǐng)求發(fā)生堆積。Sentinel 熔斷降級(jí)會(huì)在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)時(shí)(例如調(diào)用超時(shí)或異常比例升高),對(duì)這個(gè)資源的調(diào)用進(jìn)行限制,讓請(qǐng)求快速失敗,避免影響到其它的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤, 最后造成微服務(wù)雪崩.

      ? 當(dāng)資源被降級(jí)后,在接下來的降級(jí)時(shí)間窗口之內(nèi),對(duì)該資源的調(diào)用都自動(dòng)熔斷(默認(rèn)行為是拋出 DegradeException)。

      ? image

      ? 熔斷策略:
      ? 慢調(diào)比: 就是調(diào)用使用該資源, 資源響應(yīng)速度很慢; 最大RT意思是最大響應(yīng)時(shí)間, 比例閾值: 這個(gè)最大響應(yīng)時(shí)間的請(qǐng)求比例的最大值;
      ? 異常比例: 訪問資源出現(xiàn)異常的比例; 比例閾值: 出現(xiàn)異常的比例最大值;
      ? 異常數(shù): 當(dāng)資源近 1 分鐘的異常數(shù)目;

      ? 熔斷時(shí)長: 限制該資源使用的時(shí)長, 超過這個(gè)時(shí)長后, 進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN)階段,即接下來的一個(gè)請(qǐng)求響應(yīng)時(shí)間小于rt,則熔斷結(jié)束,否則會(huì)再次被熔斷。

      ? 最小請(qǐng)求數(shù): 觸發(fā)熔斷的最小請(qǐng)求數(shù);

      ? 統(tǒng)計(jì)時(shí)長: 設(shè)置多長時(shí)間作為一個(gè)統(tǒng)計(jì)周期, 判斷是否進(jìn)入熔斷;

      4)限流和熔斷處理

      @SentinelResource注解

      可以靈活用該注解來定義需要控制的資源, 可以在類或者接口上, 也可以是在方法上;

      ? value: 定義資源名稱;
      ? blockHandler / fallback: 指定當(dāng)發(fā)生熔斷或者限流時(shí)的處理函數(shù)
      ? blockHandlerClass: 指定當(dāng)發(fā)生熔斷或者限流時(shí)的處理函數(shù)所在的類, 這樣可以定義全局的限流熔斷的處理方法;

       	@GetMapping("/order/index")
          @SentinelResource(value = "byUrl", blockHandler = "handleException")
          public String index(Integer num) throws InterruptedException {
              if(num>3){
                  Thread.sleep(600);
              }
              return "hello:"+port;
          }
          public String handleException(Integer num,BlockException e){
              return "擁堵了, 心里沒數(shù)嗎?";
          }
      

      ? fallback和blockHandler 作用相同, 但是blockHandler指定的方法形參和資源方法相同外, 還必須入?yún)lockException異常;
      ? fallback值需要形參相同即可;
      ? 優(yōu)先級(jí)上, 一開始幾次是fallback,后面限流開始調(diào)用blockHandler。

      5)配置持久化

      1)下載sentinel-dashborad源碼;

      2)修改pom.xml文件

      <!-- for Nacos rule publisher sample -->
      <dependency>
          <groupId>com.alibaba.csp</groupId>
          <artifactId>sentinel-datasource-nacos</artifactId>
          <!--<scope>test</scope>-->
      </dependency>
      
      spring.cloud.sentinel.eager=true
      spring.cloud.sentinel.transport.dashboard=127.0.0.1:8888
      spring.cloud.sentinel.transport.port=8719
      spring.cloud.sentinel.datasource.ds1.nacos.server-addr=127.0.0.1:8848
      spring.cloud.sentinel.datasource.ds1.nacos.data-id=sentinel-service
      spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
      spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
      spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow
      

      image

      流控規(guī)則的寫法:

      [
        {
          // 資源名
          "resource": "/test",
          // 針對(duì)來源,若為 default 則不區(qū)分調(diào)用來源
          "limitApp": "default",
          // 限流閾值類型(1:QPS;0:并發(fā)線程數(shù))
          "grade": 1,
          // 閾值
          "count": 1,
          // 是否是集群模式
          "clusterMode": false,
          // 流控效果(0:快速失敗;1:Warm Up(預(yù)熱模式);2:排隊(duì)等待)
          "controlBehavior": 0,
          // 流控模式(0:直接;1:關(guān)聯(lián);2:鏈路)
          "strategy": 0,
          // 預(yù)熱時(shí)間(秒,預(yù)熱模式需要此參數(shù))
          "warmUpPeriodSec": 10,
          // 超時(shí)時(shí)間(排隊(duì)等待模式需要此參數(shù))
          "maxQueueingTimeMs": 500,
          // 關(guān)聯(lián)資源、入口資源(關(guān)聯(lián)、鏈路模式)
          "refResource": "rrr"
        }
      ]
      
      spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
      spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel-order2-server
      spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
      spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
      spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade
      

      熔斷降級(jí)的寫法:

      [
        {
        	// 資源名
          "resource": "/test1",
          "limitApp": "default",
          // 熔斷策略(0:慢調(diào)用比例,1:異常比率,2:異常計(jì)數(shù))
          "grade": 0,
          // 最大RT、比例閾值、異常數(shù)
          "count": 200,
          // 慢調(diào)用比例閾值,僅慢調(diào)用比例模式有效(1.8.0 引入)
          "slowRatioThreshold": 0.2,
          // 最小請(qǐng)求數(shù)
          "minRequestAmount": 5,
          // 當(dāng)單位統(tǒng)計(jì)時(shí)長(類中默認(rèn)1000)
          "statIntervalMs": 1000,
          // 熔斷時(shí)長
          "timeWindow": 10
        }
      ]
      

      8 分布式CAP理論

      1)CAP的介紹

      分布式CAP理論是由計(jì)算機(jī)科學(xué)家Eric Brewer提出的,它描述了在分布式系統(tǒng)中三個(gè)重要屬性之間的沖突。這三個(gè)屬性是一致性(Consistency)、可用性(Availability)分區(qū)容錯(cuò)性(Partition tolerance)。根據(jù)CAP理論,一個(gè)分布式系統(tǒng)最多只能同時(shí)滿足其中的兩個(gè)屬性,無法同時(shí)滿足全部三個(gè)。

      一致性(Consistency)即更新操作成功并返回客戶端完成后,所有節(jié)點(diǎn)在同一時(shí)間的數(shù)據(jù)完全一致。對(duì)于一致性,可以分為從客戶端和服務(wù)端兩個(gè)不同的視角。

      從客戶端來看,一致性主要指的是多并發(fā)訪問時(shí)更新過的數(shù)據(jù)如何獲取的問題。從服務(wù)端來看,則是更新如何復(fù)制分布到整個(gè)系統(tǒng),以保證數(shù)據(jù)最終一致。一致性是因?yàn)橛胁l(fā)讀寫才有的問題,因此在理解一致性的問題時(shí),一定要注意結(jié)合考慮并發(fā)讀寫的場(chǎng)景。

      從客戶端角度,多進(jìn)程并發(fā)訪問時(shí),更新過的數(shù)據(jù)在不同進(jìn)程如何獲取的不同策略,決定了不同的一致性。對(duì)于關(guān)系型數(shù)據(jù)庫,要求更新過的數(shù)據(jù)能被后續(xù)的訪問都能看到,這是強(qiáng)一致性。如果能容忍后續(xù)的部分或者全部訪問不到,則是弱一致性。如果經(jīng)過一段時(shí)間后要求能訪問到更新后的數(shù)據(jù),則是最終一致性。

      可用性(Availability)即服務(wù)一直可用,而且是正常響應(yīng)時(shí)間。對(duì)于一個(gè)可用性的分布式系統(tǒng),每一個(gè)非故障的節(jié)點(diǎn)必須對(duì)每一個(gè)請(qǐng)求作出響應(yīng)。也就是,該系統(tǒng)使用的任何算法必須最終終止。當(dāng)同時(shí)要求分區(qū)容忍性時(shí),這是一個(gè)很強(qiáng)的定義:即使是嚴(yán)重的網(wǎng)絡(luò)錯(cuò)誤,每個(gè)請(qǐng)求必須終止。

      好的可用性主要是指系統(tǒng)能夠很好的為用戶服務(wù),不出現(xiàn)用戶操作失敗或者訪問超時(shí)等用戶體驗(yàn)不好的情況。可用性通常情況下可用性和分布式數(shù)據(jù)冗余,負(fù)載均衡等有著很大的關(guān)聯(lián)。

      分區(qū)容錯(cuò)性(Partition tolerance)即分布式系統(tǒng)在遇到某節(jié)點(diǎn)或網(wǎng)絡(luò)分區(qū)故障的時(shí)候,仍然能夠?qū)ν馓峁M足一致性和可用性的服務(wù)。分區(qū)容錯(cuò)性和擴(kuò)展性緊密相關(guān)。在分布式應(yīng)用中,可能因?yàn)橐恍┓植际降脑驅(qū)е孪到y(tǒng)無法正常運(yùn)轉(zhuǎn)。好的分區(qū)容錯(cuò)性要求能夠使應(yīng)用雖然是一個(gè)分布式系統(tǒng),而看上去卻好像是在一個(gè)可以運(yùn)轉(zhuǎn)正常的整體。比如現(xiàn)在的分布式系統(tǒng)中有某一個(gè)或者幾個(gè)機(jī)器宕掉了,其他剩下的機(jī)器還能夠正常運(yùn)轉(zhuǎn)滿足系統(tǒng)需求,或者是機(jī)器之間有網(wǎng)絡(luò)異常,將分布式系統(tǒng)分隔未獨(dú)立的幾個(gè)部分,各個(gè)部分還能維持分布式系統(tǒng)的運(yùn)作,這樣就具有好的分區(qū)容錯(cuò)性。

      2)CAP的證明

      image

      如上圖,是我們證明CAP的基本場(chǎng)景,網(wǎng)絡(luò)中有兩個(gè)節(jié)點(diǎn)N1和N2,可以簡單的理解N1和N2分別是兩臺(tái)計(jì)算機(jī),他們之間網(wǎng)絡(luò)可以連通,N1中有一個(gè)應(yīng)用程序A,和一個(gè)數(shù)據(jù)庫V,N2也有一個(gè)應(yīng)用程序B2和一個(gè)數(shù)據(jù)庫V?,F(xiàn)在,A和B是分布式系統(tǒng)的兩個(gè)部分,V是分布式系統(tǒng)的數(shù)據(jù)存儲(chǔ)的兩個(gè)子數(shù)據(jù)庫。

      在滿足一致性的時(shí)候,N1和N2中的數(shù)據(jù)是一樣的,V0=V0。在滿足可用性的時(shí)候,用戶不管是請(qǐng)求N1或者N2,都會(huì)得到立即響應(yīng)。在滿足分區(qū)容錯(cuò)性的情況下,N1和N2有任何一方宕機(jī),或者網(wǎng)絡(luò)不通的時(shí)候,都不會(huì)影響N1和N2彼此之間的正常運(yùn)作。

      如上圖,是分布式系統(tǒng)正常運(yùn)轉(zhuǎn)的流程,用戶向N1機(jī)器請(qǐng)求數(shù)據(jù)更新,程序A更新數(shù)據(jù)庫Vo為V1,分布式系統(tǒng)將數(shù)據(jù)進(jìn)行同步操作M,將V1同步的N2中V0,使得N2中的數(shù)據(jù)V0也更新為V1,N2中的數(shù)據(jù)再響應(yīng)N2的請(qǐng)求。

      這里,可以定義N1和N2的數(shù)據(jù)庫V之間的數(shù)據(jù)是否一樣為一致性;外部對(duì)N1和N2的請(qǐng)求響應(yīng)為可用行;N1和N2之間的網(wǎng)絡(luò)環(huán)境為分區(qū)容錯(cuò)性。這是正常運(yùn)作的場(chǎng)景,也是理想的場(chǎng)景,然而現(xiàn)實(shí)是殘酷的,當(dāng)錯(cuò)誤發(fā)生的時(shí)候,一致性和可用性還有分區(qū)容錯(cuò)性,是否能同時(shí)滿足,還是說要進(jìn)行取舍呢?

      作為一個(gè)分布式系統(tǒng),它和單機(jī)系統(tǒng)的最大區(qū)別,就在于網(wǎng)絡(luò),現(xiàn)在假設(shè)一種極端情況,N1和N2之間的網(wǎng)絡(luò)斷開了,我們要支持這種網(wǎng)絡(luò)異常,相當(dāng)于要滿足分區(qū)容錯(cuò)性,能不能同時(shí)滿足一致性和響應(yīng)性呢?還是說要對(duì)他們進(jìn)行取舍。

      假設(shè)在N1和N2之間網(wǎng)絡(luò)斷開的時(shí)候,有用戶向N1發(fā)送數(shù)據(jù)更新請(qǐng)求,那N1中的數(shù)據(jù)V0將被更新為V1,由于網(wǎng)絡(luò)是斷開的,所以分布式系統(tǒng)同步操作M,所以N2中的數(shù)據(jù)依舊是V0;這個(gè)時(shí)候,有用戶向N2發(fā)送數(shù)據(jù)讀取請(qǐng)求,由于數(shù)據(jù)還沒有進(jìn)行同步,應(yīng)用程序沒辦法立即給用戶返回最新的數(shù)據(jù)V1,怎么辦呢?有二種選擇,第一,犧牲數(shù)據(jù)一致性,響應(yīng)舊的數(shù)據(jù)V0給用戶;第二,犧牲可用性,阻塞等待,直到網(wǎng)絡(luò)連接恢復(fù),數(shù)據(jù)更新操作M完成之后,再給用戶響應(yīng)最新的數(shù)據(jù)V1。

      這個(gè)過程,證明了要滿足分區(qū)容錯(cuò)性的分布式系統(tǒng),只能在一致性和可用性兩者中,選擇其中一個(gè)。

      3)CAP的權(quán)衡

      通過CAP理論,我們知道無法同時(shí)滿足一致性、可用性和分區(qū)容錯(cuò)性這三個(gè)特性,那要舍棄哪個(gè)呢?

      CA without P:如果不要求P(不允許分區(qū)),則C(強(qiáng)一致性)和A(可用性)是可以保證的。但其實(shí)分區(qū)不是你想不想的問題,而是始終會(huì)存在,因此CA的系統(tǒng)更多的是允許分區(qū)后各子系統(tǒng)依然保持CA。

      CP without A:如果不要求A(可用),相當(dāng)于每個(gè)請(qǐng)求都需要在Server之間強(qiáng)一致,而P(分區(qū))會(huì)導(dǎo)致同步時(shí)間無限延長,如此CP也是可以保證的。很多傳統(tǒng)的數(shù)據(jù)庫分布式事務(wù)都屬于這種模式。

      AP wihtout C:要高可用并允許分區(qū),則需放棄一致性。一旦分區(qū)發(fā)生,節(jié)點(diǎn)之間可能會(huì)失去聯(lián)系,為了高可用,每個(gè)節(jié)點(diǎn)只能用本地?cái)?shù)據(jù)提供服務(wù),而這樣會(huì)導(dǎo)致全局?jǐn)?shù)據(jù)的不一致性?,F(xiàn)在眾多的NoSQL都屬于此類。

      對(duì)于多數(shù)大型互聯(lián)網(wǎng)應(yīng)用的場(chǎng)景,主機(jī)眾多、部署分散,而且現(xiàn)在的集群規(guī)模越來越大,所以節(jié)點(diǎn)故障、網(wǎng)絡(luò)故障是常態(tài),而且要保證服務(wù)可用性達(dá)到N個(gè)9,即保證P和A,舍棄C(退而求其次保證最終一致性)。雖然某些地方會(huì)影響客戶體驗(yàn),但沒達(dá)到造成用戶流程的嚴(yán)重程度。

      對(duì)于涉及到錢財(cái)這樣不能有一絲讓步的場(chǎng)景,C必須保證。網(wǎng)絡(luò)發(fā)生故障寧可停止服務(wù),這是保證CA,舍棄P。貌似這幾年國內(nèi)銀行業(yè)發(fā)生了不下10起事故,但影響面不大,報(bào)到也不多,廣大群眾知道的少。還有一種是保證CP,舍棄A。例如網(wǎng)絡(luò)故障事只讀不寫。

      孰優(yōu)孰略,沒有定論,只能根據(jù)場(chǎng)景定奪,適合的才是最好的。

      9 分布式鎖

      1)介紹

      隨著技術(shù)快速發(fā)展,數(shù)據(jù)規(guī)模增大,分布式系統(tǒng)越來越普及,一個(gè)應(yīng)用往往會(huì)部署在多臺(tái)機(jī)器上(多節(jié)點(diǎn)),在有些場(chǎng)景中,為了保證數(shù)據(jù)不重復(fù),要求在同一時(shí)刻,同一任務(wù)只在一個(gè)節(jié)點(diǎn)上運(yùn)行,即保證某一方法同一時(shí)刻只能被一個(gè)線程執(zhí)行。在單機(jī)環(huán)境中,應(yīng)用是在同一進(jìn)程下的,只需要保證單進(jìn)程多線程環(huán)境中的線程安全性,通過 JAVA 提供的 volatile、ReentrantLock、synchronized 以及 concurrent 并發(fā)包下一些線程安全的類等就可以做到。而在多機(jī)部署環(huán)境中,不同機(jī)器不同進(jìn)程,就需要在多進(jìn)程下保證線程的安全性了。因此,分布式鎖應(yīng)運(yùn)而生。

      分布式鎖需滿足四個(gè)條件

      首先,為了確保分布式鎖可用,我們至少要確保鎖的實(shí)現(xiàn)同時(shí)滿足以下四個(gè)條件:

      1. 互斥性。在任意時(shí)刻,只有一個(gè)客戶端能持有鎖。
      2. 不會(huì)發(fā)生死鎖。即使有一個(gè)客戶端在持有鎖的期間崩潰而沒有主動(dòng)解鎖,也能保證后續(xù)其他客戶端能加鎖。
      3. 解鈴還須系鈴人。加鎖和解鎖必須是同一個(gè)客戶端,客戶端自己不能把別人加的鎖給解了,即不能誤解鎖。
      4. 具有容錯(cuò)性。只要大多數(shù)Redis節(jié)點(diǎn)正常運(yùn)行,客戶端就能夠獲取和釋放鎖。

      常見的分布式的實(shí)現(xiàn)方式:

      分類 方案 實(shí)現(xiàn)原理 優(yōu)點(diǎn) 缺點(diǎn)
      基于數(shù)據(jù)庫 基于mysql 表唯一索引 1.表增加唯一索引 2.加鎖:執(zhí)行insert語句,若報(bào)錯(cuò),則表明加鎖失敗 3.解鎖:執(zhí)行delete語句 完全利用DB現(xiàn)有能力,實(shí)現(xiàn)簡單 1.鎖無超時(shí)自動(dòng)失效機(jī)制,有死鎖風(fēng)險(xiǎn) 2.不支持鎖重入,不支持阻塞等待 3.操作數(shù)據(jù)庫開銷大,性能不高
      基于MongoDB findAndModify原子操作 1.加鎖:執(zhí)行findAndModify原子命令查找document,若不存在則新增 2.解鎖:刪除document 實(shí)現(xiàn)也很容易,較基于MySQL唯一索引的方案,性能要好很多 1.大部分公司數(shù)據(jù)庫用MySQL,可能缺乏相應(yīng)的MongoDB運(yùn)維、開發(fā)人員 2.鎖無超時(shí)自動(dòng)失效機(jī)制
      基于分布式協(xié)調(diào)系統(tǒng) 基于ZooKeeper 1.加鎖:在/lock目錄下創(chuàng)建臨時(shí)有序節(jié)點(diǎn),判斷創(chuàng)建的節(jié)點(diǎn)序號(hào)是否最小。若是,則表示獲取到鎖;否,則則watch /lock目錄下序號(hào)比自身小的前一個(gè)節(jié)點(diǎn) 2.解鎖:刪除節(jié)點(diǎn) 1.由zk保障系統(tǒng)高可用 2.Curator框架已原生支持系列分布式鎖命令,使用簡單 需單獨(dú)維護(hù)一套zk集群,維保成本高
      基于緩存 基于redis命令 1. 加鎖:執(zhí)行setnx,若成功再執(zhí)行expire添加過期時(shí)間 2. 解鎖:執(zhí)行delete命令 實(shí)現(xiàn)簡單,相比數(shù)據(jù)庫和分布式系統(tǒng)的實(shí)現(xiàn),該方案最輕,性能最好 1.setnx和expire分2步執(zhí)行,非原子操作;若setnx執(zhí)行成功,但expire執(zhí)行失敗,就可能出現(xiàn)死鎖 2.delete命令存在誤刪除非當(dāng)前線程持有的鎖的可能 3.不支持阻塞等待、不可重入
      基于redis Lua腳本能力 1. 加鎖:執(zhí)行SET lock_name random_value EX seconds NX 命令 2. 解鎖:執(zhí)行Lua腳本,釋放鎖時(shí)驗(yàn)證random_value -- ARGV[1]為random_value, KEYS[1]為lock_nameif redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1])else return 0 end 同上;實(shí)現(xiàn)邏輯上也更嚴(yán)謹(jǐn),除了單點(diǎn)問題,生產(chǎn)環(huán)境采用用這種方案,問題也不大。 不支持鎖重入,不支持阻塞等待

      表格中對(duì)比了幾種常見的方案,redis+lua基本可應(yīng)付工作中分布式鎖的需求。

      2)基本使用

      模擬:3臺(tái)order-server服務(wù)器同時(shí)賣20個(gè)商品, 商品數(shù)量保存在redis中;

      業(yè)務(wù)邏輯: order-server從redis中取出商品數(shù)量, 如果數(shù)量大于10, 那么就賣出一個(gè)商品, 然后講redis中的數(shù)量-1, 如果取出的數(shù)量等于0, 代表商品賣完了, 返回商品搶購結(jié)束!

      依賴

      <dependency>
      		<groupId>org.redisson</groupId>
      		<artifactId>redisson-spring-boot-starter</artifactId>
      		<version>3.17.1</version>
      </dependency>
      

      基本配置

      spring:
          redis:
              host: 175.24.205.196
              port: 6379
              password: boge123123
              database: 3
      

      啟動(dòng)網(wǎng)關(guān)服務(wù);

      啟動(dòng)3個(gè)訂單服務(wù);

      不加鎖:
      
      
      
      
      
      普通鎖:
      
      
      
      
      
      
      分布式鎖:
      
      
      
      
      

      redisson分布式鎖流程:

      image

      3)redisson中的鎖

      普通鎖

      RLock lock = redisson.getLock("myLock");
      lock.lock();
      lock.lock(10, TimeUnit.SECONDS);
      boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
      if (res) {
         try {
           ...
         } finally {
             lock.unlock();
         }
      }
      

      公平鎖

      RLock lock = redisson.getFairLock("myLock");
      lock.lock();
      lock.lock(10, TimeUnit.SECONDS);
      boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
      if (res) {
         try {
           ...
         } finally {
             lock.unlock();
         }
      }
      

      多重鎖

      RLock lock1 = redisson1.getLock("lock1");
      RLock lock2 = redisson2.getLock("lock2");
      RLock lock3 = redisson3.getLock("lock3");
      
      RLock multiLock = anyRedisson.getMultiLock(lock1, lock2, lock3);
      
      multiLock.lock();
      multiLock.lock(10, TimeUnit.SECONDS);
      boolean res = multiLock.tryLock(100, 10, TimeUnit.SECONDS);
      if (res) {
         try {
           ...
         } finally {
             multiLock.unlock();
         }
      }
      

      讀寫鎖

      RReadWriteLock rwlock = redisson.getReadWriteLock("myLock");
      
      RLock lock = rwlock.readLock();
      RLock lock = rwlock.writeLock();
      
      lock.lock();
      lock.lock(10, TimeUnit.SECONDS);
      boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
      if (res) {
         try {
           ...
         } finally {
             lock.unlock();
         }
      }
      

      信號(hào)量

      RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
      
      semaphore.acquire();
      semaphore.acquire(10);
      
      // or try to acquire permit
      boolean res = semaphore.tryAcquire();
      
      // or try to acquire permit or wait up to 15 seconds
      boolean res = semaphore.tryAcquire(15, TimeUnit.SECONDS);
      
      // or try to acquire 10 permit
      boolean res = semaphore.tryAcquire(10);
      
      // or try to acquire 10 permits or wait up to 15 seconds
      boolean res = semaphore.tryAcquire(10, 15, TimeUnit.SECONDS);
      if (res) {
         try {
           ...
         } finally {
             semaphore.release();
         }
      }
      

      10 分布式事務(wù)

      1)事務(wù)的介紹

      嚴(yán)格意義上的事務(wù)實(shí)現(xiàn)應(yīng)該是具備原子性、一致性、隔離性持久性,簡稱 ACID。

      • 原子性(Atomicity),可以理解為一個(gè)事務(wù)內(nèi)的所有操作要么都執(zhí)行,要么都不執(zhí)行。
      • 一致性(Consistency),可以理解為數(shù)據(jù)是滿足完整性約束的,也就是不會(huì)存在中間狀態(tài)的數(shù)據(jù),比如你賬上有400,我賬上有100,你給我打200塊,此時(shí)你賬上的錢應(yīng)該是200,我賬上的錢應(yīng)該是300,不會(huì)存在我賬上錢加了,你賬上錢沒扣的中間狀態(tài)。
      • 隔離性(Isolation),指的是多個(gè)事務(wù)并發(fā)執(zhí)行的時(shí)候不會(huì)互相干擾,即一個(gè)事務(wù)內(nèi)部的數(shù)據(jù)對(duì)于其他事務(wù)來說是隔離的。
      • 持久性(Durability),指的是一個(gè)事務(wù)完成了之后數(shù)據(jù)就被永遠(yuǎn)保存下來,之后的其他操作或故障都不會(huì)對(duì)事務(wù)的結(jié)果產(chǎn)生影響。

      分布式事務(wù)是指在分布式系統(tǒng)中涉及到多個(gè)獨(dú)立的操作或數(shù)據(jù)更新時(shí),保證這些操作要么全部成功要么全部失敗的機(jī)制。它是為了解決分布式系統(tǒng)中數(shù)據(jù)一致性問題而提出的一種技術(shù)手段。

      在傳統(tǒng)的單體應(yīng)用中,數(shù)據(jù)庫事務(wù)能夠確保操作的原子性、一致性、隔離性和持久性(ACID)特性。然而,在分布式系統(tǒng)中,由于存在多個(gè)數(shù)據(jù)庫實(shí)例、服務(wù)節(jié)點(diǎn)或存儲(chǔ)介質(zhì),事務(wù)的隔離性和一致性變得更加復(fù)雜。

      為了解決這些挑戰(zhàn),有幾種常見的分布式事務(wù)模型被提出,包括兩階段提交(2PC)、三階段提交(3PC)、補(bǔ)償事務(wù)等。這些模型都試圖通過協(xié)調(diào)各參與節(jié)點(diǎn)的狀態(tài)來達(dá)到全局一致性。

      然而,分布式事務(wù)也帶來了一些性能和可用性的問題。由于需要協(xié)調(diào)多個(gè)節(jié)點(diǎn),會(huì)增加通信開銷和延遲;同時(shí),若一個(gè)節(jié)點(diǎn)失效,整個(gè)事務(wù)可能會(huì)被阻塞或回滾。因此,在設(shè)計(jì)分布式系統(tǒng)時(shí),需要權(quán)衡事務(wù)一致性要求和性能可擴(kuò)展性。

      2)常用的分布式事務(wù)解決方案

      a)XA 模式之兩階段提交

      ? 兩階段提交又稱2PC(two-phase commit protocol),2pc是一個(gè)非常經(jīng)典的強(qiáng)一致、中心化的原子提交協(xié)議。這里所說的中心化是指協(xié)議中有兩類節(jié)點(diǎn):一個(gè)是中心化協(xié)調(diào)者節(jié)點(diǎn)和N個(gè)參與者節(jié)點(diǎn)。

      ? 準(zhǔn)備階段: 事務(wù)協(xié)調(diào)者向所有事務(wù)參與者發(fā)送事務(wù)內(nèi)容,詢問是否可以提交事務(wù),并等待參與者回復(fù)。事務(wù)參與者收到事務(wù)內(nèi)容,開始執(zhí)行事務(wù)操作,講 undo 和 redo 信息記入事務(wù)日志中(但此時(shí)并不提交事務(wù))。如果參與者執(zhí)行成功,給協(xié)調(diào)者回復(fù)yes,表示可以進(jìn)行事務(wù)提交。如果執(zhí)行失敗,給協(xié)調(diào)者回復(fù)no,表示不可提交。

      ? 提交階段: 如果協(xié)調(diào)者收到了參與者的失敗信息或超時(shí)信息,直接給所有參與者發(fā)送回滾(rollback)信息進(jìn)行事務(wù)回滾,否則發(fā)送提交(commit)信息。參與者根據(jù)協(xié)調(diào)者的指令執(zhí)行提交或者回滾操作,釋放所有事務(wù)處理過程中使用的鎖資源。(注意:必須在最后階段釋放鎖資源)

      ? 會(huì)遇到的一些問題

      ? 性能問題

      ? 從流程上我們可以看得出,其最大缺點(diǎn)就在于它的執(zhí)行過程中間,節(jié)點(diǎn)都處于阻塞狀態(tài)。各個(gè)操作數(shù)據(jù)庫的節(jié)點(diǎn)此時(shí)都占用著數(shù)據(jù)庫資源,只有當(dāng)所有節(jié)點(diǎn)準(zhǔn)備完畢,事務(wù)協(xié)調(diào)者才會(huì)通知進(jìn)行全局提交,參與者進(jìn)行本地事務(wù)提交后才會(huì)釋放資源。這樣的過程會(huì)比較漫長,對(duì)性能影響比較大。

      ? 協(xié)調(diào)者單點(diǎn)故障問題

      ? 事務(wù)協(xié)調(diào)者是整個(gè)XA模型的核心,一旦事務(wù)協(xié)調(diào)者節(jié)點(diǎn)掛掉,會(huì)導(dǎo)致參與者收不到提交或回滾的通知,從而導(dǎo)致參與者節(jié)點(diǎn)始終處于事務(wù)無法完成的中間狀態(tài)。

      ? 丟失消息導(dǎo)致的數(shù)據(jù)不一致問題

      ? 在第二個(gè)階段,如果發(fā)生局部網(wǎng)絡(luò)問題,一部分事務(wù)參與者收到了提交消息,另一部分事務(wù)參與者沒收到提交消息,那么就會(huì)導(dǎo)致節(jié)點(diǎn)間數(shù)據(jù)的不一致問題。

      ? 2PC 方案實(shí)現(xiàn)起來簡單,基于上面提到的兩階段提交協(xié)議中會(huì)遇到的問題;

      b)XA 模式之三階段提交

      ? 三階段提交又稱3PC, 三階段提交是在二階段提交上的改進(jìn)版本,其在兩階段提交的基礎(chǔ)上增加了 CanCommit階段,并加入了超時(shí)機(jī)制。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制。三階段將二階段的準(zhǔn)備階段拆分為2個(gè)階段,插入了一個(gè)preCommit階段,以此來處理原先二階段,參與者準(zhǔn)備后,參與者發(fā)生崩潰或錯(cuò)誤,導(dǎo)致參與者無法知曉是否提交或回滾的不確定狀態(tài)所引起的延時(shí)問題。

      ? 階段一(canCommit): 協(xié)調(diào)者向所有參與者發(fā)出包含事務(wù)內(nèi)容的 canCommit 請(qǐng)求,詢問是否可以提交事務(wù),并等待所有參與者答復(fù)。參與者收到 canCommit 請(qǐng)求后,如果認(rèn)為可以執(zhí)行事務(wù)操作,則反饋 yes 并進(jìn)入預(yù)備狀態(tài),否則反饋 no

      ? 階段二(PreCommit): 階段一中,如果所有的參與者都返回Yes的話,那么就會(huì)進(jìn)入PreCommit階段進(jìn)行事務(wù)預(yù)提交。此時(shí)分布式事務(wù)協(xié)調(diào)者會(huì)向所有的參與者節(jié)點(diǎn)發(fā)送PreCommit請(qǐng)求,參與者收到后開始執(zhí)行事務(wù)操作,并將Undo和Redo信息記錄到事務(wù)日志中。參與者執(zhí)行完事務(wù)操作后(此時(shí)屬于未提交事務(wù)的狀態(tài)),就會(huì)向協(xié)調(diào)者反饋“Ack”表示我已經(jīng)準(zhǔn)備好提交了,并等待協(xié)調(diào)者的下一步指令。如果階段一中有任何一個(gè)參與者節(jié)點(diǎn)返回的結(jié)果是No響應(yīng),或者協(xié)調(diào)者在等待參與者節(jié)點(diǎn)反饋的過程中因掛掉而超時(shí)2PC中只有協(xié)調(diào)者可以超時(shí),參與者沒有超時(shí)機(jī)制)。整個(gè)分布式事務(wù)就會(huì)中斷,協(xié)調(diào)者就會(huì)向所有的參與者發(fā)送“abort”請(qǐng)求。

      ? 階段三(do Commit): 該階段進(jìn)行真正的事務(wù)提交,在階段二中如果所有的參與者節(jié)點(diǎn)都可以進(jìn)行PreCommit提交,那么協(xié)調(diào)者就會(huì)從“預(yù)提交狀態(tài)” 轉(zhuǎn)變?yōu)?“提交狀態(tài)”。然后向所有的參與者節(jié)點(diǎn)發(fā)送"doCommit"請(qǐng)求,參與者節(jié)點(diǎn)在收到提交請(qǐng)求后就會(huì)各自執(zhí)行事務(wù)提交操作,并向協(xié)調(diào)者節(jié)點(diǎn)反饋“Ack”消息,協(xié)調(diào)者收到所有參與者的Ack消息后完成事務(wù)。

      ? 相比較2PC而言,3PC對(duì)于協(xié)調(diào)者(Coordinator)和參與者(Partcipant)都設(shè)置了超時(shí)時(shí)間,而2PC只有協(xié)調(diào)者才擁有超時(shí)機(jī)制。這解決了一個(gè)什么問題呢?這個(gè)優(yōu)化點(diǎn),主要是避免了參與者在長時(shí)間無法與協(xié)調(diào)者節(jié)點(diǎn)通訊(協(xié)調(diào)者掛掉了)的情況下,無法釋放資源的問題,因?yàn)閰⑴c者自身擁有超時(shí)機(jī)制會(huì)在超時(shí)后,自動(dòng)進(jìn)行本地commit從而進(jìn)行釋放資源。而這種機(jī)制也側(cè)面降低了整個(gè)事務(wù)的阻塞時(shí)間和范圍。

      ? 另外,通過CanCommit、PreCommit、DoCommit三個(gè)階段的設(shè)計(jì),相較于2PC而言,多設(shè)置了一個(gè)緩沖階段保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的。

      ? 以上就是3PC相對(duì)于2PC的一個(gè)提高(相對(duì)緩解了2PC中的前兩個(gè)問題),但是3PC依然沒有完全解決數(shù)據(jù)不一致的問題。假如在 DoCommit 過程,參與者A無法接收協(xié)調(diào)者的通信,那么參與者A會(huì)自動(dòng)提交,但是提交失敗了,其他參與者成功了,此時(shí)數(shù)據(jù)就會(huì)不一致。

      c) AT模式

      ? AT 模式是一種無侵入的分布式事務(wù)解決方案。在 AT 模式下,用戶只需關(guān)注自己的“業(yè)務(wù) SQL”,用戶的 “業(yè)務(wù) SQL” 作為一階段,Seata 框架會(huì)自動(dòng)生成事務(wù)的二階段提交和回滾操作。

      ? 在一階段,Seata 會(huì)攔截“業(yè)務(wù) SQL”,首先解析 SQL 語義,找到“業(yè)務(wù) SQL”要更新的業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)被更新前,將其保存成“before image”,然后執(zhí)行“業(yè)務(wù) SQL”更新業(yè)務(wù)數(shù)據(jù),在業(yè)務(wù)數(shù)據(jù)更新之后,再將其保存成“after image”,最后生成行鎖。以上操作全部在一個(gè)數(shù)據(jù)庫事務(wù)內(nèi)完成,這樣保證了一階段操作的原子性。

      ? 把業(yè)務(wù)數(shù)據(jù)在更新前后的數(shù)據(jù)鏡像組織成回滾日志,將業(yè)務(wù)數(shù)據(jù)的更新和回滾日志在同一個(gè)本地事務(wù)中提交,分別插入到業(yè)務(wù)表和 UNDO_LOG 表中。

      ? 二階段如果是提交的話,因?yàn)椤皹I(yè)務(wù) SQL”在一階段已經(jīng)提交至數(shù)據(jù)庫, 所以 Seata 框架只需將一階段保存的快照數(shù)據(jù)和行鎖刪掉,完成數(shù)據(jù)清理即可;

      ? 二階段如果是回滾的話,Seata 就需要回滾一階段已經(jīng)執(zhí)行的“業(yè)務(wù) SQL”,還原業(yè)務(wù)數(shù)據(jù)。回滾方式便是用“before image”還原業(yè)務(wù)數(shù)據(jù);但在還原前要首先要校驗(yàn)臟寫,對(duì)比“數(shù)據(jù)庫當(dāng)前業(yè)務(wù)數(shù)據(jù)”和 “after image”,如果兩份數(shù)據(jù)完全一致就說明沒有臟寫,可以還原業(yè)務(wù)數(shù)據(jù),如果不一致就說明有臟寫,出現(xiàn)臟寫就需要轉(zhuǎn)人工處理;

      ? AT 模式的一階段、二階段提交和回滾均由 Seata 框架自動(dòng)生成,用戶只需編寫“業(yè)務(wù) SQL”,便能輕松接入分布式事務(wù),AT 模式是一種對(duì)業(yè)務(wù)無任何侵入的分布式事務(wù)解決方案。但AT模式存在的不足就是當(dāng)操作的數(shù)據(jù)是共享型數(shù)據(jù),會(huì)存在臟寫的問題,所以如果是用戶獨(dú)有數(shù)據(jù)可以使用AT模式。

      d)TCC模式

      ? TCC方案其實(shí)是兩階段提交的一種改進(jìn)。分成了Try、Confirm、Cancel三個(gè)操作。事務(wù)發(fā)起方在一階段執(zhí)行 Try 方式,在二階段提交執(zhí)行 Confirm 方法,二階段回滾執(zhí)行 Cancel 方法。

      • Try部分完成業(yè)務(wù)的準(zhǔn)備工作
      • confirm部分完成業(yè)務(wù)的提交
      • cancel部分完成事務(wù)的回滾

      TCC 模式,不依賴于底層數(shù)據(jù)資源的事務(wù)支持:

      ? 一階段 prepare 行為:調(diào)用 自定義 的 prepare 邏輯。

      ? 二階段 commit 行為:調(diào)用 自定義 的 commit 邏輯。

      ? 二階段 rollback 行為:調(diào)用 自定義 的 rollback 邏輯。

      用戶接入 TCC 模式,最重要的事情就是考慮如何將業(yè)務(wù)模型拆成 2 階段,實(shí)現(xiàn)成 TCC 的 3 個(gè)方法,并且保證 Try 成功 Confirm 一定能成功。相對(duì)于 AT 模式,TCC 模式對(duì)業(yè)務(wù)代碼有一定的侵入性,但是 TCC 模式無 AT 模式的全局行鎖,TCC 性能會(huì)比 AT 模式高很多。

      e)SAGA模式

      ? Saga模式是SEATA提供的長事務(wù)解決方案,在Saga模式中,業(yè)務(wù)流程中每個(gè)參與者都提交本地事務(wù),當(dāng)出現(xiàn)某一個(gè)參與者失敗則補(bǔ)償前面已經(jīng)成功的參與者,一階段正向服務(wù)和二階段補(bǔ)償服務(wù)都由業(yè)務(wù)開發(fā)實(shí)現(xiàn)。

      ? 分布式事務(wù)執(zhí)行過程中,依次執(zhí)行各參與者的正向操作,如果所有正向操作均執(zhí)行成功,那么分布式事務(wù)提交。如果任何一個(gè)正向操作執(zhí)行失敗,那么分布式事務(wù)會(huì)退回去執(zhí)行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務(wù)回到初始狀態(tài)。

      ? Saga 正向服務(wù)與補(bǔ)償服務(wù)也需要業(yè)務(wù)開發(fā)者實(shí)現(xiàn)。因此是業(yè)務(wù)入侵的。

      ? Saga 模式下分布式事務(wù)通常是由事件驅(qū)動(dòng)的,各個(gè)參與者之間是異步執(zhí)行的,Saga 模式是一種長事務(wù)解決方案。

      使用場(chǎng)景

      ? Saga 模式適用于業(yè)務(wù)流程長且需要保證事務(wù)最終一致性的業(yè)務(wù)系統(tǒng),Saga 模式一階段就會(huì)提交本地事務(wù),無鎖、長流程情況下可以保證性能。

      ? 事務(wù)參與者可能是其它公司的服務(wù)或者是遺留系統(tǒng)的服務(wù),無法進(jìn)行改造和提供 TCC 要求的接口,可以使用 Saga 模式。

      1. 補(bǔ)償事務(wù)(Compensating Transaction):補(bǔ)償事務(wù)模式基于"撤銷"操作來實(shí)現(xiàn)事務(wù)的回滾。當(dāng)某個(gè)步驟發(fā)生錯(cuò)誤時(shí),可以通過執(zhí)行逆向操作來恢復(fù)數(shù)據(jù)的一致性。
      2. Saga模式:Saga是一種基于微服務(wù)架構(gòu)的分布式事務(wù)處理模式,通過一系列局部事務(wù)來完成分布式事務(wù)。每個(gè)局部事務(wù)都有一個(gè)補(bǔ)償操作,用于回滾之前的操作。
      3. TCC模式(Try-Confirm-Cancel):TCC是一種基于業(yè)務(wù)邏輯的分布式事務(wù)解決方案。在TCC中,每個(gè)參與者需要實(shí)現(xiàn)Try、Confirm和Cancel三個(gè)操作,分別對(duì)應(yīng)事務(wù)的嘗試階段、確認(rèn)階段和取消階段。

      f)總結(jié)

      ? 四種分布式事務(wù)模式,分別在不同的時(shí)間被提出,每種模式都有它的適用場(chǎng)景:

      ? AT 模式是無侵入的分布式事務(wù)解決方案,適用于不希望對(duì)業(yè)務(wù)進(jìn)行改造的場(chǎng)景,幾乎0學(xué)習(xí)成本。

      ? TCC 模式是高性能分布式事務(wù)解決方案,適用于核心系統(tǒng)等對(duì)性能有很高要求的場(chǎng)景。

      ? Saga 模式是長事務(wù)解決方案,適用于業(yè)務(wù)流程長且需要保證事務(wù)最終一致性的業(yè)務(wù)系統(tǒng),Saga 模式一階段就會(huì)提交本地事務(wù),無鎖,長流程情況下可以保證性能,多用于渠道層、集成層業(yè)務(wù)系統(tǒng)。事務(wù)參與者可能是其它公司的服務(wù)或者是遺留系統(tǒng)的服務(wù),無法進(jìn)行改造和提供 TCC 要求的接口,也可以使用 Saga 模式。

      ? XA模式是分布式強(qiáng)一致性的解決方案,但性能低而使用較少。

      3)seata

      a)介紹

      ? seata是一款開源的分布式事務(wù)解決方案,致力于提供高性能和簡單易用的分布式事務(wù)服務(wù)。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案。

      image

      TC (Transaction Coordinator) - 事務(wù)協(xié)調(diào)者
      維護(hù)全局和分支事務(wù)的狀態(tài),驅(qū)動(dòng)全局事務(wù)提交或回滾。

      TM (Transaction Manager) - 事務(wù)管理器
      定義全局事務(wù)的范圍:開始全局事務(wù)、提交或回滾全局事務(wù)。

      RM (Resource Manager) - 資源管理器
      管理分支事務(wù)處理的資源,與TC交談以注冊(cè)分支事務(wù)和報(bào)告分支事務(wù)的狀態(tài),并驅(qū)動(dòng)分支事務(wù)提交或回滾

      b)數(shù)據(jù)庫和業(yè)務(wù)層

      seata_order.sql

      DROP TABLE IF EXISTS `order_tbl`;
      CREATE TABLE `order_tbl`  (
        `id` int NOT NULL AUTO_INCREMENT,
        `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
        `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
        `count` int NULL DEFAULT 0,
        `money` int NULL DEFAULT 0,
        PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
      
      INSERT INTO `order_tbl` VALUES (1, '1', 'product-1', 1, 5);
      INSERT INTO `order_tbl` VALUES (9, '1', 'product-1', 1, 5);
      INSERT INTO `order_tbl` VALUES (10, '1', 'product-1', 1, 5);
      
      DROP TABLE IF EXISTS `undo_log`;
      CREATE TABLE `undo_log`  (
        `id` bigint NOT NULL AUTO_INCREMENT,
        `branch_id` bigint NOT NULL,
        `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
        `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
        `rollback_info` longblob NOT NULL,
        `log_status` int NOT NULL,
        `log_created` datetime NOT NULL,
        `log_modified` datetime NOT NULL,
        `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
        PRIMARY KEY (`id`) USING BTREE,
        UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
      

      seata_stock.sql

      DROP TABLE IF EXISTS `stock_tbl`;
      CREATE TABLE `stock_tbl`  (
        `id` int NOT NULL AUTO_INCREMENT,
        `commodity_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
        `count` int NULL DEFAULT 0,
        PRIMARY KEY (`id`) USING BTREE,
        UNIQUE INDEX `commodity_code`(`commodity_code`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
      
      INSERT INTO `stock_tbl` VALUES (1, 'product-1', 100000);
      INSERT INTO `stock_tbl` VALUES (2, 'product-2', 0);
      
      DROP TABLE IF EXISTS `undo_log`;
      CREATE TABLE `undo_log`  (
        `id` bigint NOT NULL AUTO_INCREMENT,
        `branch_id` bigint NOT NULL,
        `xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
        `context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
        `rollback_info` longblob NOT NULL,
        `log_status` int NOT NULL,
        `log_created` datetime NOT NULL,
        `log_modified` datetime NOT NULL,
        `ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
        PRIMARY KEY (`id`) USING BTREE,
        UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE
      ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
      

      ? 分別創(chuàng)建order-server, stock-server兩個(gè)服務(wù);

      ? order-server: get請(qǐng)求 , /order/insert , 新增一條訂單, 往數(shù)據(jù)庫中新增一條數(shù)據(jù), 同時(shí)遠(yuǎn)程調(diào)用stock-server中的/stock減庫存,;

      ? stock-server: put請(qǐng)求, /stock, 接收傳入過來的對(duì)象信息, 減去庫存;

      業(yè)務(wù)邏輯代碼省略
      

      c)seata-server配置

      ? 腳本和配置準(zhǔn)備:

      ? image

      ? nacos中創(chuàng)建seata的命名空間

      ? image

      執(zhí)行腳本

      使用git命令行打開,并且執(zhí)行腳本:

      sh nacos-config.sh -h 127.0.0.1 -p 8848 -g seata -t 命名空間的id -u nacos -w nacos
      

      腳本執(zhí)行完后, 配置的信息都導(dǎo)入到了nacos中:

      image

      修改seata的配置文件

      image

      啟動(dòng)seata-server

      d)業(yè)務(wù)服務(wù)的配置

      導(dǎo)入依賴

      <dependency>
      			<groupId>com.alibaba.cloud</groupId>
      			<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
      		</dependency>
      

      seata配置(***)

      #配置當(dāng)前事務(wù)的組名  必須和nacos中的service.vgroupMapping后面的值一直(下圖)
      seata.tx-service-group=my_test_tx_group
      #配置分組服務(wù)的mapping的值, 必須和nacos中service.vgroupMapping.****的值一直
      seata.service.vgroup-mapping.my_test_tx_group=default
      #設(shè)置事務(wù)分組對(duì)應(yīng)的seata服務(wù)地址  seata.service.grouplist后面的default和上面配置的值要相同
      seata.service.grouplist.default=127.0.0.1:8091
      

      image

      image

      e)測(cè)試

      在業(yè)務(wù)方法中手動(dòng)添加異常, 觀察事務(wù)的回滾過程;

      11 微服務(wù)鏈路追蹤

      在微服務(wù)架構(gòu)下,系統(tǒng)的功能是由大量的微服務(wù)協(xié)調(diào)組成的,例如:電商創(chuàng)建訂單業(yè)務(wù)就需要訂單服務(wù)、庫存服務(wù)、支付服務(wù)、短信通知服務(wù)逐級(jí)調(diào)用才能完成。而每個(gè)服務(wù)可能是由不同的團(tuán)隊(duì)進(jìn)行開發(fā),部署在成百上千臺(tái)服務(wù)器上。

      image

      如此復(fù)雜的消息傳遞過程,當(dāng)系統(tǒng)發(fā)生故障的時(shí)候,就需要一種機(jī)制對(duì)故障點(diǎn)進(jìn)行快速定位,確認(rèn)是哪個(gè)服務(wù)出了問題,鏈路追蹤技術(shù)由此而生。所謂的鏈路追蹤,就是運(yùn)行時(shí)通過某種方式記錄下服務(wù)之間的調(diào)用過程,在通過可視化的 UI 界面幫研發(fā)運(yùn)維人員快速定位到出錯(cuò)點(diǎn)。引入鏈路追蹤,是微服務(wù)架構(gòu)運(yùn)維的底層基礎(chǔ),沒有它,運(yùn)維人員就像盲人摸象一樣,根本無法了解服務(wù)間通信過程。

      1)Sleuth+Zipkin

      在 Spring Cloud 標(biāo)準(zhǔn)生態(tài)下內(nèi)置了 Sleuth 這個(gè)組件,它通過擴(kuò)展 Logging 日志的方式實(shí)現(xiàn)微服務(wù)的鏈路追蹤。說起來比較晦澀,咱們看一個(gè)實(shí)例就明白了,在標(biāo)準(zhǔn)的微服務(wù)下日志產(chǎn)生的格式是:

      2021-01-12 17:00:33.441 INFO [nio-7000-exec-2] c.netflix.config.ChainedDynamicProperty  : Flipping property: b-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
      

      但是當(dāng)引入 Spring Cloud Sleuth 鏈路追蹤組件后就會(huì)變成下面的格式:

      2021-01-12 17:00:33.441  INFO [a-service,5f70945e0eefa832,5f70945e0eefa832,true] 18404 --- [nio-7000-exec-2] c.netflix.config.ChainedDynamicProperty  : Flipping property: b-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
      //比較后會(huì)發(fā)現(xiàn),在原有日志中額外附加了下面的文本
      [a-service,5f70945e0eefa832,5f70945e0eefa832,true]
      

      這段文本就是 Sleuth 在微服務(wù)日志中附加的鏈路調(diào)用數(shù)據(jù),它的格式是固定的,包含以下四部分:

      [微服務(wù) Id,TraceId,SpanId,isExport]

      image

      鏈路追蹤數(shù)據(jù)的組成

      微服務(wù) Id: 說明日志是由哪個(gè)微服務(wù)產(chǎn)生的。

      TraceId: 軌跡編號(hào)。一次完整的業(yè)務(wù)處理過程被稱為軌跡,例如:實(shí)現(xiàn)登錄功能需要從服務(wù) A 調(diào)用服務(wù) B,服務(wù)B再調(diào)用服務(wù) C,那這一次登錄處理的過程就是一個(gè)軌跡,從前端應(yīng)用發(fā)來請(qǐng)求到接收到響應(yīng),每一次完整的業(yè)務(wù)功能處理過程都對(duì)應(yīng)唯一的 TraceId。

      SpanId,步驟編號(hào)。剛才要實(shí)現(xiàn)登錄功能需要從服務(wù) A 到服務(wù) C 涉及 3 個(gè)微服務(wù)處理,按處理前后順序,每一個(gè)微服務(wù)處理時(shí)日志都被賦予不同的 SpanId。一個(gè) TraceId 擁有多個(gè) SpanId,而 SpanId 只能隸屬于某一個(gè) TraceId。

      導(dǎo)出標(biāo)識(shí),當(dāng)前這個(gè)日志是否被導(dǎo)出,該值為 true 的時(shí)候說明當(dāng)前軌跡數(shù)據(jù)允許被其他鏈路追蹤可視化服務(wù)收集展現(xiàn)。

      下面我們看一個(gè)完整的追蹤數(shù)據(jù)實(shí)例:

      模擬了服務(wù) A -> 服務(wù) B -> 服務(wù) C的調(diào)用鏈路,下面是分別產(chǎn)生的日志

      #服務(wù) A 應(yīng)用控制臺(tái)日志
      2021-01-12 22:16:54.394 DEBUG [a-service,e8ca7047a782568b,e8ca7047a782568b,true] 21320 --- [nio-7000-exec-1] org.apache.tomcat.util.http.Parameters   : ...
      #服務(wù) B 應(yīng)用控制臺(tái)日志
      2021-01-12 22:16:54.402 DEBUG [b-service,e8ca7047a782568b,b6aa80fb33e71de6,true] 21968 --- [nio-8000-exec-2] org.apache.tomcat.util.http.Parameters   : ...
      #服務(wù) C 應(yīng)用控制臺(tái)日志
      2021-01-12 22:16:54.405 DEBUG [c-service,e8ca7047a782568b,537098c59827a242,true] 17184 --- [nio-9000-exec-2] org.apache.tomcat.util.http.Parameters   : ...
      

      可以發(fā)現(xiàn),在 DEBUG 級(jí)別下鏈路追蹤數(shù)據(jù)被打印出來,按調(diào)用時(shí)間先后順序分別是 A 到 C 依次出現(xiàn)。因?yàn)槭且淮瓮暾麡I(yè)務(wù)處理,TraceId 都是相同的,SpanId 卻各不相同,這些日志都已經(jīng)被 Sleuth 導(dǎo)出,可以被 ZipKin 收集展示。

      Zipkin 是 推特的一個(gè)開源項(xiàng)目,它能收集各個(gè)服務(wù)實(shí)例上的鏈路追蹤數(shù)據(jù)并可視化展現(xiàn)。剛才 ABC 服務(wù)控制臺(tái)產(chǎn)生的日志在 ZipKin 的 UI 界面中會(huì)以鏈路追蹤圖表的形式展現(xiàn)。

      <dependency>
      			<groupId>org.springframework.cloud</groupId>
      			<artifactId>spring-cloud-starter-zipkin</artifactId>
      		</dependency>
      		<dependency>
      			<groupId>org.springframework.cloud</groupId>
      			<artifactId>spring-cloud-starter-sleuth</artifactId>
      		</dependency>
      
      spring:
          sleuth:
              sampler:
                  probability: 1.0
                  rate: 100
          zipkin:
              base-url: http://localhost:9411
      
      posted @ 2024-07-26 20:48  二價(jià)亞鐵  閱讀(377)  評(píng)論(1)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲精品一二三四区| 一区二区三区av在线观看| 高清精品一区二区三区| 国产精品人成视频免费播放| 亚洲国产成人精品无色码| 欧美一级黄色影院| 无码精品人妻一区二区三区中| 国产精一品亚洲二区在线播放| 亚洲激情一区二区三区视频| 暖暖免费观看电视在线高清| 久久中文字幕一区二区| 亚洲欧美人成人让影院| 欧美怡春院一区二区三区| 中国xxx农村性视频| 国产午夜亚洲精品福利| av一区二区中文字幕| 精品无码一区在线观看| 亚洲精品国产字幕久久麻豆| 高清一区二区三区不卡视频| 一区二区丝袜美腿视频| 色综合久久久久综合体桃花网| 热久久这里只有精品99| 成人午夜电影福利免费| 国产精品福利自产拍久久| 亚洲一区二区三区久久受| 亚洲中文字幕在线精品一区| 亚洲国产日韩一区三区| 熟女精品视频一区二区三区| 精品人妻中文字幕有码在线 | 无遮无挡爽爽免费视频| 亚洲精品久久久久久久久久吃药| 日韩三级一区二区在线看| 欧美日韩精品一区二区视频| 精品少妇人妻av无码久久| 免费观看成人毛片a片| 国产精品日日摸夜夜添夜夜添无码 | 18禁国产一区二区三区| 漂亮的保姆hd完整版免费韩国| 亚洲sm另类一区二区三区| 亚洲日韩性欧美中文字幕| 污网站在线观看视频|