- 浏览: 56438 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (117)
- RPC相关 (4)
- mvc_controller (3)
- mvc_model (3)
- maven (4)
- mvc_view (5)
- IO (2)
- 业务相关 (2)
- MQ (7)
- 搜索引擎 (3)
- zookeeper (2)
- 工具相关 (4)
- 编辑错误 (1)
- tomcat (1)
- 单元测试 (1)
- 负载均衡 (1)
- ubuntu (1)
- nginx (1)
- dubbo (2)
- 网络站点分发 (1)
- 电商-支付相关 (10)
- 电商订单业务相关 (3)
- Core java1 (3)
- Core Java (12)
- 多线程高并发(并发包/线程/锁) (10)
- 数据库+缓存 (17)
- springcloud (2)
- jvm (5)
- 日志相关 (1)
- 算法 (3)
- spring (2)
- 分布式一致性算法 (1)
最新评论
zipkin链路监控跟踪
- 博客分类:
- 日志相关
zipkin链路跟踪:
多服务之间调用,服务与服务之间监控,原理是在发送和接收请求时由brave异步传输(HTTP, Kafka和Scribe)给zipkin传输记录,zipkin把记录整理存储起来(可以内存,DB,es等)。
同时zipkin有自己的ui可以展示给我们使用,调查日志。
另外zipkin也可以使用brave-mysql类库跟踪业务DB,增加MySQLStatementInterceptorManagementBean方法实例 ,原理是在jdbc时进行拦截把记录放到zipkin。
OkHttpClient调用发起http请求。在每次发起请求时则需要通过brave记录Span信息,并异步传递给zipkin
作为被调用方(服务端)也同样需要完成以上操作。
zipkin链路跟踪mysql:
maven引用brave-mysql类库,增加MySQLStatementInterceptorManagementBean实例 ,原理是在jdbc时进行拦截把记录放到zipkin。
cs:Client Send,客户端发起请求;
sr:Server Receive,服务器接受请求,开始处理;
ss:Server Send,服务器完成处理,给客户端应答;
cr:Client Receive,客户端接受应答从服务器;
zipkin参考:
zipkin入门和brave源码:
https://blog.csdn.net/john1337/article/details/71127056/
https://blog.csdn.net/apei830/article/details/78722180
brave-mysql:
https://www.cnblogs.com/java-zhao/p/5858138.html
https://www.h3399.cn/201805/576621.html
google dapper
package com.pingan.haofang.qypms.common.configuration.zipkin;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.filter.GenericFilterBean;
import com.alibaba.fastjson.JSONObject;
/**
* @Author: huaxiuming
* @Description: [此处填写类的描述信息]
* @Date: Created in 15:21 2019-3-4
* @Modified By:
*/
public class HttpResponseInjectingTraceFilter extends GenericFilterBean {
private static final Logger logger = LoggerFactory
.getLogger(HttpResponseInjectingTraceFilter.class);
private final Tracer tracer;
public HttpResponseInjectingTraceFilter(Tracer tracer) {
this.tracer = tracer;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
Span currentSpan = this.tracer.getCurrentSpan();
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 添加头部信息
Map<String, String> headerMap = new HashMap<String, String>();
Enumeration<String> enume = httpRequest.getHeaderNames();
while (enume.hasMoreElements()) {
String key = enume.nextElement();
String value = httpRequest.getHeader(key);
headerMap.put(key, value);
}
if (headerMap.size() > 0) {
currentSpan.tag("http.head", JSONObject.toJSONString(headerMap));
}
//方法名
String method = httpRequest.getMethod();
currentSpan.tag("request.method", method);
RequestWrapper wrapperRequest = new RequestWrapper(httpRequest);// 转换成代理类
ResponseWrapper wrapperResponse = new ResponseWrapper(
(HttpServletResponse) response);// 转换成代理类
// 拦截返回
filterChain.doFilter(wrapperRequest, wrapperResponse);
// 添加参数信息
String params = this.getRequestParameter(wrapperRequest);
currentSpan.tag("http.params", params);
// 添加返回值信息
byte[] content = wrapperResponse.getContent();// 获取返回值
// 判断是否有值
if (content.length > 0) {
try {
String result = new String(content, "UTF-8");
currentSpan.tag("http.result", result);
} catch (Exception e) {
logger.error("添加返回值信息异常", e);
}
}
// 把返回值输出到客户端
ServletOutputStream out = null;
try {
out = response.getOutputStream();
} catch (Exception e) {
} finally {
try {
if (out != null) {
out.write(content);
out.flush();
out.close();
}
} catch (IOException e) {
}
}
}
/**
* 方法功能说明: 获取请求参数包括form表单和json参数
*/
public String getRequestParameter(RequestWrapper wrapperRequest) {
if (null == wrapperRequest) {
return null;
}
String params = null;
String method = wrapperRequest.getMethod();
if (StringUtils.isNotBlank(method) && "GET".equals(method.toUpperCase())) {
// 获取请求体中的字符串(get)
params = wrapperRequest.getQueryString();
try {
if (StringUtils.isNotBlank(params)) {
params = URLDecoder.decode(params, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
// Logger.error("获取到的请求参数解码错误 : {}", e.getMessage());
}
return params;
} else {
return wrapperRequest.getBodyString(wrapperRequest);
}
}
}
多服务之间调用,服务与服务之间监控,原理是在发送和接收请求时由brave异步传输(HTTP, Kafka和Scribe)给zipkin传输记录,zipkin把记录整理存储起来(可以内存,DB,es等)。
同时zipkin有自己的ui可以展示给我们使用,调查日志。
另外zipkin也可以使用brave-mysql类库跟踪业务DB,增加MySQLStatementInterceptorManagementBean方法实例 ,原理是在jdbc时进行拦截把记录放到zipkin。
OkHttpClient调用发起http请求。在每次发起请求时则需要通过brave记录Span信息,并异步传递给zipkin
作为被调用方(服务端)也同样需要完成以上操作。
zipkin链路跟踪mysql:
maven引用brave-mysql类库,增加MySQLStatementInterceptorManagementBean实例 ,原理是在jdbc时进行拦截把记录放到zipkin。
cs:Client Send,客户端发起请求;
sr:Server Receive,服务器接受请求,开始处理;
ss:Server Send,服务器完成处理,给客户端应答;
cr:Client Receive,客户端接受应答从服务器;
zipkin参考:
zipkin入门和brave源码:
https://blog.csdn.net/john1337/article/details/71127056/
https://blog.csdn.net/apei830/article/details/78722180
brave-mysql:
https://www.cnblogs.com/java-zhao/p/5858138.html
https://www.h3399.cn/201805/576621.html
google dapper
package com.pingan.haofang.qypms.common.configuration.zipkin; import com.github.kristofa.brave.Brave; import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler; import com.github.kristofa.brave.Sampler; import com.github.kristofa.brave.SpanCollector; import com.github.kristofa.brave.http.DefaultSpanNameProvider; import com.github.kristofa.brave.http.HttpSpanCollector; import com.github.kristofa.brave.mysql.MySQLStatementInterceptorManagementBean; import com.github.kristofa.brave.okhttp.BraveOkHttpRequestResponseInterceptor; import com.github.kristofa.brave.servlet.BraveServletFilter; import okhttp3.OkHttpClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author: huaxiuming * @Description: [此处填写类的描述信息] * @Date: Created in 15:22 2019-3-4 * @Modified By: */ @Configuration public class SqlSpanConfig { @Autowired private ZipkinProperties properties; // @Bean // HttpResponseInjectingTraceFilter responseInjectingTraceFilter(Brave brave) { // return new HttpResponseInjectingTraceFilter(brave.localTracer()); // } @Bean public SpanCollector spanCollector() { HttpSpanCollector.Config config = HttpSpanCollector.Config.builder().connectTimeout(properties.getConnectTimeout()).readTimeout(properties.getReadTimeout()) .compressionEnabled(properties.isCompressionEnabled()).flushInterval(properties.getFlushInterval()).build(); return HttpSpanCollector.create(properties.getUrl(), config, new EmptySpanCollectorMetricsHandler()); } @Bean public Brave brave(SpanCollector spanCollector){ Brave.Builder builder = new Brave.Builder(properties.getServiceName()); //指定state builder.spanCollector(spanCollector); builder.traceSampler(Sampler.ALWAYS_SAMPLE); Brave brave = builder.build(); return brave; } @Bean public BraveServletFilter braveServletFilter(Brave brave){ BraveServletFilter filter = new BraveServletFilter(brave.serverRequestInterceptor(),brave.serverResponseInterceptor(),new DefaultSpanNameProvider()); return filter; } @Bean public OkHttpClient okHttpClient(Brave brave){ OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new BraveOkHttpRequestResponseInterceptor(brave.clientRequestInterceptor(), brave.clientResponseInterceptor(), new DefaultSpanNameProvider())) .build(); return client; } @Bean public MySQLStatementInterceptorManagementBean mySQLStatementInterceptorManagementBean(Brave brave) { return new MySQLStatementInterceptorManagementBean(brave.clientTracer()); } }
package com.pingan.haofang.qypms.common.configuration.zipkin;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.filter.GenericFilterBean;
import com.alibaba.fastjson.JSONObject;
/**
* @Author: huaxiuming
* @Description: [此处填写类的描述信息]
* @Date: Created in 15:21 2019-3-4
* @Modified By:
*/
public class HttpResponseInjectingTraceFilter extends GenericFilterBean {
private static final Logger logger = LoggerFactory
.getLogger(HttpResponseInjectingTraceFilter.class);
private final Tracer tracer;
public HttpResponseInjectingTraceFilter(Tracer tracer) {
this.tracer = tracer;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
Span currentSpan = this.tracer.getCurrentSpan();
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 添加头部信息
Map<String, String> headerMap = new HashMap<String, String>();
Enumeration<String> enume = httpRequest.getHeaderNames();
while (enume.hasMoreElements()) {
String key = enume.nextElement();
String value = httpRequest.getHeader(key);
headerMap.put(key, value);
}
if (headerMap.size() > 0) {
currentSpan.tag("http.head", JSONObject.toJSONString(headerMap));
}
//方法名
String method = httpRequest.getMethod();
currentSpan.tag("request.method", method);
RequestWrapper wrapperRequest = new RequestWrapper(httpRequest);// 转换成代理类
ResponseWrapper wrapperResponse = new ResponseWrapper(
(HttpServletResponse) response);// 转换成代理类
// 拦截返回
filterChain.doFilter(wrapperRequest, wrapperResponse);
// 添加参数信息
String params = this.getRequestParameter(wrapperRequest);
currentSpan.tag("http.params", params);
// 添加返回值信息
byte[] content = wrapperResponse.getContent();// 获取返回值
// 判断是否有值
if (content.length > 0) {
try {
String result = new String(content, "UTF-8");
currentSpan.tag("http.result", result);
} catch (Exception e) {
logger.error("添加返回值信息异常", e);
}
}
// 把返回值输出到客户端
ServletOutputStream out = null;
try {
out = response.getOutputStream();
} catch (Exception e) {
} finally {
try {
if (out != null) {
out.write(content);
out.flush();
out.close();
}
} catch (IOException e) {
}
}
}
/**
* 方法功能说明: 获取请求参数包括form表单和json参数
*/
public String getRequestParameter(RequestWrapper wrapperRequest) {
if (null == wrapperRequest) {
return null;
}
String params = null;
String method = wrapperRequest.getMethod();
if (StringUtils.isNotBlank(method) && "GET".equals(method.toUpperCase())) {
// 获取请求体中的字符串(get)
params = wrapperRequest.getQueryString();
try {
if (StringUtils.isNotBlank(params)) {
params = URLDecoder.decode(params, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
// Logger.error("获取到的请求参数解码错误 : {}", e.getMessage());
}
return params;
} else {
return wrapperRequest.getBodyString(wrapperRequest);
}
}
}
package com.pingan.haofang.qypms.common.configuration.zipkin; import org.springframework.cloud.sleuth.Tracer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author: huaxiuming * @Description: [此处填写类的描述信息] * @Date: Created in 15:22 2019-3-4 * @Modified By: */ @Configuration public class HttpSpanConfig { @Bean HttpResponseInjectingTraceFilter responseInjectingTraceFilter(Tracer tracer) { return new HttpResponseInjectingTraceFilter(tracer); } }
package com.pingan.haofang.qypms.common.configuration.zipkin; import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.SpanTextMap; import org.springframework.cloud.sleuth.instrument.web.ZipkinHttpSpanInjector; /** * @Author: huaxiuming * @Description: [此处填写类的描述信息] * @Date: Created in 15:20 2019-3-4 * @Modified By: */ public class CustomHttpServletResponseSpanInjector extends ZipkinHttpSpanInjector { @Override public void inject(Span span, SpanTextMap carrier) { super.inject(span, carrier); carrier.put(Span.TRACE_ID_NAME, span.traceIdString()); carrier.put(Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId())); } }
package com.pingan.haofang.qypms.common.configuration.zipkin; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Enumeration; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.commons.lang3.StringUtils; import org.springframework.util.StreamUtils; /** * @Author: huaxiuming * @Description: [请求输出代理类] * @Date: Created in 15:23 2019-3-4 * @Modified By: */ public class RequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public RequestWrapper(HttpServletRequest request) throws IOException { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(Charset.forName("UTF-8")); } /** * 获取请求Body * * @param request * @return */ public String getBodyString(final ServletRequest request) { String contentType = request.getContentType(); String bodyString = ""; if (StringUtils.isNotBlank(contentType) && (contentType.contains("multipart/form-data") || contentType.contains("x-www-form-urlencoded"))) { Enumeration<String> pars = request.getParameterNames(); while (pars.hasMoreElements()) { String n = pars.nextElement(); bodyString += n + "=" + request.getParameter(n) + "&"; } bodyString = bodyString.endsWith("&") ? bodyString.substring(0, bodyString.length() - 1) : bodyString; return bodyString; } try { byte[] byteArray = StreamUtils.copyToByteArray(request.getInputStream()); bodyString = new String(byteArray, "UTF-8"); } catch (IOException e) { } return bodyString; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } }
相关推荐
zipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪。 zipkin主要涉及四个组件 collector storage search web UI 1.Collector接收各service传输的数据 2.Cassandra作为Storage的一...
SpringCloud的Demo,里面包含,服务注册与发现、分布式链路跟踪、分布式服务跟踪zipkin、健康检查、断路器、分布式网关、分布式配置
zipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪。pinpoint是开源在github上的一款APM监控工具,它是用Java编写的,用于大规模分布式系统监控。它对性能的影响最小(只增加约3%...
+ openFeign远程调用 + gateway网关+ tkMybatis+druid+dynamic-datasource多数据源 + pagehelper分页插件 + MGB自动代码生成 + seata分布式事务+ sentinel服务限流降级 + sleuth-zipkin链路跟踪 + spring-boot-admin...
zipkinzipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪
zipkin为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪。 architecture 如图,在复杂的调用链路中假设存在一条调用链路响应缓慢,如何定位其中延迟高的服务呢? 日志: 通过分析调用...
Spring Cloud Config:配置管理工具,目前支持本地存储、Git以及Subversion,可以实现应用配置的外部化存储,支持客户端配置...Zipkin:为分布式链路调用监控系统,聚合各业务系统调用延迟数据,达到链路调用监控跟踪。
springcloud-zipkin:链路跟踪工具,监控并就持久化微服务集群中调用链路的通畅情况,采用rabbitmq异步传输、elasticsearch负责持久化的方式集成。 #### 软件架构 1、JDK:jdk-8u181-windows-x64。 2、MAVEN:...
使用相关组件下载地址,其项目是基于SpringCloud的模板项目。 纳科斯 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、 ...Zipkin是一个分布式跟踪系统。
Spring Cloud微服务开发实践系列文章,详细介绍了微服务开发流程。 部分内容如下: ...14、分布式链路跟踪和 Spring Cloud Sleuth 15、Zipkin 介绍与实践 16、Nacos 基础用法 17微服务常见面试题分析
服务注册、发现: eureka配置管理:spring config集群容错: hystrixAPI网关: zuul服务负载:feign+ribbonapi文档输出:swagger2链路跟踪:spring cloud sletuh ->zipkin安全认证:jwt服务监控:spring-boot-admin各模块介绍...
rabbitmq分布式锁: redis (待实现)链路跟踪:spring cloud sletuh ->zipkin安全认证:oauth2/JWT(通过JWT轻量级的实现)服务监控:spring-boot-admin各模块介绍模块名称端口简介admin-server9002服
- [springcloud(十二):使用Spring Cloud Sleuth和Zipkin进行分布式链路跟踪](http://www.ityouknow.com/springcloud/2018/02/02/spring-cloud-sleuth-zipkin.html) - [springcloud(十三):Spring Cloud Consul ...