熔斷器,網關,配置中心搭建配置


熔斷器Hystrix

2.1 為什么要使用熔斷器

​ 在微服務架構中通常會有多個服務層調用,基礎服務的故障可能會導致級聯故障,進而造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。服務雪崩效應是一種因“服務提供者”的不可用導致“服務消費者”的不可用,並將不可用逐漸放大的過程。

​ 如果下圖所示:A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者。A不可用引起了B的不可用,並將不可用像滾雪球一樣放大到C和D時,雪崩效應就形成了。

 

​ 如何避免產生這種雪崩效應呢?我們可以使用Hystrix來實現熔斷器。

2.2 什么是Hystrix

Hystrix [hɪst'rɪks]的中文含義是豪豬, 因其背上長滿了刺,而擁有自我保護能力  

​ Hystrix 能使你的系統在出現依賴服務失效的時候,通過隔離系統所依賴的服務,防止服務級聯失敗,同時提供失敗回退機制,更優雅地應對失效,並使你的系統能更快地從異常中恢復。

​ 了解熔斷器模式請看下圖:

2.3 快速體驗

Feign 本身支持Hystrix,不需要額外引入依賴。

(1)修改tensquare_qa模塊的application.yml ,開啟hystrix


feign:
hystrix:
  enabled: true

(2)在com.tensquare.qa.client包下創建impl包,包下創建熔斷實現類,實現自接口LabelClient


@Component
public class LabelClientImpl implements LabelClient {

   @Override
   public Result findById(String id) {
       return new Result(false, StatusCode.ERROR,"熔斷器啟動了");
  }
}

(3)修改LabelClient的注解


@FeignClient(value="tensquare-base",fallback = LabelClientImpl.class)

(4)測試運行

重新啟動問答微服務,測試看熔斷器是否運行。

3 微服務網關Zuul

3.1 為什么需要微服務網關

不同的微服務一般有不同的網絡地址,而外部的客戶端可能需要調用多個服務的接口才能完成一個業務需求。比如一個電影購票的收集APP,可能回調用電影分類微服務,用戶微服務,支付微服務等。如果客戶端直接和微服務進行通信,會存在一下問題:

# 客戶端會多次請求不同微服務,增加客戶端的復雜性

# 存在跨域請求,在一定場景下處理相對復雜

# 認證復雜,每一個服務都需要獨立認證

# 難以重構,隨着項目的迭代,可能需要重新划分微服務,如果客戶端直接和微服務通信,那么重構會難以實施

# 某些微服務可能使用了其他協議,直接訪問有一定困難

上述問題,都可以借助微服務網關解決。微服務網關是介於客戶端和服務器端之間的中間層,所有的外部請求都會先經過微服務網關。

3.2 什么是Zuul

​ Zuul是Netflix開源的微服務網關,他可以和Eureka,Ribbon,Hystrix等組件配合使用。Zuul組件的核心是一系列的過濾器,這些過濾器可以完成以下功能:

# 身份認證和安全: 識別每一個資源的驗證要求,並拒絕那些不符的請求

#審查與監控:

## 動態路由:動態將請求路由到不同后端集群

# 壓力測試:逐漸增加指向集群的流量,以了解性能

# 負載分配:為每一種負載類型分配對應容量,並棄用超出限定值的請求

# 靜態響應處理:邊緣位置進行響應,避免轉發到內部集群

# 多區域彈性:跨域AWS Region進行請求路由,旨在實現ELB(ElasticLoad Balancing)使用多樣化

Spring Cloud對Zuul進行了整合和增強。

使用Zuul后,架構圖演變為以下形式

3.3 Zuul路由轉發

3.3.1 管理后台微服務網關

(1)創建子模塊tensquare_manager,pom.xml引入eureka-client 和zuul的依賴


   <dependencies>
       <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-zuul</artifactId>
       </dependency>
   </dependencies>

(2)創建application.yml


server:
port: 9011
spring:
application:
  name: tensquare-manager #指定服務名
eureka:
client:
  serviceUrl: #Eureka客戶端與Eureka服務端進行交互的地址
    defaultZone: http://127.0.0.1:6868/eureka/
instance:
  prefer-ip-address: true
zuul:
routes:
  tensquare-gathering: #活動
    path: /gathering/** #配置請求URL的請求規則
    serviceId: tensquare-gathering #指定Eureka注冊中心中的服務id
  tensquare-article: #文章
    path: /article/** #配置請求URL的請求規則
    serviceId: tensquare-article #指定Eureka注冊中心中的服務id
  tensquare-base: #基礎
    path: /base/** #配置請求URL的請求規則
    serviceId: tensquare-base #指定Eureka注冊中心中的服務id
  tensquare-friend: #交友
    path: /friend/** #配置請求URL的請求規則
    serviceId: tensquare-friend #指定Eureka注冊中心中的服務id
  tensquare-qa: #問答
    path: /qa/** #配置請求URL的請求規則
    serviceId: tensquare-qa #指定Eureka注冊中心中的服務id
  tensquare-recruit: #招聘
    path: /recruit/** #配置請求URL的請求規則
    serviceId: tensquare-recruit #指定Eureka注冊中心中的服務id          
  tensquare-spit: #吐槽
    path: /spit/** #配置請求URL的請求規則
    serviceId: tensquare-spit #指定Eureka注冊中心中的服務id      
  tensquare-user: #用戶
    path: /user/** #配置請求URL的請求規則
    serviceId: tensquare-user #指定Eureka注冊中心中的服務id

(3)編寫啟動類


@EnableZuulProxy
@SpringBootApplication
public class Application {
   public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
  }
}

3.3.2 網站前台的微服務網關

(1)創建子模塊tensquare_web,pom.xml引入依賴zuul


   <dependencies>
       <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-zuul</artifactId>
       </dependency>
   </dependencies>

(2)創建application.yml


server:
port: 9012
spring:
application:
  name: tensquare-web #指定服務名
eureka:
client:
  serviceUrl: #Eureka客戶端與Eureka服務端進行交互的地址
    defaultZone: http://127.0.0.1:6868/eureka/
instance:
  prefer-ip-address: true
zuul:
routes:
  tensquare-gathering: #活動
    path: /gathering/** #配置請求URL的請求規則
    serviceId: tensquare-gathering #指定Eureka注冊中心中的服務id
  tensquare-article: #文章
    path: /article/** #配置請求URL的請求規則
    serviceId: tensquare-article #指定Eureka注冊中心中的服務id
  tensquare-base: #基礎
    path: /base/** #配置請求URL的請求規則
    serviceId: tensquare-base #指定Eureka注冊中心中的服務id
  tensquare-friend: #交友
    path: /friend/** #配置請求URL的請求規則
    serviceId: tensquare-friend #指定Eureka注冊中心中的服務id
  tensquare-qa: #問答
    path: /qa/** #配置請求URL的請求規則
    serviceId: tensquare-qa #指定Eureka注冊中心中的服務id
  tensquare-recruit: #招聘
    path: /recruit/** #配置請求URL的請求規則
    serviceId: tensquare-recruit #指定Eureka注冊中心中的服務id
  tensquare-spit: #吐槽
    path: /spit/** #配置請求URL的請求規則
    serviceId: tensquare-spit #指定Eureka注冊中心中的服務id
  tensquare-user: #用戶
    path: /user/** #配置請求URL的請求規則
    serviceId: tensquare-user #指定Eureka注冊中心中的服務id
  tensquare-search: #搜索
    path: /search/** #配置請求URL的請求規則
    serviceId: tensquare-search #指定Eureka注冊中心中的服務id

(3)編寫啟動類


@EnableZuulProxy
@SpringBootApplication
public class WebApplication {

   public static void main(String[] args) {
       SpringApplication.run(WebApplication.class);
  }
}

3.4 Zuul過濾器

3.4.1 Zuul過濾器快速體驗

我們現在在tensquare_web 創建一個簡單的zuul過濾器


@Component
public class WebFilter extends ZuulFilter {

   @Override
   public String filterType() {
        return "pre";// 前置過濾器
  }

   @Override
   public int filterOrder() {
       return 0;// 優先級為0,數字越大,優先級越低
  }

   @Override
   public boolean shouldFilter() {
       return true;// 是否執行該過濾器,此處為true,說明需要過濾
  }

   @Override
   public Object run() throws ZuulException {
       System.out.println("zuul過濾器...");
       return null;
  }
}

啟動tensquare_web會發現過濾器已經執行

filterType:返回一個字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:

  • pre: 可以在請求被路由之前調用

  • route:在路由請求時候被調用

  • post:在route和error過濾器之后被調用

  • error:處理請求時發生錯誤時被調用

filterOrder:通過int值來定義過濾器的執行順序

shouldFilter:返回一個boolean類型來判斷該過濾器是否要執行,所以通過此函數可實現過濾器的開關。在上例中,我們直接返回true,所以該過濾器總是生效

run:過濾器的具體邏輯。

3.4.2 網站前台的token轉發

我們現在在過濾器中接收header,轉發給微服務

修改tensquare_web的過濾器。如果有token,直接轉發。


   @Override
   public Object run() throws ZuulException {
       System.out.println("zuul過濾器...");
       //向header中添加鑒權令牌
       RequestContext requestContext = RequestContext.getCurrentContext();
       //獲取header
       HttpServletRequest request = requestContext.getRequest();
       String authorization = request.getHeader("Authorization");
       if(authorization!=null){
           requestContext.addZuulRequestHeader("Authorization",authorization);
      }
       return null;
  }

3.4.3 管理后台過濾器實現token校驗

修改tensquare_manager的過濾器, 因為是管理后台使用,所以需要在過濾器中對token進行驗證。

(1)tensquare_manager引入tensquare_common依賴 ,因為需要用到其中的JWT工具類

        <dependency>
           <groupId>com.tensquare</groupId>
           <artifactId>tensquare_common</artifactId>
           <version>1.0-SNAPSHOT</version>
       </dependency>

(2)修改tensquare_manager配置文件application.yml


jwt:
config:
  key: itcast

(3)修改tensquare_manager的啟動類,添加bean


   @Bean
   public JwtUtil jwtUtil(){
       return new JwtUtil();
  }

(4)tensquare_manager編寫過濾器類


@Component
public class ManagerFilter extends ZuulFilter {

   @Autowired
   private JwtUtil jwtUtil;

   @Override
   public String filterType() {//過濾器類型
       return "pre";//前置過濾器
  }

   @Override
   public int filterOrder() {
       return 0;//優先級,數字越大,優先級越低
  }

   @Override
   public boolean shouldFilter() {
       return true;//過濾器開關,true表示開啟
  }

   @Override
   public Object run() throws ZuulException {
       System.out.println("Zuul過濾器");
       RequestContext requestContext=RequestContext.getCurrentContext();
       HttpServletRequest request = requestContext.getRequest();
       
       if(request.getMethod().equals("OPTIONS")){
           return null;
      }
       String url=request.getRequestURL().toString();
       if(url.indexOf("/admin/login")>0){
           System.out.println("登陸頁面"+url);
           return null;
      }

       String authHeader =(String)request.getHeader("Authorization");//獲取頭信息
       if(authHeader!=null && authHeader.startsWith("Bearer ") ){
           String token = authHeader.substring(7);
           Claims claims = jwtUtil.parseJWT(token);
           if(claims!=null){
               if("admin".equals(claims.get("roles"))){
                   requestContext.addZuulRequestHeader("Authorization",authHeader);
                   System.out.println("token 驗證通過,添加了頭信息"+authHeader);
                   return null;
              }
          }
      }
       requestContext.setSendZuulResponse(false);//終止運行
       requestContext.setResponseStatusCode(401);//http狀態碼
       requestContext.setResponseBody("無權訪問");
       requestContext.getResponse().setContentType("text/html;charset=UTF-8");

       return null;
  }
}

需要注意,這里我們通過ctx.setSendZuulResponse(false)令zuul過濾該請求,不對其進行路由,然后通過ctx.setResponseStatusCode(401)設置了其返回的錯誤碼

 

4 集中配置組件SpringCloudConfig

4.1 Spring Cloud Config簡介

在分布式系統中,由於服務數量巨多,為了方便服務配置文件統一管理,實時更新,所以需要分布式配置中心組件。在Spring Cloud中,有分布式配置中心組件spring cloud config ,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程Git倉庫中。在spring cloud config 組件中,分兩個角色,一是config server,二是config client。

Config Server是一個可橫向擴展、集中式的配置服務器,它用於集中管理應用程序各個環境下的配置,默認使用Git存儲配置文件內容,也可以使用SVN存儲,或者是本地文件存儲。

Config Client是Config Server的客戶端,用於操作存儲在Config Server中的配置內容。微服務在啟動時會請求Config Server獲取配置文件的內容,請求到后再啟動容器。

詳細內容看在線文檔: https://springcloud.cc/spring-cloud-config.html

4.2 配置服務端

4.2.1 將配置文件提交到碼雲

使用GitHub時,國內的用戶經常遇到的問題是訪問速度太慢,有時候還會出現無法連接的情況。如果我們希望體驗Git飛一般的速度,可以使用國內的Git托管服務——碼雲gitee.com)。

和GitHub相比,碼雲也提供免費的Git倉庫。此外,還集成了代碼質量檢測、項目演示等功能。對於團隊協作開發,碼雲還提供了項目管理、代碼托管、文檔管理的服務。

步驟:

(1)瀏覽器打開gitee.com,注冊用戶 ,注冊后登陸碼雲管理控制台

 

(2)創建項目 tensquare-config (點擊右上角的加號 ,下拉菜單選擇創建項目)

 

(3)上傳配置文件,將tensquare_base工程的application.yml改名為base-dev.yml后上傳

可以通過拖拽的方式將文件上傳上去

上傳成功后列表可見

可以再次編輯此文件

文件命名規則:

{application}-{profile}.yml或{application}-{profile}.properties

application為應用名稱 profile指的開發環境(用於區分開發環境,測試環境、生產環境等)

(4)復制git地址 ,備用

地址為:https://gitee.com/chuanzhiliubei/tensquare-config.git

4.2.2 配置中心微服務

(1)創建工程模塊 配置中心微服務 tensquare_config ,pom.xml引入依賴


   <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-config-server</artifactId>
       </dependency>
   </dependencies>

(2)創建啟動類ConfigServerApplication


@EnableConfigServer //開啟配置服務
@SpringBootApplication
public class ConfigServerApplication {
   public static void main(String[] args) {
       SpringApplication.run(ConfigServerApplication.class, args);
  }
}

(3)編寫配置文件application.yml


spring:
application:
  name: tensquare-config
cloud:
  config:
    server:
      git:
        uri: https://gitee.com/chuanzhiliubei/tensquare-config.git
server:
port: 12000

(4)瀏覽器測試:http://localhost:12000/base-dev.yml 可以看到配置內容

4.3 配置客戶端

(1)在tensquare_base工程添加依賴


<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

(2)添加bootstrap.yml ,刪除application.yml


spring:
cloud:
  config:
    name: base
    profile: dev
    label: master
    uri: http://127.0.0.1:12000

(3)測試: 啟動工程tensquare_eureka tensquare_config tensquare_base,看是否可以正常運行


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM