公務員 做網(wǎng)站 違法網(wǎng)站制作網(wǎng)站推廣
思路
補充一下,為什么這里我會想到使用"pre"類型的過濾器實現(xiàn)流量復制/流量鏡像。
剛開始的時候,參考了阿里的流量鏡像實現(xiàn)方案: 配置流量復制策略,阿里的方案本身是對基于云原生envoy做的,這確實是istio原生能力。istio原生是通過配置spec.-mirror
這個參數(shù),開啟流量復制功能,阿里將這個功能白屏化并且對接了自己的監(jiān)控,不得不承認,阿里對原生istio的很友好。
kubectl describe vs my-virtualservice
隨后我嘗試了sidecar注入、修改envoy配置,但皆以失敗告終,一是平臺不支持VirtualService,二是平臺對Envoy做了一定的優(yōu)化,配置文件里的各種參數(shù)魔改的讓我摸不著頭腦。
直到上周,突然想到流量復制使用envoy來做的原因之一是因為envoy充當了網(wǎng)關,那可不可以用zuul來實現(xiàn)?有了這個想法后,立即搜索了一遍網(wǎng)上對于zuul的特性描述,只有極少數(shù)的博客提到了zuul的復制功能,但均無現(xiàn)成的實現(xiàn)。問題不大,有可行性就行。
實現(xiàn)過程很容易聯(lián)想到zuul的過濾器,因為pre過濾器可以完整地訪問和修改請求信息,可以直接拿到請求并將其復制給鏡像服務。有了這個思路一切就順利多啦~
Spring Cloud代碼
在zuul端創(chuàng)建class TrafficCopyFilter:
●假設provider-mirror是provider-demo的灰度應用
package com.tencent.tsf.msgw.zuul1.filter;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;import org.slf4j.Logger;public class TrafficCopyFilter extends ZuulFilter {private static final Logger LOG = LoggerFactory.getLogger(TrafficCopyFilter.class);private RestTemplate restTemplate = new RestTemplate();@Overridepublic String filterType() {return "pre";}@Overridepublic int filterOrder() {return 1;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();HttpServletRequest request = ctx.getRequest();// 檢查請求是否是發(fā)送給服務A的if (request.getRequestURI().contains("/provider-demo")) {LOG.info("復制請求到mirror服務");// 將請求復制到服務BString param = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1); // 提取參數(shù)String bServiceUrl = "http://svcb host ip:port/echo/" + param; //這里寫mirror服務的鏡像地址,后期可從配置文件中讀入HttpMethod method = HttpMethod.valueOf(request.getMethod());HttpHeaders headers = new HttpHeaders();Enumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String headerName = headerNames.nextElement();headers.add(headerName, request.getHeader(headerName));}HttpEntity<String> entity = new HttpEntity<>(headers);try {restTemplate.exchange(bServiceUrl, method, entity, Void.class);} catch (Exception e) {// 捕獲異常,避免影響客戶端LOG.error("復制請求到mirror服務失敗: {}", e.getMessage());}}return null;}
}
配置類
package com.tencent.tsf.msgw.zuul1.filter;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ZuulConfig {@Beanpublic TrafficCopyFilter trafficCopyFilter() {return new TrafficCopyFilter();}
}
最后,查看服務日志會發(fā)現(xiàn),通過zuul請求provider /echo 接口時,流量會被復制到provider-mirror
遺留的問題
查看apm調(diào)用鏈的時候,會發(fā)現(xiàn)調(diào)用鏈缺失,分析原因是因為traceid是在流量入口的時候生成的,使用zuul復制流量的過程相當于做了內(nèi)部的流量轉(zhuǎn)發(fā),不會在日志中生成traceid,也就無法生成調(diào)用鏈。