配置中心(SpringCloud config)
註冊中心(SpringCloud netflix eurka)
API網關(SpringCloud netflix zuul)
1、SpringCloud Alibaba簡介
Spring Cloud Alibaba 致力於提供微服務開發的一站式解決方案。此項目包含開發分佈式應用服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕鬆使用這些組件來開發分佈式應用服務。
依託 Spring Cloud Alibaba,您只需要添加一些註解和少量配置,就可以將 Spring Cloud 應用接入阿里分佈式應用解決方案,通過阿里中間件來迅速搭建分佈式應用系統。
SpringCloud Alibaba Github地址
-
SpringCloud的幾大缺點
1.部分組件停止維護和更新給開發帶來不便(eurka)
2.部分環境搭建複雜,沒有完善的可視化界面,需要大量的二次開發
3.配置複雜難上手部分配置差別較細 -
SpringCloud Alibaba的優點
阿里使用的組件經過實際考驗,性能強悍,設計合理,開源成套的產品搭配完善的可視化界面給開發和運維帶來極大便利,且搭建簡單,學習難度低。 -
結合SpringCloud Alibaba項目的最終的技術搭配方案
-
spring-cloud-alibaba版本的選擇,見
SpringCloud Alibaba Github地址 -
在父項目pom文件中引入一
<!-- dependencyManagement實際不引用依賴只提供版本號與scope信息 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1.1.spring Cloud Alibaba Nacos
- 安裝 Alibaba Nacos server
下載Nacous Server並解壓(這裏爲了方便我們放到本地window系統),運行bin/startup.cmd即可啓動Nacous Server服務
http://127.0.0.1:8848/nacos訪問服務
1.1.1 discovery(註冊中心)
- common模塊引入依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 在應用的配置文件中配置服務名和Nacos Server 地址,
spring:
application:
name: wwmall-product
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
- 啓動類標註@EnableDiscoveryClient即可將服務註冊到nacous註冊中心
1.1.2Config(配置中心)
1.1.2.1簡單示例
- common模塊導入依賴,引入 Nacos Config Starter
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 在應用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 元數據
#該文件會優先於application.yml/application.properties加載
spring.application.name=wwmall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
- 給配置中心默認添加一個數據集(Data Id的規則爲:應用名.properties。例如wwmall-coupon.properties)
- 將需要的配置文件寫在數據集中併發布,即可動態獲取
- 動態獲取:使用@RefreshScope(動態獲取或刷新配置)和@Value("${配置項的名}")(獲取配置)
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
/*---------------------測試代碼start----------------------------------------------*/
@Value("${coupon.user.name}")
private String username;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){
return R.ok().put("username",username).put("age",age);
}
注:如果配置中心和當前應用的配置文件中由相同的項,則優先使用配置中心中的配置信息
1.1.2.2 命名空間與配置分組
- 命名空間(Namespace):可用於進行不同環境的配置隔離。一般一個環境劃分到一個命名空間
默認的public爲保留空間,默認新增的所有配置都在public空間
1.在不同的環境(開發、測試、生產)利用命名空間來做環境隔離可以在bootstrap.properties配置需要使用哪個命名空間下的配置
2.每一個微服務之間互相隔離,每個微服務創建自己的命名空間,只加載自己命名空間下的所有配置
#指定使用的命名空間
spring.cloud.nacos.config.namespace=ad0d2241-8cfc-4c30-a83f-1bd2c72eb62d
- 配置分組(Group):配置分組用於將不同的服務可以歸類到同一分組。一般將一個項目的配置分到一組
默認所有的配置集都屬於DEFAULT_GRUOP
在bootstrap.properties中使用指定命名空間下的指定配置分組:
#指定使用的命名空間
spring.cloud.nacos.config.namespace=ad0d2241-8cfc-4c30-a83f-1bd2c72eb62d
#指定使用的分組
spring.cloud.nacos.config.group=dev
- 配置集(Data ID):在系統中,一個配置文件通常就是一個配置集。一般微服務的配置就是一個配置集
本項目採用:每個微服務創建自己的命名空間,使用配置分組區分環境(desv,test,prod)
1.1.2.3加載多配置文件
配置文件不會全寫在application.yml中會根據配置項分出多個配置集,我們關心在nacos中如何加載多個配置集
將配置文件拆分成多個datasource.yml,mybatis.yml,other.yml並在配置中心創建對應的配置集
- 在bootstrap.properties說明加載配置中心中指定的配置集組
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
#開啓動態刷新
spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true
spring.cloud.nacos.config.extension-configs[2].data-id=other.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true
- @value @configrationProperties等以前在springboot中能從配置文件中獲取值的現在也可以使用。
注:配置中心有的優先從配置中心取,沒有的話就去項目的application.properties文件中取
1.1.3Nacos持久化
https://www.cnblogs.com/larscheng/p/11422909.html
1.2spring Cloud Alibaba sentinel
1.2.1什麼是熔斷降級限流
熔斷
降級
兩者相同點
兩者不同點
限流
對打入服務的請求流量進行控制,使服務能承擔不超過自己的流量壓力
1.2.2sentinel簡介
隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
官方文檔 https://github.com/alibaba/spring-cloud-alibaba/wiki
整合springboot/springcolud https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
Sentinel 分爲兩個部分:
核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。
資源
資源是 Sentinel 的關鍵概念。它可以是 Java 應用程序中的任何內容,例如,由應用程序提供的服務,或由應用程序調用的其它應用提供的服務,甚至可以是一段代碼。在接下來的文檔中,我們都會用資源來描述代碼塊。
只要通過 Sentinel API 定義的代碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作爲資源名來標示資源。
規則
圍繞資源的實時狀態設定的規則,可以包括流量控制規則、熔斷降級規則以及系統保護規則。所有規則可以動態實時調整。
控制檯
Sentinel 控制檯提供一個輕量級的控制檯,它提供機器發現、單機資源實時監控、集羣資源彙總,以及規則管理的功能。您只需要對應用進行簡單的配置,就可以使用這些功能。
1.2.3spring boot 整合sentinel
引入依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
下載,啓動,配置控制檯
下載地址 https://github.com/alibaba/Sentinel/releases 命令java -jar 啓動
配置控制檯
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8080
在控制檯設置流控設置即可,設置的留空規則是保存在內存中的,重啓就會失效
兩個問題
- 控制檯的實時監控沒有數據(使用endpoint支持)?
1.在服務中導入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.修改springboot配置
#允許 Endpoints 的訪問。
management.endpoints.web.exposure.include=*
- 請求限流的自定義提示,資源控制
@RestController
public class TestController {
// blockHandler 函數,原方法調用被限流/降級/系統保護的時候調用
@SentinelResource(blockHandler = "blockHandlerForGetUser", fallback = "blockHandlerForGetUser")
@RequestMapping("/hello")
public String hello(String id) {
return "Hello Sentinel";
}
public String blockHandlerForGetUser(String id,BlockException exception) {
System.out.println(id+"--------------------");
return id+"訪問頻繁...";
}
}
1.2.4流控規則
流控模式:鏈路 假設現在需要流控的資源名C,設置A爲請求入口,有一個請求A調用了B調用了C,那麼只有請求只有入口爲A落到C的請求才被流控,從其他入口調用C都不會被流控
流控模式:關聯 當兩個資源之間具有資源爭搶或者依賴關係的時候,這兩個資源便具有了關聯。流控資源爲C 關聯資源爲A,當C被流控時也流控A
1.2.5熔斷降級
使用sentinel來保護feign遠程調用,熔斷
調用方的熔斷保護
引入依賴spring-cloud-starter-alibaba-sentinel,spring-cloud-starter-openfeign
配置文件配置:feign.sentinel.enabled=true
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfiguration {
@Bean
public EchoServiceFallback echoServiceFallback() {
return new EchoServiceFallback();
}
}
class EchoServiceFallback implements EchoService {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
調用方控制檯手動指定遠程服務的降級策略,遠程服務被降級處理會觸發我們的熔斷回掉方法
超大流量的時候必須犧牲一下遠程服務,在服務的提供方指定降級策略.提供方是在執行方法,但是執行自己的業務邏輯,返回的是默認的降級數據(限流的數據)
1.2.6自定義受保護資源
1.拋出異常的方式定義資源
// 資源名可使用任意有業務語義的字符串,比如方法名、接口名或其它可唯一標識的字符串。
try (Entry entry = SphU.entry("resourceName")) {
// 被保護的業務邏輯
// do something here...
} catch (BlockException ex) {
// 資源訪問阻止,被限流或被降級
// 在此處進行相應的處理操作
}
2.註解方式定義資源
注意 blockHandler 函數會在原方法被限流/降級/系統保護的時候調用,而 fallback 函數會針對所有類型的異常。請注意 blockHandler 和 fallback 函數的形式要求,https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
// 原本的業務方法.
@SentinelResource(blockHandler = "blockHandlerForGetUser")
public User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函數,原方法調用被限流/降級/系統保護的時候調用
public User blockHandlerForGetUser(String id, BlockException ex) {
return new User("admin");
}
1.2.7網關層控制-不進入服務
引入依賴(sentinel與網關的整合版本與cloud alibaba吻合)-提供了自動配置,官方文檔給的依賴還需要編寫配置類
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
可以在配置文件中配置被限流降級的回調信息
使用代碼方式編寫回調操作
@Configuration
public class SentinelGatewayConfig {
public SentinelGatewayConfig(){
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Mono<ServerResponse> mono = ServerResponse.ok().body(Mono.just("網關限流降級"), String.class);
return mono;
}
});
}
}
1.2.8sentinel持久化
https://www.jianshu.com/p/609961eb6a6e
2.Spring cloud組件
2.1Feign(聲明式遠程調用)
Feign是聲明式的Http客戶端,它讓微服務之間的調用變得更簡單了,Fegin提供了Http請求的模板,通過編寫簡單的接口和插入註解,就可以定義好Http請求的參數、格式、地址等信息。
Spring Cloud Fegin集成了Ribbon(負載均衡),可在讓我們不在顯式的使用這個組件。
Spring Cloud openFegin在NetfilxFeign基礎上擴展了對SpringMVC註解的支持,在其實現下我們只需要創建一個接口並用註解的方式來配置它,即可完成對服務提供方的接口綁定,簡化了Spring Cloud Ribbon自行封裝服務調用客戶端的開發量。
- 引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
模仿會員(wwmall-member)模塊調用優惠券(wwmall-coupon)模塊
- 想要遠程調用coupon模塊的getCouponListByMemberId方法
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@RequestMapping("/member-coupon/couponList")
public R getCouponListByMemberId(String memberName){
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("五折優惠.....");
return R.ok().put("memberName",memberName).put("couponEntity",Arrays.asList(couponEntity));
}
- 在會員模塊編寫一個接口,使用@FeignClient註解告訴springcloud這個接口需要調用哪個遠程服務,聲明接口內的每一個方法是調用哪個遠程服務的哪個請求
package com.walkwind.wwmall.member.feign;
@FeignClient("wwmall-coupon")
public interface CouponFeignService {
@RequestMapping("/coupon/coupon/member-coupon/couponList")
public R getCouponListByMemberId(String memberName);
}
- 測試調用遠程接口業務代碼
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private MemberService memberService;
@Autowired
CouponFeignService couponFeignService;
@RequestMapping("/getCouponList")
public R getCouponList(){
R coupon = couponFeignService.getCouponListByMemberId("張三");
return coupon;
}
- 使用@EnableFeignClients在啓動類上註解開啓遠程調用功能
@SpringBootApplication
@EnableDiscoveryClient
//明確告訴fegin遠程調用接口處在哪個包下,不配置的話會自動掃描所有標註了@FeignClient("wwmall-coupon")的接口
@EnableFeignClients(basePackages="com.walkwind.wwmall.member.feign")
public class WwmallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(WwmallMemberApplication.class, args);
}
}
- 運行項目測試遠程調用功能(需開啓Nacos服務)
注:feign遠程調用傳遞參數是以json數據傳輸,只要屬性名對應就可以封裝到任意引用類型中,上例的張三傳遞失敗沒有實際業務意義,實際應用會創建一個to對象(從業務中抽取的實體類中的某些屬性組合成的對象,沒有實際意義只用於遠程調用接口數據傳輸的載體)
Fegin請求頭丟失問題
登錄後遠程調用請求頭數據cookie丟失
解決方法:fegin在調用之前要構造請求,調用很多的攔截器,我們可以加上fegin遠程調用的攔截器在請求進入後,獲取請求頭數據,將請求頭放入新的requestTemplate中。RequestContextHolder使用ThreadLocal去獲取原請求上下文信息
fegin異步情況丟失上下文問題
解決方法
在主方法中獲取老請求的請求頭數據,在創建的每個子線程類中爲請求頭放入數據
2.2gateway網關
1.簡介
網關作爲流量的入口,常用功能包括路由轉發、權限校驗、限流控制。springcloud gateway作爲springcloud官方推出的第二代網關框架,取代了zuul網關。
2.概念
Route(路由):這是網關的基本構建塊。它由一個 ID,一個目標 URI,一組斷言和一組過濾器定義。如果斷言爲真,則路由匹配。
Predicate(斷言):這是一個 Java 8 的 Predicate。輸入類型是一個 ServerWebExchange。我們可以使用它來匹配來自 HTTP 請求的任何內容,例如 headers 或參數。
Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的實例,我們可以使用它修改請求和響應。
3.工作原理
客戶端向 Spring Cloud Gateway 發出請求。然後在 Gateway Handler Mapping 中找到與請求相匹配的路由,將其發送到 Gateway Web Handler。Handler 再通過指定的過濾器鏈來將請求發送到我們實際的服務執行業務邏輯,然後返回。過濾器之間用虛線分開是因爲過濾器可能會在發送代理請求之前(“pre”)或之後(“post”)執行業務邏輯。
4.使用gateway
- 使用spring初始化嚮導創建wwmall-gateway模塊引入gateway組件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- 在pom文件中引入common模塊
注這裏應排除common工程中的mybatis依賴不然會報錯
<dependency>
<groupId>com.walkwind.wwmall</groupId>
<artifactId>wwmall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
- 將wwmall-gateway註冊到nacos中
1.開啓註冊發現服務功能
@EnableDiscoveryClient
2.配置文件中配置,服務註冊/發現中心地址
spring:
application:
name: wwmall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
3.在nacos中配置命名空間與配置集
4.配置文件中配置,配置中心信息及使用的命名空間信息
bootstrap.properties
spring.application.name=wwmall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=ac252e0f-5dc4-4a9c-9175-08937b6ddcd9
spring.cloud.nacos.config.name=wwmall-gateway.yml
spring.cloud.nacos.config.group=dev
5.配置網關路由信息
spring:
cloud:
nacos:
gateway:
routes:
- id: baidu_route
uri: https://www.baidu.com/
predicates:
- Path=/baidu
- id: qq_route
uri: https://www.qq.com
predicates:
- Path=/qq
更多路由配置參考說明文檔
2.3sleuth+zipkin服務鏈路追蹤
2.3.1.爲什麼用
2.3.2.基本術語
官方文檔:https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.2.2.RELEASE/reference/html/#introduction
2.3.3流程圖
服務調用業務
對應的流程
span之間的父子關係
2.3.4整合sleuth
2.3.5整合zipkin可視化觀察鏈路
界面分析