Python培訓:約束佈局的使用方法
1.分散式系統面臨的問題
複雜分散式體系結構中的應用程式有數十個依賴關係,每個依賴關係在某些時候將不可避免的失敗
2.服務雪崩
-
多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和微服務C,微服務B和微服務C又呼叫其他的微服務,這就是所謂的“扇出”,如果扇出的鏈路上某個微服務的呼叫響應時間過長或者不可用,對微服務A的呼叫就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”
-
對於高流量的應用來說,單一的後端依賴可能會導致所有伺服器上的所有資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式,還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多級聯故障,這些都表示需要對故障和延遲進行距離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
3.Hystrix的概念和作用
3.1Hystrix的概念
-
Hystrix是一個用於處理分散式系統的延遲和熔斷的開源庫,在分散式系統裡,許多依賴不可避免的會呼叫失敗,比如超時,異常等,Hystrix能夠保證在一個依賴出問題的時候,不會導致整個服務失敗,避免級聯故障,以提高分散式系統的彈性。
-
“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(雷士熔斷保險絲),向呼叫方返回一個服務預期的,可處理的備選相應(FallBack)而不是長時間的等待或者丟擲呼叫方法無法處理的異常,這樣就可以保證了服務呼叫方法的執行緒不會被長時間佔用,不必要的佔用,從而避免了故障在分散式系統中的蔓延,乃至雪崩
3.2Hystrix的作用
-
服務熔斷
-
熔斷機制是對應雪崩效用的一中微服務鏈路保護機制
-
當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快速返回錯誤的響應資訊。當檢測到該節點微服務呼叫響應正常回復呼叫鏈路。在SpringCloud框架裡熔斷機制通過Hystrix實現。Hystrix會監控微服務間呼叫的狀況,當時白的呼叫到一定閾值,預設是5秒內20次呼叫失敗就會啟動熔斷機制。熔斷機制的註解是@HystrixCommand
-
-
服務降級
-
接近實時的監控
-
服務限流
4.Hystrix實戰
4.1服務熔斷
前提:基於負載均衡及Ribbon
-
建立一個新的modules,專案名稱為複製provider-dept-hystrix-8004,然後將provider-dept--8001的程式碼全部複製進去
-
在原來依賴的基礎上,新增hystrix依賴
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 修改DeptController中的程式碼
package com.zixin.springcloud.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.zixin.springcloud.pojo.Dept;
import com.zixin.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/provider/dept")
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/findDeptById/{deptno}")
//發生異常的時候呼叫備用方法
@HystrixCommand(fallbackMethod = "getDeptHystrix")
public Dept getDept(@PathVariable Long deptno){
Dept dept = deptService.findDeptById(deptno);
if(dept == null){
throw new RuntimeException("id=" + deptno + ",不存在該使用者或資訊無法找到");
}
return dept;
}
//備選方法
public Dept getDeptHystrix(@PathVariable Long deptno){
Dept dept = new Dept();
dept.setDeptno(deptno.toString());
dept.setDname("id=" + deptno + ",沒有對應資訊,null--@Hystrix");
dept.setDb_source("no this database in MySQL");
return dept;
}
}
-
啟動類重新命名為ProviderDeptHystrixApplication,並在該啟動類上新增
@EnableCircuitBreaker
註解,用於開啟熔斷器 -
執行provider-dept-hystrix-8004、eureka-server-7001以及consumer-dept-8001專案,訪問
http://localhost:7001/
,可以看到provider-dept-hystrix-8004服務已經註冊上去了然後在訪問
http://localhost:9001/consumer/dept/findDeptById/1
,可以獲取到對應的資料
當訪問資料庫中沒有的資料時,如http://localhost:9001/consumer/dept/findDeptById/5
,頁面中就會顯示對應的提示資訊,至此服務熔斷功能得以實現
4.2服務降級
前提:基於負載均衡及Ribbon和Feign-使用介面方式呼叫服務這兩篇文章中的Ribbon實戰專案的基礎上新增內容
- 在springcloud-api專案的pom.xml中新增feign的依賴
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 在springcloud-api專案中com.zixin.springcloud.service包下建立impl資料夾,並在該資料夾下建立FeignDeptFallBackFactoryServiceImpl類,實現FallbackFactory介面
package com.zixin.springcloud.service.impl;
import com.zixin.springcloud.pojo.Dept;
import com.zixin.springcloud.service.FeignDeptService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
//服務降級
@Component
public class FeignDeptFallBackFactoryServiceImpl implements FallbackFactory<FeignDeptService> {
@Override
public FeignDeptService create(Throwable throwable) {
return new FeignDeptServiceFactory() {
@Override
public int addDept(Dept dept) {
return 0;
}
@Override
public Dept findDeptById(Long deptno) {
Dept dept = new Dept();
dept.setDeptno(deptno.toString());
dept.setDname("id="+deptno+"沒有對應的資訊,客戶端提供了降級的資訊,這個服務已經被關閉了");
dept.setDb_source("沒有資料~");
return dept;
}
@Override
public List<Dept> getDeptList() {
return null;
}
};
}
}
- 接著在
@FeignClient
註解裡面新增fallbackFactory
屬性,由於配置出現異常時呼叫的類,全部程式碼如下:
package com.zixin.springcloud.service;
import com.zixin.springcloud.pojo.Dept;
import com.zixin.springcloud.service.impl.FeignDeptFallBackFactoryServiceImpl;
import com.zixin.springcloud.service.impl.FeignDeptServiceFactory;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Component
@FeignClient(value = "PROVIDER-DEPT/provider/dept", fallbackFactory = FeignDeptFallBackFactoryServiceImpl.class)
public interface FeignDeptService {
//新增部門
@PostMapping("/addDept")
int addDept(Dept dept);
//根據id查詢部門資訊
@GetMapping("/findDeptById/{deptno}")
Dept findDeptById(@PathVariable Long deptno);
//查詢所有部門資訊
@GetMapping("/findDeptList")
List<Dept> getDeptList();
}
- 在consumer-dept-feign專案的配置檔案中新增下面的配置,開啟降級服務
#開啟服務降級
feign.hystrix.enabled=true
- 執行provider-dept-8001、eureka-server-7001以及consumer-dept-feign專案,訪問
http://localhost:9002/consumer/dept/findDeptById?deptno=2
,出現下面的錯誤
原因:接收引數時使用@PathVariable
註解
解決方法:把原來都使用到@PathVariable
註解的地方都換成@RequestParam
- 執行provider-dept-8001、eureka-server-7001以及consumer-dept-feign專案,訪問
http://localhost:9002/consumer/dept/findDeptById?deptno=2
,出現下面的錯誤
原因:當使用feign傳引數的時候,需要加上@RequestParam註解,否則對方服務無法識別引數
解決方法:使用feign傳引數的時候,加上@RequestParam註解,比如我這裡的FeignDeptService 類中的findDeptById方法
package com.zixin.springcloud.service;
import com.zixin.springcloud.pojo.Dept;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Component
@FeignClient(value = "PROVIDER-DEPT/provider/dept")
public interface FeignDeptService {
//新增部門
@PostMapping("/addDept")
int addDept(Dept dept);
//根據id查詢部門資訊
@GetMapping("/findDeptById")//路徑中的引數也去掉
Dept findDeptById(@RequestParam("deptno") Long deptno);//這裡要換成@RequestParam註解
//查詢所有部門資訊
@GetMapping("/findDeptList")
List<Dept> getDeptList();
}
- 再次執行provider-dept-8001、eureka-server-7001以及consumer-dept-feign專案,訪問
http://localhost:9002/consumer/dept/findDeptById?deptno=2
,得到下面結果
當把provider-dept-8001停掉,訪問http://localhost:9002/consumer/dept/findDeptById?deptno=2
,就會出現提示資訊如下
服務熔斷與服務降級的區別
-
服務熔斷:服務端,某個服務超時或者異常時引起熔斷
-
服務降級:客戶端,從整體網站請求負載考慮,即當某個服務熔斷或者關閉之後,服務將不再被呼叫,此時在客戶端,我們可以準備一個FallbackFactory,返回一個預設的值(預設值),整個服務水平下降了,但還是可以用,比直接掛掉好
4.3Dashboard流監控
前提:基於負載均衡及Ribbon和Feign-使用介面方式呼叫服務這兩篇文章中的Ribbon實戰專案的基礎上新增內容
- 新建立一個Modules,名稱為consumer-hystrix-dashboard,然後引入hystrix和hystrix-dashboard依賴
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
- 在配置檔案application.properties中新增該專案的服務埠號
#服務埠號
server.port=9003
- 在src/main/java目錄下建立com.zixin.springcloud包,並在該包下建立啟動類ConsumerHystrixDashboard
package com.zixin.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.web.bind.annotation.PathVariable;
//開啟hystrix監控
@EnableHystrixDashboard
@SpringBootApplication
public class ConsumerHystrixDashboard {
public static void main(String[] args) {
SpringApplication.run(ConsumerHystrixDashboard.class, args);
}
}
-
執行consumer-hystrix-dashboard專案,訪問
http://localhost:9003/
,出現下面的介面,說明專案執行成功 -
訪問
http://localhost:9003/hystrix
,可以看到如下的監控頁面資訊 -
在provider-dept-hystrix-8004專案中的啟動類中新增一個Bean
package com.zixin.springcloud;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
//開啟熔斷器
@EnableCircuitBreaker
@EnableEurekaClient
@MapperScan(basePackages = "com.zixin.springcloud.mapper")
@SpringBootApplication
public class ProviderDeptHystrixApplication {
private static final Logger logger = LoggerFactory.getLogger(ProviderDeptHystrixApplication.class);
public static void main(String[] args) {
logger.debug("-------ProviderDeptHystrixApplication正在啟動-----");
SpringApplication.run(ProviderDeptHystrixApplication.class, args);
}
//增加一個Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/hystrix.stream");
return registrationBean;
}
}
說明:這裡的/hystrix.stream對映路徑對應hystrix監控頁面的預設路徑,如下面紅色框起來的那部分
-
執行consumer-hystrix-dashboard、eureka-server-7001以及provider-dept-hystrix-8004專案,訪問
http://localhost:7001/
,可以看到provider-dept-hystrix-8004 服務已經註冊到eureka註冊中心,如下所示 -
訪問
http://localhost:8004/provider/dept//findDeptById?deptno=1
,也可以獲取到資料,如下所示 -
訪問
http://localhost:9003/hystrix
,也可以看到hystrix的監控頁面,如下所示 -
訪問
http://localhost:8004/hystrix.stream
,可以得到如下的資料 -
在hystrix監控頁面中輸入對應的監控地址,監控毫秒數以及監控服務名稱
-
點選Monitor Stream按鈕,跳轉到如下頁面
說明:
-
七種顏色對應關係
-
一個圈
實心圓:共有兩種含義,它通過顏色的變化代表了例項的健康程度,它的健康程度從綠色<黃色<橙色<紅色遞減,該實心圓除了顏色的變化之外,它的大小也會根據例項的請求流量發生變化,流量越大,該實心圓就越大,所以通過該實心圓的展示,就可以在大量的例項中快速發現故障例項和高壓力例項
- 一條線:用來記錄2分鐘內流量的相對變化,可以通過它來觀察流量的上升和下降趨勢
比如訪問多次http://localhost:8004/provider/dept//findDeptById?deptno=1
請求,那個圈也跟著變大,那條線就會有一定的弧度
- 全圖說明