官方参考文档:
https://istio.io/docs/tasks/telemetry/distributed-tracing/overview/
https://istio.io/docs/tasks/traffic-management/egress/
https://istio.io/docs/examples/advanced-gateways/egress-gateway/
https://istio.io/help/faq/distributed-tracing/#why-mixer-spans
(1)在使用Isito服务追踪之前,需要先开启选项(默认helm安装):
--set tracing.enabled=true;
(2)其次需要设定traceSampling(追踪百分比,范围0-100):
方式1:--set pilot.traceSampling=20
方式2:修改deployment->istio-pilot中环境变量 PILOT_TRACE_SAMPLING(默认1.0)
(3)暴露Jaeger dashboard:
可参见官网通过port-forward或k8s-ingress:https://istio.io/docs/tasks/telemetry/distributed-tracing/jaeger/
在实际使用中,可以直接建立k8s ingress与jaeger servcie对应即可:
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: tracing
spec:
rules:
- host: tracing.xxx.com
http:
paths:
- backend:
serviceName: tracing
servicePort: 80
Jaeger运行后,效果截图如下:
Istio中服务追踪默认只会追踪到2级,
例如A -> B -> C, 在Istio中会出现2条追踪链路:A -> B 和B -> C,而不会出现我们期望的A -> B -> C的形式,
如果想要服务串联起来,需要对服务间调用进行改造,在Istio中应用程序通过传播http header来将span关联到同一个trace;
Istio追踪相关http header如下:
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
服务间调用有很多方式,例如Spring RestTemplate, Apache HttpClient等,之前在项目中使用的自己封装的基于Apache HttpClient的服务调用工具,关于HttpClient可以通过对HttpClient设置拦截器进行相应reqeust header的提取与设置,具体代码如下:
/**
* Isito服务追踪 - 请求拦截器
*
* @author luohq
* @date 2019/5/30
*/
public class IstioTraceInterceptor implements HttpRequestInterceptor {private static final Logger logger = LogManager.getLogger(IstioTraceInterceptor.class);
/**
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
*/
private final ListTRACE_HEADER_LIST = Arrays.asList("x-request-id", "x-b3-traceid", "x-b3-spanid", "x-b3-parentspanid", "x-b3-sampled", "x-b3-flags", "x-ot-span-context"); /**
* 处理request请求 - 添加服务追踪相关请求header
*
* @param httpRequest
* @param httpContext
* @throws HttpException
* @throws IOException
*/
@Override
public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {
//从请求头中提取trace相关header(x-)
MapistioTraceHeaders = extractTraceHeaders();
//设置rpc外部调用trace相关header(x-)
istioTraceHeaders.forEach((headerName, headerVal) -> httpRequest.addHeader(headerName, headerVal));
}/**
* 从请求头中提取trace相关header(x-)
*
* @return
*/
private MapextractTraceHeaders() {
MaptraceHeaderMap = new HashMap<>(7);
try {
//获取当前SpringMvc上下文中的request对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//获取request请求中的所有header名称
EnumerationheaderNames = request.getHeaderNames();
//遍历header名称 -> 过滤出Istio追踪的相关的header
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (TRACE_HEADER_LIST.contains(headerName)) {
//提取Istio追踪的相关的header
traceHeaderMap.put(headerName, request.getHeader(headerName));
}
}
logger.debug("【ISTIO】cur request istio trace header: {}", traceHeaderMap);
} catch (Exception e) {
logger.debug("【ISTIO】extract request istio trace header fail!");
}
return traceHeaderMap;
}
}...
//构建HttpClient对象
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
//设置Isito服务追踪拦截器
.addInterceptorFirst(new IstioTraceInterceptor())
.build();
CloseableHttpResponse response = httpClient.execute(httpPost);
在对服务调用工具进行改造后,多服务间调用可以串联到一起(A -> B -> C),实际最终效果图如下:
在Istio1.1.0(实际使用1.1.7)中默认放开了对所有外部服务的访问权限,所以对外部服务的追踪默认是不生效的;
相关设置:global.outboundTrafficPolicy.mode=ALLOW_ANY(默认) | REGISTRY_ONLY
关于设置envoy可以访问外部服务,参见官方文档:https://istio.io/docs/tasks/traffic-management/egress/
若想对集群外服务进行追踪,需要通过egress网关的形式(ServcieEntry + EgressGateway + istio-egressgateway + DestinationRule + VirtualService),具体参见官方文档:https://istio.io/docs/examples/advanced-gateways/egress-gateway/
实际测试过程中只对Http请求进行了追踪而Https并没有生效,下图的测试用例对又拍云相关服务进行了追踪:
注:在进行了egress相关配置后,对外部服务的追踪并没有和downstream(调用方服务)串联起来,需要在调用外部服务的时候同样传播追踪相关的http header才能真正将外部服务与集群内服务的追踪串联起来(如上图效果),否则便会出现单独的追踪链路,如下图:
另外,关于egressgateway的相关配置过于繁琐难懂,如果没有特殊要求,不考虑配置istio-egressgateway出口网关(仅作为探索与学习),默认放开对所有外部服务的访问权限(同时也失去的对外部服务的控制权,无法将外部服务接入istio集群);
在实际测试过程中,会看到很多和istio-mixer相关的span,如下图:
上述istio-mixer相关调用是Isito执行policy检查时进行的Istio平台级调用,可以通过编辑 istio-policy 的deployment配置,删除命令行参数 --trace_zipkin_url=http://zipkin:9411/api/v1/spans以禁用对istio-mixer的追踪;
官方参考文档:https://istio.io/help/faq/distributed-tracing/#why-mixer-spans
另外由于Istio默认关闭了policy检查(global.disablePolicyChecks=true),所以在服务的实际调用过程中是不会去调用istio-mixer相关服务的,之所以会在上述服务追踪中多次出现istio-mixer相关span,是由于之前在进行rateLimits相关测试时开启了policy检查机制;
可以在kiali中集成Jaeger,集成方式如下:
(1)修改isttio-system -> configmap -> kiali -> jaeger.url:
jaeger:
url: http://tracing.xxx.com/jaeger
grafana:
url:
(2)重启istio-system -> deployment -> kiali即可
配置成功后会在kiali左侧菜单最下方出现【Distributed Tracing】菜单项,单击此菜单项则跳转到相应Jaeger页面;
同时在Services中的具体服务中,也可以单击【Traces】按钮弹出当前服务的追踪信息;
在Isito中的默认安装中,Jaeger默认使用内存来存储追踪记录,重启Jaeger后所有之前的追踪记录就都没有了,若真正想在生产环境使用Jaeger,需要集成自定义的Jaeger(可外接Cassandra, ES存储等);
Supported storage backends:
具体集成自定义Jaeger,继续探索......
Isito支持Envoy追踪(默认)和Mixer追踪,继续探索......;