公務(wù)員 做網(wǎng)站 違法網(wǎng)站制作網(wǎng)站推廣
思路
補(bǔ)充一下,為什么這里我會(huì)想到使用"pre"類型的過濾器實(shí)現(xiàn)流量復(fù)制/流量鏡像。
剛開始的時(shí)候,參考了阿里的流量鏡像實(shí)現(xiàn)方案: 配置流量復(fù)制策略,阿里的方案本身是對基于云原生envoy做的,這確實(shí)是istio原生能力。istio原生是通過配置spec.-mirror
這個(gè)參數(shù),開啟流量復(fù)制功能,阿里將這個(gè)功能白屏化并且對接了自己的監(jiān)控,不得不承認(rèn),阿里對原生istio的很友好。
kubectl describe vs my-virtualservice
隨后我嘗試了sidecar注入、修改envoy配置,但皆以失敗告終,一是平臺(tái)不支持VirtualService,二是平臺(tái)對Envoy做了一定的優(yōu)化,配置文件里的各種參數(shù)魔改的讓我摸不著頭腦。
直到上周,突然想到流量復(fù)制使用envoy來做的原因之一是因?yàn)閑nvoy充當(dāng)了網(wǎng)關(guān),那可不可以用zuul來實(shí)現(xiàn)?有了這個(gè)想法后,立即搜索了一遍網(wǎng)上對于zuul的特性描述,只有極少數(shù)的博客提到了zuul的復(fù)制功能,但均無現(xiàn)成的實(shí)現(xiàn)。問題不大,有可行性就行。
實(shí)現(xiàn)過程很容易聯(lián)想到zuul的過濾器,因?yàn)閜re過濾器可以完整地訪問和修改請求信息,可以直接拿到請求并將其復(fù)制給鏡像服務(wù)。有了這個(gè)思路一切就順利多啦~
Spring Cloud代碼
在zuul端創(chuàng)建class TrafficCopyFilter:
●假設(shè)provider-mirror是provider-demo的灰度應(yīng)用
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ā)送給服務(wù)A的if (request.getRequestURI().contains("/provider-demo")) {LOG.info("復(fù)制請求到mirror服務(wù)");// 將請求復(fù)制到服務(wù)BString param = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1); // 提取參數(shù)String bServiceUrl = "http://svcb host ip:port/echo/" + param; //這里寫mirror服務(wù)的鏡像地址,后期可從配置文件中讀入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("復(fù)制請求到mirror服務(wù)失敗: {}", 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();}
}
最后,查看服務(wù)日志會(huì)發(fā)現(xiàn),通過zuul請求provider /echo 接口時(shí),流量會(huì)被復(fù)制到provider-mirror
遺留的問題
查看apm調(diào)用鏈的時(shí)候,會(huì)發(fā)現(xiàn)調(diào)用鏈缺失,分析原因是因?yàn)閠raceid是在流量入口的時(shí)候生成的,使用zuul復(fù)制流量的過程相當(dāng)于做了內(nèi)部的流量轉(zhuǎn)發(fā),不會(huì)在日志中生成traceid,也就無法生成調(diào)用鏈。