尽管有诸多优势,微服务架构也带来了新的复杂性。其中一项挑战是,在构成应用的所有微服务之间传输数据时,跟踪请求的处理过程。为此,人们提出了一种名为分布式(请求)追踪的新方法,而OpenTracing是一套规范和标准API,旨在指导分布式追踪工具的设计与实现。
在NGINX Plus Release 18(R18)中,我们将NGINX OpenTracing模块添加到了动态模块存储库中(此前,它已作为GitHub上的第三方模块提供了数年)。NGINX OpenTracing模块的一大优势是,只需对NGINX和NGINX Plus进行分布式追踪插桩,即可获取每个代理应用的追踪数据,无需逐一对应用进行插桩。
本文介绍如何为NGINX或NGINX Plus的请求启用分布式追踪(为简洁起见,下文统称为“NGINX Plus”)。本文提供两种分布式追踪服务(在OpenTracing术语中称为“追踪器”)的配置说明,即Jaeger和Zipkin。(如需查看其他追踪器的列表,请参阅OpenTracing文档。)为说明追踪器可提供的信息,本文对比了启用NGINX Plus缓存前后的请求处理情况。
追踪器包含两个基本组件:
- 一种代理,用于从与其运行在同一主机上的应用程序中收集跟踪数据。在本例中,“应用程序”是NGINX Plus,代理以插件形式实现。
- 一种服务器(也称为“收集器”),用于接收来自一个或多个代理的跟踪数据,并将其显示在中央UI中。可根据需要在NGINX Plus主机或其他主机上运行该服务器。
安装跟踪服务器
第一步是为所选的追踪器安装并配置服务器。本文提供了 Jaeger 和 Zipkin 的操作说明;如使用其他追踪器,请根据需要进行调整。
安装Jaeger服务器
建议使用以下方法安装Jaeger服务器。也可以通过步骤 1 中指定的URL下载Docker镜像。
- 转到Jaeger 下载页面,然后下载 Linux 二进制文件(撰写本文时为 jaeger-1.12.0-linux-amd64.tar)。
- 将二进制文件移至/usr/bin/jaeger(如有必要,请先创建该目录),然后运行该文件。
$ mkdir /usr/bin/jaeger$ mv jaeger-1.12.0-linux-amd64.tar /usr/bin/jaeger
$ cd /usr/bin/jaeger
$ tar xvzf jaeger-1.12.0-linux-amd64.tar.gz
$ sudo rm -rf jaeger-1.12.0-linux-amd64.tar.gz
$ cd jaeger-1.12.0-linux-amd64
$ ./jaeger-all-in-one- 确认可在浏览器中通过 http://Jaeger-server-IP-address:16686/ 访问Jaeger UI(16686是Jaeger服务器的默认端口)。
安装Zipkin服务器
- 下载并运行Zipkin的Docker镜像(此处使用默认端口9411)。
$ docker run -d -p 9411:9411 openzipkin/zipkin- 确认可在浏览器中通过 http://Zipkin-server-IP-address:9411/ 访问 Zipkin UI。
安装和配置追踪器插件
在NGINX Plus主机上运行以下命令,安装Jaeger或Zipkin插件。
安装Jaeger插件
- 安装Jaeger插件。以下
wget命令适用于x86-64 Linux系统:
$ cd /usr/local/lib
$ wget https://github.com/jaegertracing/jaeger-client-cpp/releases/download/v0.4.2/libjaegertracing_plugin.linux_amd64.so -O /usr/local/lib/libjaegertracing_plugin.so- 有关从源代码构建插件的说明,请参阅GitHub。
- 为该插件创建一个JSON格式的配置文件,将其命名为/etc/jaeger/jaeger-config.json,并写入以下内容。此处使用Jaeger服务器的默认端口6831:
{ "service_name": "nginx",
"sampler": {
"type": "const",
"param": 1
},
"reporter": {
"localAgentHostPort": "Jaeger-server-IP-address:6831"
}
}- 有关
sampler对象的详细信息,请参阅Jaeger文档。
安装Zipkin插件
- 安装Zipkin插件。以下
wget命令适用于x86-64 Linux系统:
$ cd /usr/local/lib$ wget -O - https://github.com/rnburn/zipkin-cpp-opentracing/releases/download/v0.5.2/linux-amd64-libzipkin_opentracing_plugin.so.gz | gunzip -c > /usr/local/lib/libzipkin_opentracing_plugin.so- 为该插件创建一个JSON格式的配置文件,命名为/etc/zipkin/zipkin-config.json,并写入以下内容。此处使用Zipkin服务器的默认端口9411:
{ "service_name": "nginx",
"collector_host": "Zipkin-server-IP-address",
"collector_port": 9411
}- 有关配置对象的详细信息,请参阅GitHub上的JSON架构。
配置NGINX Plus
在NGINX Plus主机上执行以下操作。
- 按照NGINX Plus 管理指南中的说明安装NGINX OpenTracing模块。
- 在NGINX Plus主配置文件(
load_module)的主(顶层)上下文中添加以下/etc/nginx/nginx.conf指令:
load_module modules/ngx_http_opentracing_module.so;- 将以下指令添加到NGINX Plus配置中。如果使用常规配置方案,请将这些指令放入名为/etc/nginx/conf.d/opentracing.conf的新文件中。此外,请确认以下
include指令位于/etc/nginx/nginx.conf的http上下文中:
http {
include /etc/nginx/conf.d/*.conf;
}# Load a vendor tracer#opentracing_load_tracer /usr/local/libjaegertracing_plugin.so
# /etc/jaeger/jaeger-config.json;
#opentracing_load_tracer /usr/local/lib/libzipkin_opentracing_plugin.so
# /etc/zipkin/zipkin-config.json;
# Enable tracing for all requests
opentracing on;
# Set additional tags that capture the value of NGINX Plus variables
opentracing_tag bytes_sent $bytes_sent;
opentracing_tag http_user_agent $http_user_agent;
opentracing_tag request_time $request_time;
opentracing_tag upstream_addr $upstream_addr;
opentracing_tag upstream_bytes_received $upstream_bytes_received;
opentracing_tag upstream_cache_status $upstream_cache_status;
opentracing_tag upstream_connect_time $upstream_connect_time;
opentracing_tag upstream_header_time $upstream_header_time;
opentracing_tag upstream_queue_time $upstream_queue_time;
opentracing_tag upstream_response_time $upstream_response_time;
#uncomment for debugging
# log_format opentracing '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for" '
# '"$host" sn="$server_name" '
# 'rt=$request_time '
# 'ua="$upstream_addr" us="$upstream_status" '
# 'ut="$upstream_response_time" ul="$upstream_response_length" '
# 'cs=$upstream_cache_status';
#access_log /var/log/nginx/opentracing.log opentracing;
server {
listen 9001;
location / {
# The operation name used for OpenTracing Spans defaults to the name of the
# 'location' block, but uncomment this directive to customize it.
#opentracing_operation_name $uri;
# Propagate the active Span context upstream, so that the trace can be
# continued by the backend.
opentracing_propagate_context;
# Make sure that your Ruby app is listening on port 4567
proxy_pass http://127.0.0.1:4567;
}
}- The
opentracing_load_tracer指令用于启用跟踪器插件。根据需要,取消注释 Jaeger 或 Zipkin 对应的指令。 - The
opentracing_tag指令使 NGINX Plus 变量可用作 OpenTracing 标签,并显示在跟踪器 UI 中。 - 要调试OpenTracing活动,请取消注释
log_format和access_log指令。如果要用此访问日志和日志格式替换NGINX的默认设置,请取消注释这些指令,然后将其中三处“opentracing”更改为“main”。另一种方法是仅记录端口9001上的流量所产生的OpenTracing活动。为此,请取消注释log_format和access_log指令,并将其移至server块中。 - The
server块为下一节所述的Ruby示例应用程序设置OpenTracing。
- 验证并重新加载NGINX Plus配置:
$ nginx -t$ nginx -s reload设置示例 Ruby 应用
完成跟踪器和NGINX Plus配置后,我们创建一个示例Ruby应用,用于展示OpenTracing数据的形式。通过该应用,我们可以衡量NGINX Plus缓存对响应时间的改善程度。当应用收到如下针对GET的HTTP /请求时,会随机等待2至5秒后再响应。
$ curl http://NGINX-Plus-IP-address:9001/#!/usr/bin/ruby
require 'sinatra'
get '/*' do
out = "<h1>Ruby simple app</h1>" + "\n"
#Sleep a random time between 2s and 5s
sleeping_time = rand(4)+2
sleep(sleeping_time)
puts "slept for: #{sleeping_time}s."
out += '<p>some output text</p>' + "\n"
return out
end- 将app.rb设为可执行文件并运行:
$ chmod +x app.rb$ ./app.rb跟踪未启用缓存时的响应时间
我们使用Jaeger和Zipkin来显示未启用缓存时NGINX Plus响应请求所需的时间。对于每个追踪工具,我们发送5个请求。
未启用缓存时的Jaeger输出
以下是Jaeger UI中显示的5个请求(按时间从近到远排列):

以下是Ruby应用控制台中显示的相同信息:
- -> /slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:50:46 +0000] "GET / HTTP/1.1" 200 49 3.0028
127.0.0.1 - - [07/Jun/2019: 10:50:43 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 2s.
127.0.0.1 - - [07/Jun/2019: 10:50:56 +0000] "GET / HTTP/1.1" 200 49 2.0018
127.0.0.1 - - [07/Jun/2019: 10:50:54 UTC] "GET / HTTP/1.0"1 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:53:16 +0000] "GET / HTTP/1.1" 200 49 3.0029
127.0.0.1 - - [07/Jun/2019: 10:53:13 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 4s.
127.0.0.1 - - [07/Jun/2019: 10:54:03 +0000] "GET / HTTP/1.1" 200 49 4.0030
127.0.0.1 - - [07/Jun/2019: 10:53:59 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:54:11 +0000] "GET / HTTP/1.1" 200 49 3.0012
127.0.0.1 - - [07/Jun/2019: 10:54:08 UTC] "GET / HTTP/1.0" 200 49在Jaeger UI中,点击第一个(最近的)请求以查看其详细信息,其中包括我们作为标签添加的NGINX Plus变量的值:

未启用缓存时的 Zipkin 输出
以下是Zipkin UI中的另外5个请求:

Ruby应用控制台上显示的相同信息:
- -> /slept for: 2s.
127.0.0.1 - - [07/Jun/2019: 10:31:18 +0000] "GET / HTTP/1.1" 200 49 2.0021
127.0.0.1 - - [07/Jun/2019: 10:31:16 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:31:50 +0000] "GET / HTTP/1.1" 200 49 3.0029
127.0.0.1 - - [07/Jun/2019: 10:31:47 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:32:08 +0000] "GET / HTTP/1.1" 200 49 3.0026
127.0.0.1 - - [07/Jun/2019: 10:32:05 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 3s.
127.0.0.1 - - [07/Jun/2019: 10:32:32 +0000] "GET / HTTP/1.1" 200 49 3.0015
127.0.0.1 - - [07/Jun/2019: 10:32:29 UTC] "GET / HTTP/1.0" 200 49
- -> /
slept for: 5s.
127.0.0.1 - - [07/Jun/2019: 10:32:52 +0000] "GET / HTTP/1.1" 200 49 5.0030
127.0.0.1 - - [07/Jun/2019: 10:32:47 UTC] "GET / HTTP/1.0" 200 49在Zipkin UI中,点击第一个请求以查看其详细信息,其中包括我们作为标签添加的NGINX Plus变量值:

使用缓存时的响应时间追踪
配置NGINX Plus缓存
我们通过在缓存中创建的opentracing.conf文件中添加指令来启用配置 NGINX Plus。
- 在
http上下文中,添加以下proxy_cache_path指令:
proxy_cache_path /data/nginx/cache keys_zone=one:10m;- 在
server块中,添加以下proxy_cache和proxy_cache_valid指令:
proxy_cache one;
proxy_cache_valid any 1m;- 验证并重新加载配置:
$ nginx -t$ nginx -s reload启用缓存后的Jaeger输出
这是发出两次请求后的Jaeger UI。

首次响应(标记为13f69db)耗时4秒。NGINX Plus缓存了该响应。约15秒后再次发送请求时,由于响应来自NGINX Plus缓存,耗时不到2毫秒(ms)。
详细查看这两个请求,就能解释响应时间为何不同。对于第一个请求,upstream_cache_status为MISS,表示请求的数据不在缓存中。Ruby应用增加了4秒的延迟。

对于第2个请求,upstream_cache_status为HIT。由于数据来自缓存,Ruby应用无法增加延迟,响应时间不到2 ms。空的upstream_*值也表明上游服务器未参与此次响应。

启用缓存后的Zipkin输出
Zipkin UI中启用缓存的两个请求也呈现出类似的情况:

再次详细查看这两个请求,就能解释响应时间为何不同。第一个请求的响应未缓存(upstream_cache_status为MISS),而Ruby应用恰好也像Jaeger示例一样增加了4秒延迟。

在发出第二个请求之前,响应已被缓存,因此upstream_cache_status为HIT。

结论
NGINX OpenTracing模块支持跟踪NGINX Plus请求和响应,并可通过OpenTracing标签访问NGINX Plus变量。此模块还可与不同的跟踪器配合使用。
有关NGINX OpenTracing模块的更多详细信息,请访问GitHub上的NGINX OpenTracing模块仓库。
要在NGINX Plus中试用OpenTracing,立即开始30天免费试用,或联系我们,讨论您的使用场景。
相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
