成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

微服務如何灰度發布?你會嗎?

開發 架構
通過 Spring Cloud 的擴展組件和自定義路由策略,開發人員可以輕松實現灰度發布功能,確保在微服務架構中安全、平滑地進行版本迭代升級。

微服務中的灰度發布(又稱為金絲雀發布)是一種持續部署策略,它允許在正式環境的小部分用戶群體上先部署新版本的應用程序或服務,而不是一次性對所有用戶同時發布全新的版本。

這種方式有助于在生產環境中逐步驗證新版本的穩定性和兼容性,同時最小化潛在風險,不影響大部分用戶的正常使用。

1.灰度發布關鍵步驟

在 Spring Cloud 微服務架構中,實現灰度發布通常涉及到以下幾個方面:

  1. 流量分割

根據一定的策略(如用戶 ID、請求頭信息、IP 地址等)將流入的請求分配給不同版本的服務實例。

使用 Spring Cloud Gateway、Zuul 等 API 網關組件實現路由規則,將部分請求定向至新版本的服務節點。

  1. 版本標識

新版本服務啟動時會注冊帶有特定版本標簽的服務實例到服務注冊中心(如 Eureka 或 Nacos)。

請求在路由時可以根據版本標簽選擇相應版本的服務實例。

  1. 監控與評估

在灰度發布的階段,運維團隊會對新版本服務的性能、穩定性以及用戶體驗等方面進行實時監控和評估。

如果新版本表現良好,則可以逐漸擴大灰度范圍直至全面替換舊版本。

  1. 故障恢復與回滾:若新版本出現問題,可通過快速撤銷灰度發布策略,使所有流量恢復到舊版本服務,實現快速回滾,確保服務整體可用性。

通過 Spring Cloud 的擴展組件和自定義路由策略,開發人員可以輕松實現灰度發布功能,確保在微服務架構中安全、平滑地進行版本迭代升級。

2.實現思路

灰色發布的常見實現思路有以下幾種:

  • 根據用戶劃分:根據用戶標識或用戶組進行劃分,在整個用戶群體中只選擇一小部分用戶獲得新功能。
  • 根據地域劃分:在不同地區或不同節點上進行劃分,在其中的一小部分地區或節點進行新功能的發布。
  • 根據流量劃分:根據流量的百分比或請求次數進行劃分,只將一部分請求流量引導到新功能上。

而在生產環境中,比較常用的是根據用戶標識來實現灰色發布,也就是說先讓一小部分用戶體驗新功能,以發現新服務中可能存在的某種缺陷或不足。

3.底層實現

Spring Cloud 全鏈路灰色發布的關鍵實現思路如下圖所示:

圖片圖片

灰度發布的具體實現步驟如下:

  1. 前端程序在灰度測試的用戶 Header 頭中打上標簽,例如在 Header 中添加“gray-tag: true”,其表示要進行灰常測試(訪問灰度服務),而其他則為訪問正式服務。
  2. 在負載均衡器 Spring Cloud LoadBalancer 中,拿到 Header 中的“gray-tag”進行判斷,如果此標簽不為空,并等于“true”的話,表示要訪問灰度發布的服務,否則只訪問正式的服務。
  3. 在網關 Spring Cloud Gateway 中,將 Header 標簽“gray-tag: true”繼續往下一個調用服務中傳遞。
  4. 在后續的調用服務中,需要實現以下兩個關鍵功能:

在負載均衡器 Spring Cloud LoadBalancer 中,判斷灰度發布標簽,將請求分發到對應服務。

將灰度發布標簽(如果存在),繼續傳遞給下一個調用的服務。

經過第四步的反復傳遞之后,整個 Spring Cloud 全鏈路的灰度發布就完成了。

4.具體實現

4.1 版本標識

在灰度發布的執行流程中,有一個核心的問題,如果在 Spring Cloud LoadBalancer 進行服務調用時,區分正式服務和灰度服務呢?

這個問題的解決方案是:在灰度服務既注冊中心的 MetaData(元數據)中標識自己為灰度服務即可,而元數據中沒有標識(灰度服務)的則為正式服務,以 Nacos 為例,它的設置如下:

spring:
  application:
    name: gray-user-service
  cloud:
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848
        namespace: public
        register-enabled: true 
        metadata: { "gray-tag":"true" } # 標識自己為灰度服務

4.2 負載均衡調用灰度服務

Spring Cloud LoadBalancer 判斷并調用灰度服務的關鍵實現代碼如下:

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,
                                                          Request request) {
        // 實例為空
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serviceId);
            }
            return new EmptyResponse();
        } else { // 服務不為空
            RequestDataContext dataContext = (RequestDataContext) request.getContext();
            HttpHeaders headers = dataContext.getClientRequest().getHeaders();
            // 判斷是否為灰度發布(請求)
            if (headers.get(GlobalVariables.GRAY_KEY) != null &&
                    headers.get(GlobalVariables.GRAY_KEY).get(0).equals("true")) {
                // 灰度發布請求,得到新服務實例列表
                List<ServiceInstance> findInstances = instances.stream().
                        filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) != null &&
                                s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true"))
                        .toList();
                if (findInstances.size() > 0) { // 存在灰度發布節點
                    instances = findInstances;
                }
            } else { // 查詢非灰度發布節點
                // 灰度發布測試請求,得到新服務實例列表
                instances = instances.stream().
                        filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) == null ||
                                !s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true"))
                        .toList();
            }
            // 隨機正數值 ++i( & 去負數)
            int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
            // ++i 數值 % 實例數 取模 -> 輪詢算法
            int index = pos % instances.size();
            // 得到服務實例方法
            ServiceInstance instance = (ServiceInstance) instances.get(index);
            return new DefaultResponse(instance);
        }
    }

以上代碼為自定義負載均衡器,并使用了輪詢算法。如果 Header 中有灰度標簽,則只查詢灰度服務的節點實例,否則則查詢出所有的正式節點實例(以供服務調用或服務轉發)。

4.3 網關傳遞灰度標識

要在網關 Spring Cloud Gateway 中傳遞灰度標識,只需要在 Gateway 的全局自定義過濾器中設置 Response 的 Header 即可,具體實現代碼如下:

package com.example.gateway.config;

import com.loadbalancer.canary.common.GlobalVariables;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class LoadBalancerFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 得到 request、response 對象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        if (request.getQueryParams().getFirst(GlobalVariables.GRAY_KEY) != null) {
            // 設置金絲雀標識
            response.getHeaders().set(GlobalVariables.GRAY_KEY,
                    "true");
        }
        // 此步驟正常,執行下一步
        return chain.filter(exchange);
    }
}

4.4 微服務中傳遞灰度標簽

HTTP 調用工具 Openfeign,我們需要在微服務間繼續傳遞灰度標簽,它的實現代碼如下:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 從 RequestContextHolder 中獲取 HttpServletRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        // 獲取 RequestContextHolder 中的信息
        Map<String, String> headers = getHeaders(attributes.getRequest());
        // 放入 openfeign 的 RequestTemplate 中
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            template.header(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 獲取原請求頭
     */
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
        }
        return map;
    }
}


責任編輯:武曉燕 來源: Java中文社群
相關推薦

2022-12-05 09:08:12

微服務灰度發布

2023-11-21 09:35:49

全量部署微服務

2025-04-03 08:00:00

灰度發布Java開發

2024-03-06 15:38:06

Spring微服務架構擴展組件

2021-06-09 09:42:50

SpringCloud微服務灰度發布

2018-10-28 18:09:22

微服務Microservic架構

2024-06-04 07:58:31

架構本質微服務

2021-10-18 08:52:42

技術

2024-03-29 12:50:00

項目分層模型

2025-02-27 00:00:55

Dubbo服務不兼容

2021-08-19 15:36:09

數據備份存儲備份策略

2017-09-14 14:50:10

2024-06-07 09:13:23

2020-01-09 15:30:32

微服務架構互聯網

2020-02-08 16:46:29

微服務架構復雜

2024-02-22 08:31:26

數據恢復工具MySQL回滾SQL

2022-01-06 07:59:05

Linux 防火墻進程

2021-12-29 08:30:48

微服務架構開發

2024-11-06 16:27:12

2016-09-26 14:45:46

微服務
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 男女啪啪高潮无遮挡免费动态 | 精产国产伦理一二三区 | 久久精品国产亚洲a | 狠狠插天天干 | 国产色爽| 亚洲综合在线播放 | 国产日韩av一区二区 | 亚洲成人精品视频 | 精品久久久久久久久久久久久久 | 日韩精品一区二区三区中文字幕 | 伊人网综合在线观看 | 亚洲三区在线观看 | 91婷婷韩国欧美一区二区 | 一区二区日本 | 国产精品1区2区 | 亚洲视频中文字幕 | avhd101在线成人播放 | 性做久久久久久免费观看欧美 | 免费看国产精品视频 | 91精品久久久久久久 | 免费福利视频一区二区三区 | 在线观看中文字幕 | 综合色播 | 精品欧美一区免费观看α√ | 久优草| 五月天天丁香婷婷在线中 | 成人在线免费网站 | 日韩久久久久久久久久久 | 91久久久精品国产一区二区蜜臀 | 日韩视频高清 | 免费看黄色小视频 | 久久精品日产第一区二区三区 | 国产精品一区二区三 | 日韩久久久久久 | 黄色大片网 | 中文字幕日韩一区 | 国产伦精品一区二区三区四区视频 | 午夜精品久久久久久久久久久久久 | 精品粉嫩aⅴ一区二区三区四区 | 99精品在线观看 | 午夜专区 |