springCloud第三課(Hystrix監控平台、DashBoard、Turbine監控、熔斷器的狀态、微服務網關Zuul))
上文回顧
上文我們實作了hystrix的熔斷降級,我們知道,當請求失敗,被拒絕,逾時的時候,都會進入到降級方法中。但進入降級方法并不意味着斷路器已經被打開。那麼如何才能了解斷路器中的狀态呢?
上文連結
項目源碼gitee:gitee位址
一、Hystrix的監控平台
除了實作容錯功能,Hystrix還提供了近乎實時的監控,HystrixCommand和HystrixObservableCommand在執行時,會生成執行結果和運作名額。比如每秒的請求數量,成功數量等。這些狀态會暴露在Actuator提供的/health端點中。
隻需為項目添加 spring-boot-actuator 依賴,重新開機項目,通路http://localhost:9013/actuator/hystrix.stream ,即可看到實時的監控資料。
搭建Hystrix監控平台
引入jar包
這個不出意外的話,在之前健康檢查時就已經引入了。
重新開機服務
通路測試一下 發現根本通路不到,這裡其實有個坑,要在yml檔案中配置一下如下
配置yml檔案
management:
endpoints:
web:
exposure:
include: '*'
再次重新開機服務
再次請求
發現它一直ping,然後請求一個服務
搭建Hystrix DashBoard監控
剛剛讨論了Hystrix的監控,但通路/hystrix.stream接口擷取的都是以文字形式展示的資訊。很難通過文字直覺的展示系統的運作狀态,是以Hystrix官方還提供了基于圖形化的DashBoard(儀表闆)監控平台。Hystrix儀表闆可以顯示每個斷路器(被 @HystrixCommand
注解的方法)的狀态。
導入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
添加注解
在啟動類使用
@EnableHystrixDashboard
注解激活儀表盤項目
重新開機服務
重新開機服務,通路測試
将之前的通路的連接配接輸入到監控連接配接裡面,如下圖 然後點選按鈕進入
然後通路服務一個測試
注意:Hystrix儀表闆可以顯示每個斷路器(被
@HystrixCommand
注解的方法)的狀态,未被添加注解的方法無法監控。
二、斷路器聚合監控Turbine
在微服務架構體系中,每個服務都需要配置Hystrix DashBoard監控。如果每次隻能檢視單個執行個體的監控資料,就需要不斷切換監控位址,這顯然很不友善。要想看這個系統的Hystrix Dashboard資料就需要用到Hystrix
Turbine。Turbine是一個聚合Hystrix 監控資料的工具,他可以将所有相關微服務的 Hystrix監控資料聚合到一起,友善使用。引入Turbine後,整個監控系統架構如下:
搭建ebuy-turbine
建立一個springboot項目
過程略
引入jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--turbine監控平台-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<!--hystrix熔斷 (因為監控平台隻監控hystrix監控的方法)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--監控 文本資料顯示-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
配置多個微服務的hystrix監控
在application.yml的配置檔案中開啟turbine并進行相關配置
server:
port: 8031 #端口
spring:
application:
name: ebuy-turbine #服務名稱
logging:
level:
cn.ebuy: DEBUG
eureka:
client:
service-url:
# 叢集配置多個,單機配置一個
defaultZone: http://127.0.0.1:9880/eureka/,http://127.0.0.1:9890/eureka/
instance:
prefer-ip-address: true #使用ip位址注冊
lease-expiration-duration-in-seconds: 10 #eureka client 發送心跳給server端,續約到期時間(預設90秒)
lease-renewal-interval-in-seconds: 5 #發送心跳續約時間間隔
turbine:
cluster-name-expression: "'default'"
app-config: ebuy-order
注:# 要監控的微服務清單,多個用,分隔
- eureka相關配置 : 指定注冊中心位址
-
turbine相關配置:指定需要監控的微服務清單
turbine會自動的從注冊中心中擷取需要監控的微服務,并聚合所有微服務中的 /hystrix.stream 資料
配置啟動類
- 作為一個獨立的監控項目,需要配置啟動類,開啟HystrixDashboard監控平台,并激活Turbine
測試
浏覽器通路 http://localhost:8031/hystrix 展示HystrixDashboard。
并在url位置輸入 http://localhost:8031/turbine.stream(文本資料),http://localhost:8031/hystrix(監控平台),動态根據turbine.stream資料展示多個微服務的監控資料
輸入需要監控的微服務位址
這樣turbine監控微服務平台便是搭建完成了。
三、熔斷器的狀态
回顧一下
回顧一下上面的情況,當product停止服務時,請求order服務,order由于請求不到product而熔斷,如下圖
正常未停止product微服務時: 停止product微服務: 請求order服務,發生熔斷
上圖可以看出監控平台顯示服務狀态是failure失敗,而非Short-Circuited熔斷,那這是為什麼呢???
熔斷器狀态
熔斷器有三個狀态、
CLOSED
、
OPEN
熔斷器預設關閉狀态,當觸發熔斷後狀态變更為
HALF_OPEN
,在等待到指定的時間,Hystrix會放請求檢測服務是否開啟,這期間熔斷器會變為 HALF_OPEN 半開啟狀态,熔斷探測服務可用則繼續變更為
OPEN
關閉熔斷器。
CLOSED
Closed:關閉狀态(斷路器關閉),所有請求都正常通路。代理類維護了最近調用失敗的次數,如果某次調用失敗,則使失敗次數加1。如果最近失敗次數超過了在給定時間内允許失敗的門檻值,則代理類切換到斷開(Open)狀态。此時代理開啟了一個逾時時鐘,當該時鐘超過了該時間,則切換到半斷開(Half-Open)狀态。該逾時時間的設定是給了系統一次機會來修正導緻調用失敗的錯誤。
Open:打開狀态(斷路器打開),所有請求都會被降級(熔斷兜底)。Hystix會對請求情況計數,當一定時間
内失敗請求百分比達到門檻值,則觸發熔斷,斷路器會完全關閉。預設失敗比例的門檻值是50%,請求次數最少不低于20次。
Half Open:半開狀态,open狀态不是永久的,打開後會進入休眠時間(預設是5S)。随後斷路器會自動進入半開狀态。此時會釋放1次請求通過,若這個請求是健康的,則會關閉斷路器,否則繼續保持打開,再次進行5秒休眠計時。
測試之前的準備
為了能夠精确控制請求的成功或失敗,我們在一下代碼做調整 注:這樣如果參數是id為816753,一定成功,其它情況都失敗。
我們準備兩個請求視窗:
- 成功請求:http://localhost:9013/order/hystrix/816753
- 不成功請求:http://localhost:9013/order/hystrix/1
熔斷器的預設觸發門檻值是20次請求,不好觸發。休眠時間時5秒,時間太短,不易觀察,為了測試友善,我們可以通過配置修改熔斷政策:
circuitBreaker.requestVolumeThreshold=5
circuitBreaker.sleepWindowInMilliseconds=10000
circuitBreaker.errorThresholdPercentage=50
- requestVolumeThreshold:觸發熔斷的最小請求次數,預設20
- errorThresholdPercentage:觸發熔斷的失敗請求最小占比,預設50%
- sleepWindowInMilliseconds:熔斷多少秒後去嘗試請求
- 然後重新開機服務
開始測試
熔斷器處于關閉狀态
- 請求正确的服務
- 服務仍是關閉狀态
- 請求錯誤的服務,但是請求次數小于5次
- 服務仍是關閉狀态
- 請求錯誤的服務,次數大于5次 - 此時熔斷器的狀态變為開啟狀态,進入休眠時間(5秒)
熔斷器處于打開狀态
- 在熔斷器進入開啟狀态之後不到5s内請求正确的服務
- 發現正确的服務也被熔斷處理
- 在熔斷器進入開啟狀态之後不到5s内請求錯誤的服務
總結:熔斷器處于開啟狀态下,所有服務都會被降級處理。
熔斷器處于半開狀态
- 熔斷器進入開啟狀态之後5s,進入半開狀态
- 此時請求正确的服務 - 服務正常傳回,并且熔斷器狀态變為關閉
- 熔斷器進入開啟狀态之後5s,進入半開狀态
- 此時請求錯誤的服務
- 熔斷器狀态變為開啟狀态,進入5秒休眠期
注意:為了友善了解,可以根據上述的熔斷器狀态流程圖來分析
四、微服務網關
在學習完前面的知識後,微服務架構已經初具雛形。但還有一些問題:不同的微服務一般會有不同的網絡位址,用戶端在通路這些微服務時必須記住幾十甚至幾百個位址,這對于用戶端方來說太複雜也難以維護。如下圖:
如果讓用戶端直接與各個微服務通訊,可能會有很多問題:
- 用戶端會請求多個不同的服務,需要維護不同的請求位址,增加開發難度
- 在某些場景下存在跨域請求的問題
- 加大身份認證的難度,每個微服務需要獨立認證
是以,我們需要一個微服務網關,介于用戶端與伺服器之間的中間層,所有的外部請求都會先經過微服務網關。用戶端隻需要與網關互動,隻知道一個網關位址即可,這樣簡化了開發還有以下優點:
- 易于監控
- 易于認證
- 減少了用戶端與各個微服務之間的互動次數
服務網關的概念
什麼是微服務網關
API網關是一個伺服器,是系統對外的唯一入口。API網關封裝了系統内部架構,為每個用戶端提供一個定制的API。API網關方式的核心要點是,所有的用戶端和消費端都通過統一的網關接入微服務,在網關層處理所有的非業務功能。通常,網關也是提供REST/HTTP的通路API。服務端通過API-GW注冊和 管理服務。
作用和應用情景
網關具有的職責,如身份驗證、監控、負載均衡、緩存、請求分片與管理、靜态響應處理。當然,最主要的職責還是與“外界聯系”。
常見的API網關實作方式
- Kong
基于Nginx+Lua開發,性能高,穩定,有多個可用的插件(限流、鑒權等等)可以開箱即用。問題:隻支援Http協定;二次開發,自由擴充困難;提供管理API,缺乏更易用的管控、配置方式。
- Zuul
Netflix開源,功能豐富,使用JAVA開發,易于二次開發;需要運作在web容器中,如Tomcat。問題:缺乏管控,無法動态配置;依賴元件較多;處理Http請求依賴的是Web容器,性能不如Nginx;
- Traefik
Go語言開發;輕量易用;提供大多數的功能:服務路由,負載均衡等等;提供WebUI 問題:二進制檔案部署,二次開發難度大;UI更多的是監控,缺乏配置、管理能力;
- Spring Cloud Gateway
SpringCloud提供的網關服務
- Nginx+lua實作
使用Nginx的反向代理和負載均衡可實作對api伺服器的負載均衡及高可用 問題:自注冊的問題和網關本身的擴充性
基于Nginx的網關實作
Nginx介紹
正向/反向代理
正向代理
正向代理,“它代理的是用戶端,代用戶端送出請求”,是一個位于用戶端和原始伺服器(origin server)之間的伺服器,為了從原始伺服器取得内容,用戶端向代理發送一個請求并指定目标(原始伺服器),然後代理向原始伺服器轉交請求并将獲得的内容傳回給用戶端。用戶端必須要進行一些特别的設定才能使用正向代理。
反向代理
多個用戶端給伺服器發送的請求,Nginx伺服器接收到之後,按照一定的規則分發給了後端的業務處理伺服器進行處理了。此時~請求的來源也就是用戶端是明确的,但是請求具體由哪台伺服器處理的并不明确了,Nginx扮演的就是一個反向代理角色。用戶端是無感覺代理的存在的,反向代理對外都是透明的,通路者并不知道自己通路的是一個代理。因為用戶端不需要任何配置就可以通路。反向代理,“它代理的是服務端,代服務端接收請求”,主要用于伺服器叢集分布式部署的情況下,反向代理隐 藏了伺服器的資訊,如果隻是單純的需要一個最基礎的具備轉發功能的網關,那麼使用Ngnix是一個不錯的選擇。
微服務網關Zuul
Zuul簡介
ZUUL是Netflix開源的微服務網關,它可以和Eureka、Ribbon、Hystrix等元件配合使用,Zuul元件的核心是一系列的過濾器,這些過濾器可以完成以下功能:
- 動态路由:動态将請求路由到不同後端叢集
- 壓力測試:逐漸增加指向叢集的流量,以了解性能
- 負載配置設定:為每一種負載類型配置設定對應容量,并棄用超出限定值的請求
- 靜态響應處理:邊緣位置進行響應,避免轉發到内部叢集
-
身份認證和安全: 識别每一個資源的驗證要求,并拒絕那些不符的請求。Spring Cloud對Zuul進行
了整合和增強。
搭建Zuul網關伺服器
建立工程導入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--zuul網關的jar-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
編寫啟動類
- @EnableZuulProxy : 通過 @EnableZuulProxy 注解開啟Zuul網管功能
編寫配置
- 建立配置檔案 application.yml ,并添加相應配置
server:
port: 9090 #端口
spring:
application:
name: ebuy-zuul #服務名稱
logging:
level:
cn.ebuy: DEBUG
Zuul中的路由轉發
最直覺的了解:“路由”是指根據請求URL,将請求配置設定到對應的處理程式。在微服務體系中,Zuul負責接收所有的請求。根據不同的URL比對規則,将不同的請求轉發到不同的微服務處理。
對應的配置
zuul:
routes:
ebuy-order: #隻是個在這個配置檔案中的節點名字這裡是路由id,随意寫
path: /ebuy-order/** # 映射路徑
url: http://127.0.0.1:9013/ # 映射路徑對應的實際url位址
sensitive-Headers: #預設zuul會屏蔽cookie,cookie不會傳到下遊服務,這裡設定為空則取
消預設的黑名單,如果設定了具體的頭資訊則不會傳到下遊服務
ebuy-product:
path: /ebuy-product/**
url: http://127.0.0.1:9015/
sensitive-Headers:
例子: path: /ebuy-order001/** # 映射路徑
位址欄通路 :http://localhost:9090/ebuy-order001/order/hystrix/816753
啟動測試
- 啟動服務
- 通路測試
面向服務的路由
微服務一般是由幾十、上百個服務組成,對于一個URL請求,最終會确認一個服務執行個體進行處理。如果對每個服務執行個體手動指定一個唯一通路位址,然後根據URL去手動實作請求比對,這樣做顯然就不合理。
Zuul支援與Eureka整合開發,根據ServiceID自動的從注冊中心中擷取服務位址并轉發請求,這樣做的好處不僅可以通過單個端點來通路應用的所有服務,而且在添加或移除服務執行個體的時候不用修改Zuul的路由配置。
添加Eureka用戶端依賴
改造上述的項目
添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
添加Eureka用戶端發現功能
添加Eureka配置,擷取服務資訊
- Eureka配置
# Eureka配置
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9890/eureka/,http://127.0.0.1:9880/eureka
lease-expiration-duration-in-seconds: 10 #eureka client發送心跳給server端後,續約到期時間(預設90秒)
lease-renewal-interval-in-seconds: 5 #發送心跳續約時間間隔
registry-fetch-interval-seconds: 5 # 擷取服務清單的周期:5s
instance:
prefer-ip-address: true # 使用ip位址註冊
- zuul面向服務的路由配置
因為已經有了Eureka用戶端,我們可以從Eureka擷取服務的位址資訊,是以映射時無需指定IP位址,而是通過服務名稱來通路,而且Zuul已經內建了Ribbon的負載均衡功能。
zuul:
routes:
ebuy-order:
path: /ebuy-order/**
serviceId: ebuy-order #配置轉發的微服務名稱
ebuy-product:
path: /ebuy-product/**
serviceId: ebuy-product #配置轉發的微服務名稱
注:serviceId: 指定需要轉發的微服務執行個體名稱
通路測試
- 重新開機服務,開始測試
- 可以看出zuul已經實作了負載均衡
簡化的路由配置
在剛才的配置中,我們的規則是這樣的:
-
: 來指定映射路徑。zuul.routes.<route>.path=/xxx/**
是自定義的路由名。<route>
-
zuul.routes.<route>.serviceId=/product-service
:來指定服務名。
而大多數情況下,我們的
路由名稱往往和服務名會寫成一樣的。是以Zuul就提供了一種簡化的配置文法:<route>
上面的配置可以簡化為一條:zuul.routes.<serviceId>=<path>
zuul:
routes:
ebuy-product: /ebuy-product/** #第一個ebuy-product是指服務名,第二個是位址欄要輸入的映射路徑
ebuy-order: /ebuy-order/**
重新開機服務測試
不再截圖展示
發現問題
- 模拟高并發情況下的問題
- 重新開機,然後再次使用zuul的路徑通路服務
- 發現提示
com.netflix.zuul.exception.ZuulException: Hystrix Readed time out
回顧之前我們配置,可以給zuul配置如下(注意是ebuy-zuul項目)
ebuy-product:
ribbon:
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 2500 # Ribbon的連接配接逾時時間(建立連接配接時間:毫秒)
ReadTimeout: 5000 # Ribbon的資料讀取逾時時間 (得到資料的時間)
OkToRetryOnAllOperations: true # 是否對所有操作都進行重試
MaxAutoRetriesNextServer: 1 # 切換執行個體的重試次數
MaxAutoRetries: 1 # 對目前執行個體的重試次數 (1表示不重試自己)
ebuy-order:
ribbon:
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 2500 # Ribbon的連接配接逾時時間(建立連接配接時間:毫秒)
ReadTimeout: 5000 # Ribbon的資料讀取逾時時間 (得到資料的時間)
OkToRetryOnAllOperations: true # 是否對所有操作都進行重試
MaxAutoRetriesNextServer: 1 # 切換執行個體的重試次數
MaxAutoRetries: 1 # 對目前執行個體的重試次數 (1表示不重試自己)
- 然後重新開機配置
- 重新通路測試
- 問題解決(可以把ebuy-product的模拟所寫的線程休眠注釋掉了)
預設的路由規則
在使用Zuul的過程中,上面講述的規則已經大大的簡化了配置項。但是當服務較多時,配置也是比較繁瑣的。是以Zuul就指定了預設的路由規則:
- 預設情況下,一切服務的映射路徑就是服務名本身。
- 例如服務名為: ebuy-product ,則預設的映射路徑就是: /ebuy-product/**
那麼到底是什麼意思呢?
意思就是說上述的路由配置是完全不需要的(當然前提是你的通路路徑想要和應用名同名)
- 注釋掉路由相關的配置
- 通路服務測試
- 通路完全沒問題