1 概述
1.1 分布式系統面臨的問題
複雜分布式體系結構中的應用程式有數十個依賴關系,每個依賴關系在某些時候将不可避免地失敗。
服務雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的“扇出”。如果扇出的鍊路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會占用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。
對于高流量的應用來說,單一的後端依賴可能會導緻所有伺服器上的所有資源都在幾秒鐘内飽和。比失敗更糟糕的是,這些應用程式還可能導緻服務之間的延遲增加,備份隊列,線程和其他系統資源緊張,導緻整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關系的失敗,不能取消整個應用程式或系統。
備注:一般情況對于服務依賴的保護主要有3中解決方案:
(1)熔斷模式:這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災。放到我們的系統中,如果某個目标服務調用慢或者有大量逾時,此時,熔斷該服務的調用,對于後續調用請求,不在繼續調用目标服務,直接傳回,快速釋放資源。如果目标服務情況好轉則恢複調用。
(2)隔離模式:這種模式就像對系統請求按類型劃分成一個個小島的一樣,當某個小島被火少光了,不會影響到其他的小島。例如可以對不同類型的請求使用線程池來資源隔離,每種類型的請求互不影響,如果一種類型的請求線程資源耗盡,則對後續的該類型請求直接傳回,不再調用後續資源。這種模式使用場景非常多,例如将一個服務拆開,對于重要的服務使用單獨伺服器來部署,再或者公司最近推廣的多中心。
(3)限流模式:上述的熔斷模式和隔離模式都屬于出錯後的容錯處理機制,而限流模式則可以稱為預防模式。限流模式主要是提前對各個類型的請求設定最高的QPS門檻值,若高于設定的門檻值則對該請求直接傳回,不再調用後續資源。這種模式不能解決服務依賴的問題,隻能解決系統整體資源配置設定問題,因為沒有被限流的請求依然有可能造成雪崩效應。
1.2 Hystrix是什麼?
Hystrix是一個用于處理分布式系統的延遲和容錯的開源庫,在分布式系統裡,許多依賴不可避免的會調用失敗,比如逾時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導緻整體服務失敗,避免級聯故障,以提高分布式系統的彈性。
“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向調用方傳回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者抛出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,進而避免了故障在分布式系統中的蔓延,乃至雪崩。
1.3 Hystrix主要作用
2.服務降級
備注:Hystrix服務降級,其實就是線程池中單個線程障處理,防止單個線程請求時間太長,導緻資源長期被占有而得不到釋放,進而導緻線程池被快速占用完,導緻服務崩潰。
Hystrix能解決如下問題:
1.請求逾時降級,線程資源不足降級,降級之後可以傳回自定義資料
2.線程池隔離降級,分布式服務可以針對不同的服務使用不同的線程池,進而互不影響
3.自動觸發降級與恢複
4.實作請求緩存和請求合并
2.服務熔斷
備注:熔斷模式:這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災。放到我們的系統中,如果某個目标服務調用慢或者有大量逾時,此時,熔斷該服務的調用,對于後續調用請求,不在繼續調用目标服務,直接傳回,快速釋放資源。如果目标服務情況好轉則恢複調用。
3.服務限流
備注:限流模式主要是提前對各個類型的請求設定最高的QPS門檻值,若高于設定的門檻值則對該請求直接傳回,不再調用後續資源。這種模式不能解決服務依賴的問題,隻能解決系統整體資源配置設定問題,因為沒有被限流的請求依然有可能造成雪崩效應。
4.接近實時的監控等等。
參考官方
2.服務熔斷
1.服務熔斷概念
服務熔斷
熔斷機制是應對雪崩效應的一種微服務鍊路保護機制。當扇對外連結路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速傳回"錯誤"的響應資訊。當檢測到該節點微服務調用響應正常後恢複調用鍊路。在SpringCloud架構裡熔斷機制通過Hystrix實作。Hystrix會監控微服務間調用的狀況,當失敗的調用到一定門檻值,預設是5秒内20次調用失敗就會啟動熔斷機制。熔斷機制的注解是@HystrixCommand。
2.操作如下
1、參考microservicecloud-provider-dept-8001,建立microservicecloud-provider-dept-hystrix-8001
2、修改pom.xml,添加Hystrix相關依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jiatp.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId>
<dependencies>
<dependency><!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
<groupId>com.jiatp.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 修改後立即生效,熱部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--添加到eureka用戶端 将provider注冊進去 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--springboot2.x之Actuator應用監控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
3.、YML配置
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置檔案所在路徑
type-aliases-package: com.jiatp.springcloud.entity # 掃描此包下的entity ->所有entity别名類所在包
mapper-locations:
- classpath:mybatis/mapper/**/*.xml # mapper映射檔案
spring:
application:
name: microservicecloud-dept # 很重要,對外暴露的微服務名字
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 資料源類型
driver-class-name: org.gjt.mm.mysql.Driver # 資料庫驅動包
url: jdbc:mysql://localhost:3306/cloudDB01?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone = GMT
username: root
password: 123456
dbcp2:
min-idle: 5 # 資料庫連接配接池的最小維持連接配接數
initial-size: 5 # 初始化連接配接數
max-idle: 5 # 最大連接配接數
max-wait-millis: 200 # 等待連接配接擷取的最大逾時時間
eureka:
client: # 用戶端注冊進eureka服務清單内
serviceUrl:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: microservicecloud-dept8001-hystrix # 自定義服務名稱資訊
prefer-ip-address: true # 通路路徑可以顯示IP位址
info:
app.name: jiatp-microservicecloud
company.name: www.jiatp.club
build.artifactId: $project.artifactId$
build.version: $project.version$
# actuator監控
management:
endpoints:
web:
exposure:
include: "*"
4、修改DeptController
@HystrixCommand報異常後如何處理
說明:一旦調用服務方法失敗并抛出了錯誤資訊後,會自動調用@HystrixCommand标注好的fallbackMethod調用類中的指定方法
5、修改主啟動類DeptProvider8001_Hystrix_App并添加新注解@EnableCircuitBreaker
package com.jiatp.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient //本服務啟動後會自動注冊進eureka服務中
@EnableDiscoveryClient //服務發現
@EnableCircuitBreaker//對hystrixR熔斷機制的支援
public class DeptProvider8001_Hystrix_App {
public static void main(String[] args) {
// provider 主啟動類
SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
}
}
測試:先啟動三個eureka注冊中心,再啟動帶有服務熔斷的provider即本服務,消費者Consumer啟動microservicecloud-consumer-dept-80,浏覽器位址通路:http://localhost/consumer/dept/get/112
如果ID:112,資料庫裡面沒有這個記錄,我們報錯後統一傳回。
3.服務降級
1、服務降級是什麼?
解釋:整體資源快不夠了,忍痛将某些服務先關掉,待渡過難關,再開啟回來。
注意:服務降級處理是在用戶端實作完成的,與服務端沒有關系
2、具體步驟
1、修改microservicecloud-api工程, 根據已經有的DeptClientService接口建立一個實作了 FallbackFactory接口的類DeptClientServiceFallbackFactory
package com.jiatp.springcloud.service;
import java.util.List;
import org.springframework.stereotype.Component;
import com.jiatp.springcloud.entity.Dept;
import feign.hystrix.FallbackFactory;
@Component//不要忘記添加,不要忘記添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>{
@Override
public DeptClientService create(Throwable cause) {
// TODO Auto-generated method stub
return new DeptClientService() {
@Override
public Dept get(long id) {
return new Dept().setDeptno(id)
.setDname("該ID:"+id+"沒有沒有對應的資訊,Consumer用戶端提供的降級資訊,此刻服務Provider已經關閉")
.setDb_source("no this database in MySQL");
}
@Override
public List<Dept> list() {
return null;
}
@Override
public boolean add(Dept dept) {
return false;
}
};
}
}
2、修改microservicecloud-api工程,DeptClientService接口在注解@FeignClient中添加fallbackFactory屬性值
package com.jiatp.springcloud.service;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jiatp.springcloud.entity.Dept;
//@FeignClient(value = "MICROSERVICECLOUD-DEPT")
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list",method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add",method = RequestMethod.POST)
public boolean add(Dept dept);
}
3、microservicecloud-api工程重新mvn clean install,
4、microservicecloud-consumer-dept-feign工程修改YML
server:
port: 80 # 消費者的端口80
feign:
hystrix:
enabled: true
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
5、測試
1、啟動順序:先啟動3個eureka注冊中心,再啟動提供者:微服務microservicecloud-provider-dept-8001啟動,再啟動消費者:microservicecloud-consumer-dept-feign啟動;
2、正常通路測試:http://localhost/consumer/dept/get/1
3、故意關閉微服務microservicecloud-provider-dept-8001
此時服務端provider已經down了,但是我們做了服務降級處理,讓用戶端在服務端不可用時也會獲得提示資訊而不會挂起耗死伺服器
服務熔斷和服務降級
3、服務監控hystrixDashboard
1、概述
除了隔離依賴服務的調用以外,Hystrix還提供了準實時的調用監控(Hystrix Dashboard),Hystrix會持續地記錄所有通過Hystrix發起的請求的執行資訊,并以統計報表和圖形的形式展示給使用者,包括每秒執行多少請求多少成功,多少失敗等。Netflix通過hystrix-metrics-event-stream項目實作了對以上名額的監控。Spring Cloud也提供了Hystrix Dashboard的整合,對監控内容轉化成可視化界面。
2、步驟
1、建立工程microservicecloud-consumer-hystrix-dashboard
2、pom配置添加相關hystrixDashboard依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jiatp.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-consumer-hystrix-dashboard</artifactId>
<dependencies>
<dependency><!-- 自己定義的api -->
<groupId>com.jiatp.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 修改後立即生效,熱部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Ribbon相關 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 引入feign相關依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- 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>
</dependencies>
</project>
3、yml配置
server:
port: 9001
4、主啟動類改名+新注解@EnableHystrixDashboard
package com.jiatp.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumer_DashBoard_App {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(DeptConsumer_DashBoard_App.class, args);
}
}
5、所有Provider微服務提供類(8001/8002/8003)都需要監控依賴配置
<!-- actuator監控資訊完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
6、啟動microservicecloud-consumer-hystrix-dashboard該微服務監控消費端
浏覽器輸入:http://localhost:9001/hystrix
看到此界面則配置成功。
啟動三個eureka叢集,啟動microservicecloud-provider-dept-hystrix-8001,浏覽器輸入:http://localhost:8001/hystrix.stream
7、啟動所有的微服務
監控測試:
1、多次重新整理http://localhost:8001/dept/get/1,觀察監控視窗
2、填寫監控位址:
1:Delay:該參數用來控制伺服器上輪詢監控資訊的延遲時間,預設為2000毫秒,可以通過配置該屬性來降低用戶端的網絡和CPU消耗。
2:Title:該參數對應了頭部标題Hystrix Stream之後的内容,預設會使用具體監控執行個體的URL,可以通過配置該資訊來展示更合适的标題。
3、監控結果
4、怎麼看?
7色、
1圈
實心圓:共有兩種含義。它通過顔色的變化代表了執行個體的健康程度,它的健康度從綠色<黃色<橙色<紅色遞減。
該實心圓除了顔色的變化之外,它的大小也會根據執行個體的請求流量發生變化,流量越大該實心圓就越大。是以通過該實心圓的展示,就可以在大量的執行個體中快速的發現故障執行個體和高壓力執行個體。
1線:
曲線:用來記錄2分鐘内流量的相對變化,可以通過它來觀察到流量的上升和下降趨勢。
全圖說明:
遇到的坑:
1、浏覽器通路:http://localhost:10001/hystrix.stream ,出現了404錯誤
provider中加入依賴:actuator
說明:第一個坑,在SpringBoot 2.0之前,隻要添加了Actuator依賴,不會出現404錯誤的
yml中要加入actuator監控配置:
management:
endpoints:
web:
exposure:
include: "*"
這時候通路位址是:http://localhost:8001/actuator/hystrix.stream
2、Hystrix-Dashboard會一直在 loading... 中,這就是第二個坑...
點選進入頁面一直顯示loading
解決方法:當通過Feign調用一次新服務後,hystrix.stream 正常,效果如下:即先調用依次provider:http://localhost:8001/dept/get/1
後顯示: