1. 程式人生 > 其它 >穀粒商城分散式基礎(二)——分散式元件SpringCloud & SpringCloud Alibaba

穀粒商城分散式基礎(二)——分散式元件SpringCloud & SpringCloud Alibaba

五、分散式元件SpringCloud Alibaba

1、SpringCloud Alibaba 簡介

1、簡介
    Spring Cloud Alibaba 致力於提供微服務開發的一站式解決方案。此專案包含開發分散式應用 微服務的必需元件,方便開發者通過 Spring Cloud 程式設計模型輕鬆使用這些元件來開發分佈 式應用服務。

    依託 Spring Cloud Alibaba,您只需要新增一些註解和少量配置,就可以將 Spring Cloud 應用 接入阿里微服務解決方案,通過阿里中介軟體來迅速搭建分散式應用系統。

    https://github.com/alibaba/spring-cloud-alibaba
2、為什麼使用
 (1)eureka、hystrix等元件停止維護


2)SpringCloud 的幾大痛點     
    SpringCloud 部分元件停止維護和更新,給開發帶來不便;     
    SpringCloud 部分環境搭建複雜,沒有完善的視覺化介面,我們需要大量的二次開發和定製     
    SpringCloud 配置複雜,難以上手,部分配置差別難以區分和合理應用
3)SpringCloud Alibaba 的優勢     阿里使用過的元件經歷了考驗,效能強悍,設計合理,現在開源出來大家用     成套的產品搭配完善的視覺化介面給開發運維帶來極大的便利     搭建簡單,學習曲線低。
4)結合 SpringCloud Alibaba 我們最終的技術搭配方案:
    SpringCloud Alibaba - Nacos:註冊中心(服務發現/註冊)
    SpringCloud Alibaba - Nacos:配置中心(動態配置管理)
    SpringCloud - Ribbon:負載均衡
    SpringCloud - Feign:宣告式 HTTP 客戶端(呼叫遠端服務)
    SpringCloud Alibaba - Sentinel:服務容錯(限流、降級、熔斷)
    SpringCloud - Gateway:API 閘道器(webflux 程式設計模式)
    SpringCloud 
- Sleuth:呼叫鏈監控     SpringCloud Alibaba - Seata:原 Fescar,即分散式事務解決方案
3、版本選擇
    由於 Spring Boot 1 和 Spring Boot 2 在 Actuator 模組的介面和註解有很大的變更,且 spring-cloud-commons 從 1.x.x 版本升級到 2.0.0 版本也有較大的變更,因此我們採取跟 SpringBoot 版本號一致的版本: 
     1.5.x 版本適用於 Spring Boot 1.5.x
     2.0.x 版本適用於 Spring Boot 2.0.x
     2.1.x 版本適用於 Spring Boot 2.1.x
4、搭配環境
 1)統一一下springboot的版本
    分別修改gulimall-coupon/member/order/product/ware 的pom.xml中springboot的版本號如下所示

 (2)引入springcloud的依賴

    修改gulimall-common的pom.xml檔案,新增如下依賴

<dependencyManagement>
<dependencies>
<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>
</dependencies>
</dependencyManagement>

2、SpringCloud Alibaba-Nacos 【作為註冊中心】

  Nacos 是阿里巴巴開源的一個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺。他是使用 java 編寫。需要依賴 java 環境   Nacos 文件地址: https://nacos.io/zh-cn/docs/quick-start.html
1、下載 nacos-server的Windows版本
  https://github.com/alibaba/nacos/releases
  nacos-server-1.1.3.zip:https://download.csdn.net/download/wu2374633583/12028032
  下載完成之後,直接解壓縮
2、啟動 nacos-server
 (1)雙擊 bin 中的 startup.cmd 檔案
 (2)訪問 http://localhost:8848/nacos/
 (3)使用預設的 nacos/nacos 進行登入
3、將微服務註冊到 nacos 中
 
1)修改gulimall-common的pom.xml,引入 Nacos Discovery Starter
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

(2)在gulimall-coupon(優惠券服務的)/src/main/resources/application.properties 配置檔案中配置 Nacos Server 地址
  spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

  (3)使用@EnableDiscoveryClient 開啟服務註冊發現功能

  (4)給服務起名稱,啟動服務,觀察 nacos 服務列表是否已經註冊上服務     注意:每一個應用都應該有名字,這樣才能註冊上去。修改 application.properties 檔案     spring.application.name=gulimall-coupon

  啟動後檢視 nacos-server ,發現gulimall-coupon已經註冊進服務列表了

  (5)總結nacos服務註冊使用三步

    1、導包 nacos-discovery     2、寫配置,指定 nacos 地址,指定應用的名字     3、開啟服務註冊發現功能@EnableDiscoveryClient

  (6)註冊更多的服務上去

    按照上述步驟將gulimall-member也註冊到nacos中

3、SpringCloud-OpenFeign【宣告式遠端呼叫】

  想要獲取當前會員領取到的所有優惠券。先去註冊中心找優惠券服務, 註冊中心調一臺優惠券伺服器給會員,會員伺服器傳送請求給這臺優 惠券伺服器,然後對方響應。

1、簡介
    Feign 是一個宣告式的 HTTP 客戶端,它的目的就是讓遠端呼叫更加簡單。Feign 提供了 HTTP 請求的模板,
通過編寫簡單的介面和插入註解,就可以定義好 HTTP 請求的引數、格式、地 址等資訊。
    Feign 整合了 Ribbon(負載均衡)和 Hystrix(服務熔斷),可以讓我們不再需要顯式地使用這 兩個元件。
    SpringCloudFeign 在 NetflixFeign 的基礎上擴充套件了對 SpringMVC 註解的支援,在其實現下,
我們只需建立一個介面並用註解的方式來配置它,即可完成對服務提供方的介面繫結。簡化了 SpringCloudRibbon 自行封裝服務呼叫客戶端的開發量
2、原理
3、OpenFeign測試遠端呼叫
    會員服務想要遠端呼叫優惠券服務,只需要給會員服務裡引入openfeign依賴,他就有了遠端呼叫其他服務的能力。
  Feign 使用三步
    1、導包 openfeign
    2、開啟@EnableFeignClients 功能
    3、編寫介面,進行遠端呼叫
 (1)gulimall-member(使用者服務)的pom.xml導包引入依賴,這樣會員服務就有了遠端呼叫其他服務的能力
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

 (2)gulimall-coupon(優惠券服務)建立被遠端呼叫的方法
  在gulimall-coupon(優惠券服務)的 CouponController 中修改如下內容
@RequestMapping("/member/list")
public R memberCoupons(){//全系統的所有返回都返回R
// 應該去資料庫查使用者對於的優惠券,但這個我們簡化了,不去資料庫查了,構造了一個優惠券給他返回
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("滿100減10");//優惠券的名字
return R.ok().put("coupons", Arrays.asList(couponEntity));
}
  這樣我們準備好了優惠券的呼叫內容
 (3)給gulimall-member(使用者服務)的主啟動類開啟 @EnableFeignClients 功能,並且設定遠端呼叫掃描的包

 (4)編寫介面,進行遠端呼叫
    那麼要呼叫什麼東西呢?就是我們剛才寫的優惠券的功能
    在gulimall-member(使用者服務)的 com.atguigu.gulimall.member.feign 包下新建優惠券遠端呼叫的feign介面
package com.atguigu.gulimall.member.feign;

import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

@Component
@FeignClient("gulimall-coupon")//告訴spring cloud這個介面是一個遠端客戶端,要呼叫coupon服務,再去呼叫coupon服務/coupon/coupon/member/list對應的方法
public interface CouponFeignService {

@RequestMapping("/coupon/coupon/member/list")
public R membercoupons();
}
 (5)編寫測試請求
    在gulimall-member(使用者服務)的控制層MemberController 寫一個測試請求
@RequestMapping("/coupons")
public R test(){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("張三");
R membercoupons = couponFeignService.membercoupons(); //假設張三去資料庫查了後返回了張三的優惠券資訊
// 列印會員和優惠券資訊
return R.ok().put("member",memberEntity).put("coupons",membercoupons.get("coupons"));
}

  (6)重新啟動服務

    http://localhost:8000/member/member/coupons

{"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"滿100減10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"張三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}

  (7)若遠端服務 gulimall-coupon 掉線宕機會咋樣?

    停掉gulimall-coupon(優惠券服務),觀察nacos-server和服務列表和介面響應

  nacos-server的gulimall-coupon健康例項數為0了,之後會被自動剔除。並且介面響應超時了

  我們重新啟動gulimall-coupon,優惠券服務重新上線之後,又完全恢復了

4、SpringCloud Alibaba-Nacos 【作為配置中心】

  我們還可以用nacos作為配置中心。配置中心的意思是不在application.properties 等檔案中配置了,而是放到nacos配置中心公用,這樣無需每臺機器都改。

1、使用步驟
 (1)匯入包依賴
  修改gulimall-common的pom.xml,引入 Nacos Config Starter
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
 (2)在gulimall-coupons專案中建立/src/main/resources/bootstrap.properties ,這個檔案是springboot裡規定的,他優先級別application.properties高
      spring.application.name=gulimall-coupon
      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
    在gulimall-coupons專案中建立/src/main/resources/application.properties
      coupon.user.name=zhangsan
      coupon.user.age=18
 (3)在gulimall-coupon(優惠券服務)的 CouponController 中新增如下內容
@Value("${coupon.user.name}")//從application.properties中獲取//不要寫user.name,他是環境裡的變數
private String name;
@Value("${coupon.user.age}")
private Integer age;

@RequestMapping("/test")
public R test(){
return R.ok().put("name",name).put("age",age);
}
 (4)重啟gulimall-coupon主啟動程式
      瀏覽器訪問 http://localhost:7000/coupon/coupon/test
      {"msg":"success","code":0,"name":"zhangsan","age":18}
    讀取到了application.properties檔案的內容
2、存在問題
    修改配置怎麼辦?實際生產中是不能修改application.properties重啟應用的
解決辦法:
    把配置交給配置中心nacos,之後只需要修改配置中心nacos即可
    我們發現專案啟動的時候預設去載入nacos資原始檔gulimall-coupon.properties,這說明如果我們的配置中心中有這麼一個配置,那麼裡面的配置也是可以獲取到的

    下面,我們來解決這個問題

  (1)nacos-server 瀏覽器設定nacos配置列表

    瀏覽器去nacos裡的配置列表,點選+號,data ID:gulimall-coupon.properties,配置gulimall-coupon.properties,然後點擊發布

  (2)gulimall-coupon對應控制層加上動態重新整理註解@RefreshScope

  (3)重啟gulimall-coupon,在nacos瀏覽器裡修改配置,修改就可以觀察到能動態修改了

    注意:nacos的配置內容優先於專案本地的配置內容。

3、總結:如何使用nacos作為配置中心統一管理配置

1)引入依賴
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
2建立一個bootstrap.properties
    spring.application.name=gulimall-coupon
    spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  
(3)nacos-server需要給配置中心預設新增一個叫 資料集(Data Id)gulimall-coupon.properties。預設規則:應用名.properties,給應用名.properties新增任何配置 
(4)動態獲取配置
@RefreshScope:動態獲取並重新整理配置
@Value("${配置項名}"):獲取到配置
之後每次修改瀏覽器nacos-server配置列表中配置檔案的資訊,不需要重啟專案,直接可動態獲取到nacos中修改後的最新的配置資訊
如果配置中心和當前應用的配置檔案中都配置了相同的項,優先使用配置中心的配置
4、核心概念
 (1)名稱空間:配置隔離
    預設:public(保留空間);預設新增的所有配置都在public空間
   (a)開發、測試、生產:利用名稱空間來做環境隔離
      注意:需要在bootstrap.properties 配置上,需要使用哪個名稱空間下的配置,若不配置,預設使用的是public
      spring.cloud.nacos.config.namespace=534e9b53-1a82-4c30-a258-5be306f7aa94

    (b)每一個微服務之間互相隔離配置,每一個微服務都建立自己的名稱空間,只加載自己名稱空間下的所有配置

 (2)配置集

  一組相關或者不相關的配置項的集合稱為配置集。在系統中,一個配置檔案通常就是一個配置集,包含了系統各個方面的配置。例如,一個配置集可能包含了資料來源、執行緒池、日誌級別等配置項。

 (3)配置集ID:類似檔名

  Nacos 中的某個配置集的 ID。配置集 ID 是組織劃分配置的維度之一。Data ID 通常用於組織劃分系統的配置集。一個系統或者應用可以包含多個配置集,每個配置集都可以被一個有意義的名稱標識。Data ID 通常採用類 Java 包(如 com.taobao.tc.refund.log.level)的命名規則保證全域性唯一性。此命名規則非強制。

 (4)配置分組

  預設所有的配置集都屬於:DEFAULT_GROUP

  每個微服務建立自己的名稱空間,使用配置分組區分環境,dev,test,prod

5、載入多配置集
  (1)微服務任何配置資訊,任何配置檔案都可以放在配置中心中
  (2)只需要在bootstrap.properties中說明載入配置中心中哪些配置檔案即可
  (3)@Value、@
ConfigurationProperties
    以前SpringBoot任何方法從配置檔案中獲取值,都能使用
    配置中心有的優先使用配置中心中的值
      我們嘗試將application.yml拆分成多個配置集,在nacos中配置多個yml,這個一拆分之後,其實之前的三個配置檔案只用保留bootstrap.properties檔案了


5、SpringCloud-OpenFeign【閘道器】

  傳送請求需要知道商品服務的地址,如果商品伺服器有100伺服器,1號掉線後, 還得改,所以需要閘道器動態地管理,他能從註冊中心中實時地感知某個服務上 線還是下線。

  請求也要加上詢問許可權,看使用者有沒有許可權訪問這個請求,也需要閘道器。

  所以我們使用spring cloud的gateway元件做閘道器功能。

1、簡介
(1)基本介紹 閘道器作為流量的入口,常用功能包括路由轉發、許可權校驗、限流控制等。而 springcloud gateway 作為 SpringCloud 官方推出的第二代閘道器框架,取代了 Zuul 閘道器。
  閘道器提供 API 全託管服務,豐富的 API 管理功能,輔助企業管理大規模的 API,以降低管理成本和安全風險,包括協議適配、協議轉發、安全策略、防刷、流量、監控日誌等功能。
  Spring Cloud Gateway 旨在提供一種簡單而有效的方式來對 API 進行路由,併為他們提供切面,例如:安全性,監控/指標 和彈性等。
  官方文件地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html

 (2)Spring Cloud Gateway特點

    基於 Spring5,支援響應式程式設計和 SpringBoot2.0

    支援使用任何請求屬性進行路由匹配

    特定於路由的斷言和過濾器

    整合 Hystrix 進行斷路保護

    整合服務發現功能

    易於編寫 Predicates 和 Filters

    支援請求速率限制

    支援路徑重寫

 (3)為什麼使用 API 閘道器

    API 網關出現的原因是微服務架構的出現,不同的微服務一般會有不同的網路地址,而外部客戶端可能需要呼叫多個服務的接口才能完成一個業務需求,如果讓客戶端直接與各個微服務通訊,會有以下的問題:

    (a)客戶端會多次請求不同的微服務,增加了客戶端的複雜性

    (b)存在跨域請求,在一定場景下處理相對複雜。

    (c)認證複雜,每個服務都需要獨立認證。

    (d)難以重構,隨著專案的迭代,可能需要重新劃分微服務。例如,可能將多個服務合併成一個或者將一個服務拆分成多個。如果客戶端直接與微服務通訊,那麼重構將會很難實施。

    (e)某些微服務可能使用了防火牆 / 瀏覽器不友好的協議,直接訪問會有一定的困難。

  以上這些問題可以藉助 API 閘道器解決。API 閘道器是介於客戶端和伺服器端之間的中間層,所有的外部請求都會先經過 API 閘道器這一層。也就是說,API 的實現方面更多的考慮業務邏輯,而安全、效能、監控可以交由 API 閘道器來做,這樣既提高業務靈活性又不缺安全性:使用 API 閘道器後的優點如下:     (a)易於監控。可以在閘道器收集監控資料並將其推送到外部系統進行分析。     (b)易於認證。可以在閘道器上進行認證,然後再將請求轉發到後端的微服務,而無須在每個微服務中進行認證。     (c)減少了客戶端與各個微服務之間的互動次數。
2、三大核心概念
 1)路由
    路由是閘道器最基礎的部分,路由資訊有一個 ID、一個目的 URL、一組斷言和一組 Filter 組成。如果斷言路由為真,則說明請求的 URL 和配置匹配
 (2)斷言
   Java8 中的斷言函式。Spring Cloud Gateway 中的斷言函式輸入型別是 Spring5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 中的斷言函式允許開發者去定義匹配
來自於 http request 中的任何資訊,比如請求頭和引數等。
 (3)過濾器
  一個標準的 Spring webFilter。Spring cloud gateway 中的 filter 分為兩種型別的Filter,分別是 Gateway Filter 和 Global Filter。
過濾器 Filter 將會對請求和響應進行修改處理

工作原理:

  客戶端傳送請求給閘道器,彎管 HandlerMapping 判斷是否請求滿足某個路由,滿足就發給閘道器的 WebHandler。這個 WebHandler 將請求交給一個過濾器鏈,請求到達目標服務之前,會執行所有過濾器的 pre 方法。請求到達目標服務處理之後再依次執行所有過濾器的 post 方法。

  一句話:滿足某些斷言(predicates)就路由到指定的地址(uri),使用指定的過濾器(filter)

3、使用
 目標:訪問http://localhost:88/?url=baidu 跳轉到百度, 訪問http://localhost:88/?url=qq 跳轉到qq
 (1)建立新Module:gulimall-gateway,選擇Spring Initializr

 (2)我們修改一下pom.xml,版本環境保持一致

 (3)引入公共依賴 gulimall-common

  gulimll-common中已經引入了服務的註冊發現和配置中心

<dependency>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

(4)@EnableDiscoveryClient註解開啟服務註冊發現
注意:由於引用了gulimall-common公共依賴,而common裡面引入了mybatis-plus,所以啟動後會報錯找不到資料來源,這裡我們使用exclude排除掉即可
  @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
(5)配置nacos註冊中心地址application.properties
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
server.port=88
  注意:nacos-server要啟動

(6)nacos-server裡建立名稱空間gateway,然後在gateway名稱空間裡建立檔案gulimall-gateway.yml

 (7)bootstrap.properties 填寫配置中心地址

spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=dd69061f-64b7-4d5c-9ce7-0106b856c70d

 (8)在專案裡建立application.yml配置閘道器路由資訊

spring:
cloud:
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu
- id: qq_route
uri: https://www.qq.com
predicates:
- Query=url,qq

 (9)啟動專案測試

    http://localhost:88/?url=baidu #跳轉到百度頁面

    http://localhost:88/?url=qq #跳轉到qq頁面