产生背景
-
日志追踪
- 当一个 Request 通过层层关卡到 Server,一般会产生多个系统的日志,包括但不限于:访问日志、异常日志、SQL日志、第三方服务日志等,而当发生了线上问题的时候,需要进行溯源排查。一般的做法是在请求之处,生成一个 unique traceId,此 id 在所有日志中携带就可以追踪该请求的所有链路,这就是所谓的全链路日志追踪
解决方案
全局变量
const http = require('http');
let globalTraceId
function handleRequest(req, res) {
globalTraceId = generateTraceId()
cookieValidator().then((res) => {
}).catch((err) => {
reportError(err, globalTraceId)
});
}
const server = http.createServer((req, res) => {
handleRequest(req, res)
});
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
- 缺点:因为是全局变量,通过异步上报 globalTraceId 时,存在下一次请求更改 globalTraceId,导致数据不一致的问题
通过参数传递
const http = require('http');
function handleRequest(req, res) {
const traceId = req.headers['x-trace-id'] || generateTraceId();
req.traceId = traceId;
cookieValidator().then((result) => {
}).catch((err) => {
reportError(err, req.traceId)
});
}
function cookieValidator() {
return new Promise((resolve, reject) => {
setTimeout(() => {
}, 1000);
});
}
依赖注入
- 具体查看 next.js,底层使用了 AsyncLocalStorage
AsyncLocalStorage
- AsyncLocalStorage 是基于 node:async_hooks 实现的,并且(比之其他方法)是性能好、内存安全的方法,允许在 Web 请求的整个生命周期或任何其他异步持续时间内存储数据
- 详情
import http from 'node:http';
import { AsyncLocalStorage } from 'node:async_hooks';
const asyncLocalStorage = new AsyncLocalStorage();
let traceId = 0;
http.createServer((req, res) => {
asyncLocalStorage.run(traceId++, () => {
const traceId = asyncLocalStorage.getStore();
console.log(`${traceId}:`, 'start');
setImmediate(() => {
const traceId = asyncLocalStorage.getStore();
console.log(`${traceId}:`, 'finish');
res.end();
});
});
}).listen(8080);
http.get('http://localhost:8080');
http.get('http://localhost:8080');