微服务TraceId设计(SpringCloud OpenFeign)
一、背景
在微服务框架下,需要通过traceId来定位到整个链路中每个细节的运行情况,这里不引用外部组件,自己来进行实现。当然还保证在多线程环境下的一致性。
二、需求
1)接口入口侧如果有traceId,则获取;如果没有则生成;
2)定义生成traceId的规则;
3)traceId可以默认打印到log中,不需要自己显示定义;
4)通过feign传输到后端服务中
三、实现
3.1)TraceId生成算法
参考:https://help.aliyun.com/document_detail/151840.html
-
public static String genTraceId() {
-
-
try {
-
StringBuilder sb = new StringBuilder();
-
InetAddress addr = InetAddress.getLocalHost();
-
if (null == addr) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
String addrStr = addr.getHostAddress();
-
if (null == addrStr) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
String[] addrArr = addrStr.split("\\.");
-
if (addrArr.length != 4) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
-
sb.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[0])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[1])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[2])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[3])) , 2, "0"))
-
.append(System.currentTimeMillis())
-
.append(RandomUtil.randomNumbers(4))
-
.append(ProcessHandle.current().pid());
-
-
return sb.toString();
-
} catch (Exception e) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
}
3.2)服务入口日志拦截
-
-
-
-
-
public class InterfaceLogAspect {
-
-
-
public Object interfaceAround(ProceedingJoinPoint joinPoint) {
-
String className = joinPoint.getTarget().getClass().getSimpleName();
-
Object[] args = joinPoint.getArgs();
-
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
-
Parameter[] argNames = signature.getMethod().getParameters();
-
StringBuilder sb = new StringBuilder(className "." joinPoint.getSignature().getName() " -- ");
-
-
//获取RequestAttributes
-
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
-
//从获取RequestAttributes中获取HttpServletRequest的信息
-
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
-
TraceIdUtil.initTraceId(request);
-
-
StopWatch clock = new StopWatch();
-
clock.start();
-
Object retVal = null;
-
try {
-
Map<String, Object> paramMap = new HashMap<>();
-
for (int i = 0; i < argNames.length; i ) {
-
paramMap.put(argNames[i].getName(), args[i]);
-
}
-
LoggerUtils.auditLogInfo(LogLabelEnum.REQUEST_IN.getLogLabel(), paramMap);
-
retVal = joinPoint.proceed(joinPoint.getArgs());
-
} catch (Throwable e) {
-
//..
-
} finally {
-
//..
-
}
-
return retVal;
-
}
-
}
3.3)FeignClient服务之间传递TraceId:
-
-
public class MyRequestInterceptor implements RequestInterceptor {
-
-
public void apply(RequestTemplate template) {
-
template.header(TraceIdUtil.TRACE_ID_KEY, TraceIdUtil.getTraceId());
-
}
-
}
3.4)logback.xml
-
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
-
<layout class="ch.qos.logback.classic.PatternLayout">
-
<pattern>[%-5level][%date{yyyy-MM-dd HH:mm:ss:SSS}][%logger:%line] --%mdc{client} %msg||traceId=%X{Trace-Id}%n</pattern>
-
-
</layout>
-
</appender>
备注:"%X{Trace-Id}"即将MDC中的以Trace-Id为key的值同步到日志中,也就是TraceIdUtil.TRACE_ID_KEY。
完整的TraceIdUtill为:
-
public class TraceIdUtil {
-
-
public static final String TRACE_ID_KEY = "Trace-Id";
-
-
public static final String TRACE_ID_VALUE_DEFAULT = "000000";
-
-
public static void setTraceId(String traceId) {
-
//如果参数为空,则设置默认traceId
-
//将traceId放到MDC中
-
MDC.put(TRACE_ID_KEY, traceId);
-
}
-
-
public static String getTraceId() {
-
String traceId = MDC.get(TRACE_ID_KEY);
-
-
return StringUtils.isNotBlank(traceId) ? traceId : TRACE_ID_VALUE_DEFAULT;
-
}
-
-
/**
-
* generate traceId: https://help.aliyun.com/document_detail/151840.html
-
*/
-
public static String genTraceId() {
-
-
try {
-
StringBuilder sb = new StringBuilder();
-
InetAddress addr = InetAddress.getLocalHost();
-
if (null == addr) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
String addrStr = addr.getHostAddress();
-
if (null == addrStr) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
String[] addrArr = addrStr.split("\\.");
-
if (addrArr.length != 4) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
-
sb.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[0])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[1])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[2])) , 2, "0"))
-
.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addrArr[3])) , 2, "0"))
-
.append(System.currentTimeMillis())
-
.append(RandomUtil.randomNumbers(4))
-
.append(ProcessHandle.current().pid());
-
-
return sb.toString();
-
} catch (Exception e) {
-
return TRACE_ID_VALUE_DEFAULT;
-
}
-
}
-
-
public static void initTraceId(HttpServletRequest request) {
-
String traceId = "";
-
if (request != null) {
-
//get traceId from request
-
traceId = request.getHeader(TraceIdUtil.TRACE_ID_KEY);
-
}
-
//generate new traceId
-
if (StringUtils.isBlank(traceId) || TRACE_ID_VALUE_DEFAULT.equals(traceId)){
-
traceId = TraceIdUtil.genTraceId();
-
}
-
-
TraceIdUtil.setTraceId(traceId);
-
}
-
-
public static void main(String[] args) {
-
System.out.println(TraceIdUtil.genTraceId());
-
}
-
}
四、多线程TraceId复制
4.1)线程配置
-
-
public class ThreadPoolConfig {
-
-
public static final String ASYNC_EXECUTOR_NAME = "threadPoolTaskExecutor";
-
-
-
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
-
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-
// for passing in request scope context
-
executor.setTaskDecorator(new ContextCopyingDecorator());
-
executor.setCorePoolSize(10);
-
executor.setMaxPoolSize(20);
-
executor.setQueueCapacity(100);
-
executor.setWaitForTasksToCompleteOnShutdown(true);
-
executor.setThreadNamePrefix("SeelAsyncThread-");
-
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
-
executor.initialize();
-
return executor;
-
}
-
}
4.2)定义TaskDecorator
-
public class ContextCopyingDecorator implements TaskDecorator {
-
-
-
public Runnable decorate(Runnable runnable) {
-
RequestAttributes context = RequestContextHolder.currentRequestAttributes();
-
Map<String, String> contextMap = MDC.getCopyOfContextMap();
-
return () -> {
-
try {
-
RequestContextHolder.setRequestAttributes(context);
-
MDC.setContextMap(contextMap);
-
runnable.run();
-
} finally {
-
RequestContextHolder.resetRequestAttributes();
-
}
-
};
-
}
-
}
Author:忆之独秀
Email:leaguenew@qq.com
转载注明出处:
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgjkheh
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13