01 基礎環境準備
02 一文讀懂Eureka
03 Zookeeper註冊中心
04 Consule註冊中心
05 Ribbon
06 OpenFegin
07 Hystrix全面解析
08 Gateway全面解析
09 Config配置中心
10 Bus消息總線
1 分佈式系統面臨的問題
複雜分佈式體系結構中的應用程序有數十個依賴關係,每個依賴關係在某些時候將不可避免地失敗。
左圖中的請求需要調用A,P,H,I 四個服務,如果一切順利則沒有什麼問題,關鍵是如果I服務超時會出現什麼情況呢?
(2) 雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的“扇出"。如果扇出的鏈路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。所以通常當你發現一個模塊下的某個實例失敗後,這時候這個模塊依然還會接收流量,然後這個有問題的模塊還調用了其他的模塊,這樣就會發生級聯故障,或者叫雪崩。
2 Hystrix是什麼
Hystrix是個用於處理分佈式系統的延遲和容錯的開源庫,在分佈式奈統裏,許多依賴不可避免的會調用失敗,比如超時、異常等。Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分佈式系統的彈性。“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回個符合預期的、可處理的備選響應( Fallback),而不是長時間的等待或者拋出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。
(1) 服務降級
當服務器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運作或高效運作。
使用場景:服務異常、超時、服務熔斷觸發服務降級、線程池/信號量打滿也會導致服務降級
(2) 服務熔斷
高壓電路中,如果某個地方的電壓過高,熔斷器就會熔斷,對電路進行保護。股票交易中,如果股票指數過高,也會採用熔斷機制,暫停股票的交易。同樣,在微服務架構中,熔斷機制也是起着類似的作用。當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。當檢測到該節點微服務調用響應正常後,恢復調用鏈路。
(3) 服務限流
限流的目的是通過對併發訪問/請求進行限速或者一個時間窗口內的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊或等待(比如秒殺、評論、下單)、降級(返回兜底數據或默認數據,如商品詳情頁庫存默認有貨)。
3 新建工程 provider-hystrix
(1) pom
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.zrs.springcloud</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
(2) application.yml
server:
port: 7004
spring:
application:
name: provider-hystrix
eureka:
client:
#是否將自己註冊到EurekaServer
register-with-eureka: true
#是否從EurekaServer獲取已有的註冊服務
fetch-registry: true
#註冊地址
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
instance-id: provider-hystrix
prefer-ip-address: true
(3) 主啓動類
@SpringBootApplication
@EnableEurekaClient
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class);
}
}
(4) Controller
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello(){
return "Hello Thread:"+Thread.currentThread().getName();
}
@GetMapping("/threeseconds")
public String threeseconds(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
}
(5) 啓動 測試
4 新建工程customer-hystrix
4.1 pom
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka 客戶端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--oepn fegin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.zrs.springcloud</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
4.2 application.yml
server:
port: 8004
spring:
application:
name: customer-hystrix
eureka:
client:
#是否將自己註冊到EurekaServer
register-with-eureka: true
#是否從EurekaServer獲取已有的註冊服務
fetch-registry: true
#註冊地址
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
instance-id: customer-hystrix
prefer-ip-address: true
4.3 主程序啓動
@SpringBootApplication
@EnableFeignClients
public class HystrixCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixCustomerApplication.class);
}
}
4.4 FeginService
@Component
@FeignClient("PROVIDER-HYSTRIX")
@RequestMapping("/hystrix")
public interface FeginService {
@GetMapping("/hello")
String hello();
@GetMapping("/threeseconds")
String threeseconds();
}
4.5 controller
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
}
4.6 啓動
5 降級配置
5.1 provider-hystrix配置
(1) 修改HystrixController
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello(){
return "Hello Thread:"+Thread.currentThread().getName();
}
/**
* fallbackMethod 降級方法
* timeoutInMilliseconds: 2秒爲正常響應,超過兩秒調用降級方法
*
*/
@HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
public String fallbackMethod(){
return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
}
}
(2) 修改啓動類
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class);
}
}
(3) 測試
5.2 customer-hystrix降級配置
(1) application.yml添加配置文件
#開啓降級
feign:
hystrix:
enabled: true
(2) 修改主啓動類
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class HystrixCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixCustomerApplication.class);
}
}
(3) 修改HystrixController
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
public String fallbackMethod(){
return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
}
}
(4) 重啓運行
6 hystrix降級解耦
6.1 @DefaultProperties
(1) DefaultProperties作用:全局降級方法。修改customer-hystrix的HystrixController
/**
* @Description: @DefaultProperties全局降級方法
* @Auther: zhurongsheng
* @Date: 2020/3/14 22:32
*/
@RequestMapping("/customer")
@RestController
@DefaultProperties(defaultFallback = "commonfallbackMethod")
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
public String commonfallbackMethod(){
return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
}
}
(2) 重啓,測試
6.2 customer-hystrix配置文件分離
(1) FeginService
@FeignClient(value = "PROVIDER-HYSTRIX",fallback = FeginFallbackService.class,path = "/hystrix")
@Service
public interface FeginService {
@GetMapping("/hello")
String hello();
@GetMapping("/threeseconds")
String threeseconds();
}
(2) 接口實現類,FeginFallbackService
@Service
public class FeginFallbackService implements FeginService{
@Override
public String hello() {
return "FeginFallbackService invoke hello";
}
@Override
public String threeseconds() {
return "FeginFallbackService invoke threeseconds";
}
}
(3) 修改Controller,HystrixController
@RequestMapping("/customer")
@RestController
public class HystrixController {
@Autowired
private FeginService feginService;
@GetMapping("/hello")
public String hello(){
return feginService.hello();
}
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds(){
return feginService.threeseconds();
}
}
(4) 重啓測試
7 熔斷
服務熔斷:在一定週期內,服務異常次數達到設定的閾值或百分比,則觸發熔斷,熔斷後,後面的請求將都走默認處理方法defaultFallback
7.1 修改provider-hystrix的 HystrixController
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
@GetMapping("/hello")
public String hello() {
return "Hello Thread:" + Thread.currentThread().getName();
}
/**
* fallbackMethod 降級方法
* timeoutInMilliseconds: 2秒爲正常響應,超過兩秒調用降級方法
*/
@HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
})
@GetMapping("/threeseconds")
public String threeseconds() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello threeseconds";
}
public String fallbackMethod() {
return "服務器正忙,請稍後訪問。Thread:" + Thread.currentThread().getName();
}
/**
* =====================熔斷配置=======================
* circuitBreaker.enabled: 啓動熔斷
* circuitBreaker.requestVolumeThreshold:請求次數
* circuitBreaker.errorThresholdPercentage: 失敗率達到多少啓動熔斷
*/
@HystrixCommand(fallbackMethod = "circuitBreakerFallback",commandProperties = {
@HystrixProperty(name="circuitBreaker.enabled",value = "true"),
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "10"),
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
@GetMapping("/{id}")
public String circuitBreaker(@PathVariable("id") Integer id) {
if (id<0){
throw new RuntimeException("id ="+id+",不能爲負數");
}
return "調用成功,O(∩_∩)O~ id=" + id;
}
public String circuitBreakerFallback(@PathVariable("id") Integer id) {
return "id =" + id + ", 不能爲負數,o(╥﹏╥)o~ ";
}
}
7.2 啓動觀察
(1) 正常訪問
(2) 錯誤訪問
(3) 多次錯誤訪問後
8 服務監控hystrixDashboard
除了隔離依賴服務的週用以外, Hystrix還提供了往實時的調用監控( Hystrix Dashboard), Hystrix:會持續地記錄所有通過 Hystrix發起的請求的執行信息,並以統計報表和圖形的形式展示給用戶,包括每秒執行多少請求多少成功,多少失敗等。 Netflix 通過hystrix- metrics- event- stream項目實現了對以上指標的監控。 Spring Cloud也提供了 Hystrix Dashboard的整合,對監控內容轉化成可視化界面。
8.1 pom
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
8.2 application.yml
server:
port: 9001
8.3 啓動類,並啓動
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashbordApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashbordApplication.class);
}
}
8.4 訪問
8.5 在provider-hystrix裏添加HystrixConfig配置文件,重啓服務
@Configuration
public class HystrixConfig {
@Bean
public ServletRegistrationBean myServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
8.6 dashboard添加provider-hystrix
http://localhost:7004/hystrix.stream
GITHUB
#分支 Hystrix-enviroment-release-v1.0
https://github.com/zhurongsheng666/spring-cloud-hoxton