一、Hystrix
1、服務雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C有調用其他的微服務,這就是所謂的”扇出”,如扇出的鏈路上某個微服務的調用響應式過長或者不可用,對微服務A的調用就會占用越來越多的系統資源,進而引起系統雪崩,所謂的”雪崩效應”。
2、Hystrix
Hystrix是一個用於分布式系統的延遲和容錯的開源庫。在分布式系統里,許多依賴不可避免的調用失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整個服務失敗,避免級聯故障,以提高分布式系統的彈性。
“斷路器”本身是一種開關裝置,當某個服務單元發生故障監控(類似熔斷保險絲),向調用方法返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方法無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延。乃至雪崩。
二、服務熔斷
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,
當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回”錯誤”的響應信息。當檢測到該節點微服務響應正常后恢復調用鏈路,在SpringCloud框架機制通過Hystrix實現,Hystrix會監控微服務見調用的狀況,當失敗的調用到一個閾值,缺省是5秒內20次調用失敗就會啟動熔斷機制,熔斷機制的注解是@HystrixCommand
創建一個工程,命名為:DeptProvider8001_Hystrix_App
1、增加pom.xml中的依賴包
<?xml version="1.0" encoding="UTF-8"?> <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"> <parent> <artifactId>microservicecloud</artifactId> <groupId>com.yufeng.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId> <dependencies> <!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <!-- 將微服務provider側注冊進eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!-- 引入自己定義的api通用包,可以使用Dept部門Entity --> <dependency> <groupId>com.yufeng.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- actuator監控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </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> </dependencies> </project>
2、yml文件修改,修改服務名稱instance-id:為自己的微服務名稱即可
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路徑
type-aliases-package: com.yufeng.springcloud.entities # 所有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 # mysql驅動包
url: jdbc:mysql://192.168.172.20:3306/cloudDB01 # 數據庫名稱
username: root
password: root
dbcp2:
min-idle: 5 # 數據庫連接池的最小維持連接數
initial-size: 5 # 初始化連接數
max-total: 5 # 最大連接數
max-wait-millis: 200 # 等待連接獲取的最大超時時間
eureka:
client: # 客戶端注冊進eureka內
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: provider-hystrix-dept-8001
prefer-ip-address: true # 訪問路徑可以顯示IP
info:
app.name: yufeng-microservicecloud
company.name: www.yufeng.com
build.artifactId: $project.artifactId$
build.version: $project.version$
3、增加熔斷機制(@HystrixCommand)
@RestController public class DeptController { @Autowired private DeptService service; @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(@RequestBody Dept dept) { return service.add(dept); } @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
//一旦調用服務方法失敗拋出“錯誤信息后,胡自動范湖用@HystrixCommand標注好的fallbackMethod調用類中的指定方法” @HystrixCommand(fallbackMethod = "processHystrixGet") public Dept get(@PathVariable("id") Long id) { Dept dept = service.get(id); //模擬異常
if(null == dept) { throw new RuntimeException("該id的信息不存在! id=" + id); } return service.get(id); } public Dept processHystrixGet(@PathVariable("id") Long id) { return new Dept().setDname("id沒有對應的信息, null -- @HystrixCommand, id=" + id) .setDb_source("no this database in MySQL."); } }
4、主啟動類添加注解 @EnableCircuitBreaker
添加此注解告訴主啟動類對Hystrix的支持
@SpringBootApplication @EnableEurekaClient //本服務啟動后自動注冊到eureka中
@EnableCircuitBreaker //對hystrixR熔斷機制的支持
public class DeptProvider8001_Hystrix_App { public static void main(String[] args) { SpringApplication.run(DeptProvider8001_Hystrix_App.class, args); } }
5、測試:
(1)啟動 3個eureka服務:EurekaServer7001、EurekaServer7002、EurekaServer7003;
(2)啟動 DeptProvider8001_Hystrix_App 服務;
(3)最后啟動DeptConsumer80_App 服務。
(4)測試地址:
http://localhost/consumer/dept/get/2
http://localhost/consumer/dept/get/112
三、服務降級
服務降級的處理是在客戶端完成的,與服務端沒有關系。
整體資源快不夠用了,忍痛將某些服務先關掉,待度過難關,再回來開啟。
所謂降級,就是一般是從整體符合考慮,就是當某個服務熔斷之后,服務器將不再被調用,此刻客戶端可以自己准備一個本地的fallback回調,返回一個缺省值,這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強。
1、修改消費者服務接口的提供者項目(microservicecloud-api),讓service接口實現一個FallbackFactory接口類DeptClientServiceFallbackFactory(千萬記得增加 @Component 注解);
注意:直接在接口定義的熔斷機制中進行服務熔斷,之前在controller上的@HystrixCommand(fallbackMethod=”methodName”)將棄用
import com.yufeng.springcloud.entities.Dept; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; @Component public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public boolean add(Dept dept) { return false; } @Override public Dept get(Long id) { Dept dept = new Dept(); dept.setDeptno(id); dept.setDname("該ID:" + id + "沒有對應的信息,Consumer客戶端提供的信息,此服務Provider已關閉"); dept.setDb_source("no this database in mysql"); return dept; } @Override public List<Dept> list() { return null; } }; } }
2、修改提供服務的service熔斷處理的機制
此處是在公共的service對某個service的方法訪問出現異常后進行統一的fallback處理,即在 DeptClientService接口在注解@FeignClient 中添加 fallbackFactory 屬性值,該屬性賦值為實現FallbcakFactory接口的異常處理類。
import com.yufeng.springcloud.entities.Dept; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.List; @FeignClient(value = "microservicecloud-dept", fallbackFactory = DeptClientServiceFallbackFactory.class) public interface DeptClientService { @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(@RequestBody Dept dept); @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) public Dept get(@PathVariable("id") Long id); @RequestMapping(value = "/dept/get/list", method = RequestMethod.GET) public List<Dept> list(); }
3、在消費者工程(microservicecloud-consumer-dept-feign)的yml文件增加如下內容,開啟feign中的hystrix
feign: hystrix: enabled: true
4、將 microservicecloud-api 工程重新打包,執行: mvn clean install
5、測試
(1)啟動3個 eureka 服務;
(2)啟動 microservicecloud-provider-dept-8001 服務;
(3)啟動 microservicecloud-consumer-dept-feign 服務;
(4)在瀏覽器中訪問:http://localhost/consumer/dept/get/1
(5)將 microservicecloud-provider-dept-8001 服務關閉,瀏覽器訪問:http://localhost/consumer/dept/get/1