內容概述
spring cloud的各種組件
Feign 聲明式服務調用【掌握】
Hystrix 熔斷器【掌握】
Gateway 網關【掌握】
每個組件都是爲了解決微服務系統中的問題的。
一、Feign-概述
疑問: spring cloud遠程調用還是讓人覺得不好用,能不能像dubbo那樣,直接調用遠程的方法?
• Feign 是一個聲明式的 REST 客戶端,它用了基於接口的註解方式,很方便實現客戶端配置。
• Feign 最初由 Netflix 公司提供。eureka也是Netflix 公司
二、Feign-快速入門
疑問: 如何使用feign客戶端進行遠程調用?
操作步驟:
- 在消費端feign-consumer 引入 open-feign 依賴
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- Feign是基於ribbon負載均衡的,使用前必須有ribbon配置。編寫Feign調用接口
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
/**
*
* feign聲明式接口。發起遠程調用的。
*
String url = "http://FEIGN-PROVIDER/goods/findOne/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
*
* 1. 定義接口
* 2. 接口上添加註解 @FeignClient,設置value屬性爲 服務提供者的 應用名稱
* 3. 編寫調用接口,接口的聲明規則 和 提供方接口保持一致。
* 4. 注入該接口對象,調用接口方法完成遠程調用
*
*/
@FeignClient(value = "FEIGN-PROVIDER")
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
- 在啓動類 添加 @EnableFeignClients 註解,開啓Feign功能
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients //開啓Feign的功能
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
- controller 調用
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private GoodsFeignClient goodsFeignClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
Goods goods = goodsFeignClient.findGoodsById(id);
return goods;
}
}
- 測試調用
http://localhost:9000/order/goods/1
三、Feign-超時配置 先配置熔斷才行
疑問:遠程調用,連接或者業務處理慢,超時了會有什麼現象?
• Feign 底層依賴於 Ribbon 實現負載均衡和遠程調用。
• Ribbon默認1秒超時。
超時會報錯ReadTimeout,我們可以根據業務進行設置。
配置方式:
#配置熔斷的時間監聽
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
# 設置Ribbon的超時時間
ribbon:
ConnectTimeout: 1000 # 連接超時時間 默認1s
ReadTimeout: 3000 # 邏輯處理的超時時間 默認1s
四、Feign-日誌記錄
疑問:遠程調用都被feign給封裝了,如何才能看到請求,響應的細節,數據?
分析:
配置feign的日誌記錄
操作步驟:
- 設置當前日誌的級別爲debug
# 設置當前的日誌級別 debug,feign只支持記錄debug級別的日誌
logging:
level:
cn.kinggm520: debug #調用了feign客戶端所在代碼的包名
- 定義Feign日誌級別Bean
@Configuration
public class FeignLogConfig {
/*
NONE,不記錄
BASIC,記錄基本的請求行,響應狀態碼數據
HEADERS,記錄基本的請求行,響應狀態碼數據,記錄響應頭信息
FULL;記錄完成的請求 響應數據
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
- 啓動Feign日誌級別Bean
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
- 測試
http://localhost:9000/order/goods/1
五、Hystrix 熔斷器-概述
• Hystix 是 Netflix 開源的一個延遲和容錯庫,用於隔離訪問遠程服務、第三方庫,防止出現級聯失敗(雪崩)。
• 雪崩:一個服務失敗,導致整條鏈路的服務都失敗的情形。
Hystix 主要功能
• 隔離
-
線程池隔離
-
信號量隔離
• 降級:異常,超時
• 熔斷
• 限流
總結: 主要解決服務器出現意外以後,應用該如何處理。
六、Hystrix 降級-服務提供方
疑問: 服務提供方何時會降級,如何編寫代碼?
分析:
服務提供方何時會降級?
兩種情況:
-
服務端代碼拋異常
-
服務端代碼超時(默認1秒鐘)
Hystrix 降級 – 服務提供方
操作步驟:
- 在服務提供方,引入 hystrix 依賴
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 在啓動類上開啓Hystrix功能:@EnableCircuitBreaker
/**
* 啓動類
*/
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker // 開啓Hystrix功能
public class ProviderApp {
- 定義降級方法
/**
* 定義降級方法:
* 1. 方法的返回值需要和原方法一樣
* 2. 方法的參數需要和原方法一樣
* 3. 就是隻有方法名不同
*/
public Goods findOne_fallback(int id){
Goods goods = new Goods();
goods.setTitle("降級了~~~");
return goods;
}
- 使用 @HystrixCommand 註解配置降級方法
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback")
public Goods findOne(@PathVariable("id") int id){
。。。
}
- 如果要設置降級配置的屬性,可以通過@HystrixCommand註解的commandProperties屬性進行配置,配置的信息在HystrixCommandProperties類中定義。瞭解常用設置即可。
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//設置Hystrix的超時時間,默認1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findOne(@PathVariable("id") int id){
總結:
定義的降級方法要和controller方法完全一致,除了方法名。通過fallbackMethod指定降級方法,只需要設置方法名即可,不要帶括號什麼的。
七、Hystrix 降級 – 服務消費方
疑問:那要是網絡有問題,都不能連上提供方,還能降級嗎?
分析:
Hystrix 降級 – 服務消費方
操作步驟:
- feign 組件已經集成了 hystrix 組件。
- 在application.yml中配置開啓 feign.hystrix.enabled = true
# 開啓feign對hystrix的支持
feign:
hystrix:
enabled: true
- 定義feign 調用接口實現類,複寫方法,即 降級方法
/**
* Feign 客戶端的降級處理類
* 1. 定義類 實現 Feign 客戶端接口
* 2. 使用@Component註解將該類的Bean加入SpringIOC容器
*/
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
@Override
public Goods findGoodsById(int id) {
Goods goods = new Goods();
goods.setTitle("又被降級了~~~");
return goods;
}
}
- 在 @FeignClient 註解中使用 fallback 屬性設置降級處理類。
@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
總結:
注意編寫的調用方降級類需要實現Feign客戶端的接口,還要添加@Component註解交給spring容器管理。
問題:如果服務器端程序拋出異常,那麼提供方還是消費方的降級方法生效?
提供方生效,因爲提供方降級後,將會給消費方返回了正常的結果,所以消費方就不會生效。
問題
服務處理的時間過長,但是不想因爲超時降級,還需要得到服務器的結果,如何配置?
配置兩個方面:
- feign客戶端調用的時候 先配置熔斷超時
#配置熔斷的時間監聽
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
# 設置Ribbon的超時時間
ribbon:
ConnectTimeout: 1000 # 連接超時時間 默認1s
ReadTimeout: 3000 # 邏輯處理的超時時間 默認1s
- 服務提供方降級的時間
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//設置Hystrix的超時時間,默認1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findOne(@PathVariable("id") int id){
八、Hystrix 熔斷-概念
Hystrix 熔斷機制,用於監控微服務調用情況,當失敗的情況達到預定的閾值(5秒失敗20次),會打開斷路器,拒絕所有請求,直到服務恢復正常爲止。
總結:
熔斷的目的是爲了保護系統。全自動,不需要干預。
三種狀態之間的切換
- 關閉到打開。失敗降級的次數達到閾值。默認5秒失敗20次。
- 打開到半開。持續5秒鐘。半開:(允許一半的請求通過)
- 半開到關閉。通過的請求成功超過80%
九、Hystrix 熔斷-代碼演示
分析:
熔斷是Hystrix 自動的機制,只要使用了Hystrix ,就可以進行系統的熔斷保護。
所以我們做這個實驗,只需要讓我們的代碼發生降級就可以。
需求: 讓我們的請求ID爲1的時候拋出異常,引發降級。
hystrix-provider的GoodsController中進行設置:
public Goods findOne(@PathVariable("id") int id){
//如果id == 1 ,則出現異常,id != 1 則正常訪問
if(id == 1){
//1.造個異常
int i = 3/0;
}
可以通過@HystrixCommand註解的commandProperties屬性進行配置:
@GetMapping("/findOne/{id}")
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//設置Hystrix的超時時間,默認1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//監控時間 默認5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失敗次數。默認20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失敗率 默認50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
public Goods findOne(@PathVariable("id") int id){
十、Hystrix -熔斷監控
分析:
Hystrix 熔斷監控
• Hystrix 提供了 Hystrix-dashboard 功能,用於實時監控微服務運行狀態。
• 但是Hystrix-dashboard只能監控一個微服務。
• Netflix 還提供了 Turbine ,進行聚合監控。
搭建Turbine 聚合監控的步驟:
SpringCloud-資料\day02\資料\1. turbine 搭建\Turbine搭建步驟.md
總結: 瞭解內容,面試能把Turbine 名字說出來就可以。
十一、Gateway 網關-概述
疑問: 什麼是網關?幹什麼用的?
分析:
定義:
• 網關旨在爲微服務架構提供一種簡單而有效的統一的API路由管理方式。
• 在微服務架構中,不同的微服務可以有不同的網絡地址,各個微服務之間通過互相調用完成用戶請求,客戶端可能通過調用N個微服務的接口完成一個用戶請求。
• 存在的問題:
• 客戶端多次請求不同的微服務,增加客戶端的複雜性
• 認證複雜,每個服務都要進行認證
• http請求不同服務次數增加,性能不高
• 網關就是系統的入口,封裝了應用程序的內部結構,爲客戶端提供統一服務,一些與業務本身功能無關的公共邏輯可以在這裏實現,諸如認證、鑑權、監控、緩存、負載均衡、流量管控、路由轉發等
• 在目前的網關解決方案裏,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等
總結: 網關也是一個應用,有了網關之後,我們所有的請求都訪問網關應用,由網關幫我們去調用其他服務。
網關幹什麼用?主要功能有兩個:
-
路由
-
過濾
十二、Gateway 網關-快速入門
疑問:如何來使用Gateway 網關?
需求:使用Gateway 網關來路由轉發請求
操作步驟:
- 搭建網關模塊,導入資料中的初始化代碼
其實就是創建一個最基本的spring cloud模塊。
- 引入依賴:starter-gateway
<dependencies>
<!--引入gateway 網關-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
- 編寫啓動類,無特殊操作
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class,args);
}
}
- 編寫配置文件
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 網關配置
gateway:
# 路由配置:轉發規則
routes: #集合。
# id: 唯一標識。默認是一個UUID
# uri: 轉發路徑
# predicates: 條件,用於請求網關路徑的匹配規則
- id: gateway-provider
uri: http://localhost:8001/
predicates:
- Path=/goods/**
- id: gateway-cum
uri: http://localhost:9000/
predicates:
- Path=/orders/**
- 啓動測試
訪問網關應用: http://localhost/goods/findOne/2
十三、Gateway 網關-靜態路由
疑問: 什麼是靜態路由?
就是轉發的地址是固定的。在開發中不便於維護,不使用。知道概念就可以。
分析:
配置:
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 網關配置
gateway:
# 路由配置:轉發規則
routes: #集合。
# id: 唯一標識。默認是一個UUID
# uri: 轉發路徑
# predicates: 條件,用於請求網關路徑的匹配規則
# filters:配置局部過濾器的
- id: gateway-provider
# 靜態路由
uri: http://localhost:8001/
predicates:
- Path=/goods/**
- id: gateway-consumer
uri: http://localhost:9000
predicates:
- Path=/order/**
# 微服務名稱配置
十四、Gateway 網關-動態路由
疑問:靜態路由的缺點是什麼?什麼是動態路由?有什麼用
分析:
靜態路由的缺點是什麼?
靜態路由,在網關中uri的配置是寫死的,不便於維護。
什麼是動態路由?有什麼用?
讓網關應用能夠從註冊中心Eureka中,動態的通過應用的名稱來獲取應用的地址
配置方式:
- 添加依賴(之前已經完成)
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 啓動類添加註解(之前已經完成)
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
- 配置動態路由
- id: gateway-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
總結: 爲網關添加Eureka客戶端依賴,能夠從註冊中心發現服務。在配置路由的uri時,通過lb://服務名稱 來獲取轉發服務器的地址信息。
十五、Gateway 網關 – 微服務名稱配置
疑問: 網關路由轉發的應用很多,名稱容易衝突,如何進行方便的區分?
分析:
將Eureka註冊中心裏應用的名稱作爲uri中的前綴來區分不同的應用。
配置:
spring:
application:
name: api-gateway-server
cloud:
# 網關配置
gateway:
discovery:
locator:
enabled: true # 設置爲true 請求路徑前可以添加微服務名稱
lower-case-service-id: true # 允許爲小寫
測試:
訪問網關應用: http://localhost/goods/findOne/2
也可以: http://localhost/gateway-provider/goods/findOne/2
十六、Gateway 網關 – 過濾器-概述
過濾器
• Gateway 支持過濾器功能,對請求或響應進行攔截,完成一些通用操作。
• Gateway 提供兩種過濾器方式:“pre”和“post”
• pre 過濾器,在轉發之前執行,可以做參數校驗、權限校驗、流量監控、日誌輸出、協議轉換等。
• post 過濾器,在響應之前執行,可以做響應內容、響應頭的修改,日誌的輸出,流量監控等。
• Gateway 還提供了兩種類型過濾器
• GatewayFilter:局部過濾器,針對單個路由
• GlobalFilter :全局過濾器,針對所有路由
十七、Gateway 網關 – 局部過濾器
局部過濾器
• GatewayFilter 局部過濾器,是針對單個路由的過濾器。
• 在Spring Cloud Gateway 組件中提供了大量內置的局部過濾器,對請求和響應做過濾操作。
• 遵循約定大於配置的思想,只需要在配置文件配置局部過濾器名稱,併爲其指定對應的值,就可以讓其生效。
參考資料: SpringCloud-資料\day02\資料\2. gateway內置過濾器工廠
配置:
# filters:配置局部過濾器的
- id: gateway-provider
# 靜態路由
# uri: http://localhost:8001/
# 動態路由
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters:
- AddRequestParameter=username,zhangsan
總結:
根據文檔中的過濾器的作用和名稱進行配置,過濾的參數和值之間使用,逗號分隔。
十八、Gateway 網關 – 全局過濾器
全局過濾器
• GlobalFilter 全局過濾器,不需要在配置文件中配置,系統初始化時加載,並作用在每個路由上。
• Spring Cloud Gateway 核心的功能也是通過內置的全局過濾器來完成。
• 自定義全局過濾器步驟:
- 定義類實現 GlobalFilter 和 Ordered接口
- 複寫方法
- 完成邏輯處理
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定義全局過濾器執行了~~~");
//獲取web應用的對象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
return chain.filter(exchange);//放行
}
/**
* 過濾器排序
* @return 數值越小 越先執行
*/
@Override
public int getOrder() {
return 0;
}
}
總結:
自定義全局過濾器無需配置,只需要實現接口中的方法就可以。
自定義的過濾器需要添加@Component交給spring容器管理。