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
後顯示: