本次分享的是一个基于JAVA的微服务应用场景。后端使用SkyWalking进行链路监控,前端使用Sentry进行性能和异常监控。然而,在排查用户侧问题和优化站点性能时,前后端请求的关联性较差。因此,我们考虑使用Nginx的RequestID作为链路TrackID,将前后端链路打通,从而实现更高效的监控和问题排查。
如上图,用户通过前端发起请求,经过Nginx,再经微服务网关路由到微服务,微服务之间有相互调用。前端的信息和异常会上报给Sentry,后端的链路信息会上报给Skywalking。我们要做的就是统一TraceId,将整个链路打通。
为了统一Sentry、Nginx和Skywalking的TraceId,我们考虑使用RequestID给TraceId赋值,因此,需要对Skywalking Nginx Agent的代码进行小改动。
- 修改后的Skywalking Nginx Agent,下载地址
wget https://github.com/yilingyi/skywalking-nginx-lua-0.6.0/releases/download/0.6.0/skywalking-nginx-lua-0.6.0.tar.gz
- 修改内容
1. 修改tracing_context.lua,给链路追踪构造函数传递RequestID
2. 修改tracing_context.lua,将RequestID赋值给TraceId
Skywalking Nginx Agent模块的添加是基于之前分享的《Nginx编译安装秘笈:实用模块与自动化部署的完美结合》的基础上进行。
- 将skywalking-nginx-lua-0.6.0.tar.gz解压至路径/app/nginx/module
tar zxvf skywalking-nginx-lua-0.6.0.tar.gz -C /app/nginx/module
安装lua-cjson,Skywalking Nginx Agent依赖它,否则访问站点会报错
# 下载lua-cjsonwget https://github.com/yilingyi/lua-cjson/releases/download/2.1.0.8/lua-cjson-2.1.0.8.tar.gz
# 解压tar zxvf lua-cjson-2.1.0.8.tar.gz
# 进入目录cd lua-cjson-2.1.0.8
# 编译cc -c -O3 -Wall -pedantic -DNDEBUG -I/app/nginx/module/luajit/include/luajit-2.0 -fpic -o lua_cjson.o lua_cjson.c
# 安装make && make install
lua-cjson安装成功后,就可以通过编译增加skywalking-nginx-lua-0.6.0模块了
# 编译./configure --conf-path=/app/nginx/conf/nginx.conf \ --user=nginx \ --group=nginx \ --prefix=/app/nginx \ --with-stream \ --with-http_stub_status_module \ --with-http_realip_module \ --with-http_gzip_static_module \ --with-http_ssl_module \ --with-http_sub_module \ --with-http_v2_module \ --add-module=/app/nginx/module/nginx_upstream_check_module-0.4.0 \ --with-ld-opt=-Wl,-rpath,/app/nginx/module/luajit/lib \ --add-module=/app/nginx/module/headers-more-nginx-module-0.33 \ --add-module=/app/nginx/module/ngx_devel_kit-0.3.0 \ --add-module=/app/nginx/module/lua-nginx-module-0.10.10 \ --add-module=/app/nginx/module/set-misc-nginx-module-0.31 \ --add-module=/app/nginx/module/skywalking-nginx-lua-0.6.0 # 安装make && make install
模块添加后,还需要在nginx.conf的http上下文中引用Skywalking Nginx Agent
http { include mime.types; default_type application/octet-stream; ... ... # skywalking-nginx-lua模块的路径 lua_package_path "/app/nginx/module/skywalking-nginx-lua-0.6.0/lib/?.lua;;";
# 共享字典,在高并发或大量上报数据的场景中,共享字典用于缓存链路信息时,如果分配的内存大小不足,可能会导致部分链路信息被丢弃 lua_shared_dict tracing_buffer 1024m;
init_worker_by_lua_block { local metadata_buffer = ngx.shared.tracing_buffer # 定义上报skywalking的服务名称 metadata_buffer:set('serviceName', 'yilingyi-nginx') # 定义上报skywalking的服务名称下的实例名,如果有多nginx实例,可以用这个配置进行区分 metadata_buffer:set('serviceInstanceName', 'yilingyi-nginx-1') metadata_buffer:set('includeHostInEntrySpan', false) require("skywalking.util").set_randomseed() # skywalking oap服务的接口地址 require("skywalking.client"):startBackendTimer("http://172.101.0.6:12800") skywalking_tracer = require("skywalking.tracer")}
接着在需要监控链路信息的vhost进行埋点,并将Nginx的RequestID传给前后端
server { listen 80; ... ... underscores_in_headers on; # 返回给前端,前端在拦截处增加extra附加信息traceid add_header x-request-id $request_id;
location /api { # 请求开始时的埋点 rewrite_by_lua_block { skywalking_tracer:start("upstream service") }
proxy_pass http://yilingyi_backend; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递给后端,后端在获取后给traceid赋值 proxy_set_header x-request-id $request_id;
# 请求结束时的埋点 body_filter_by_lua_block { if ngx.arg[2] then skywalking_tracer:finish() end } # 日志记录阶段的埋点 log_by_lua_block { skywalking_tracer:prepareForReport() } } ... ...}
最后就是配置reload了,由于reload时不检查lua的语法,所以建议在配置验证后再上生产
systemctl reload nginx
通过上述配置和前后端代码实现TraceID赋值后,我们就可以统一前端、网关及后端的TraceId,打通整个请求链路了,在问题排查和性能分析上大大提效,本期就分享到这里,谢谢!