APISIX 可观测性最佳实践

APISIX 介绍

Apache APISIX 是一个动态、实时、高性能的云原生 API 网关。它构建于 NGINX + ngx_lua 的技术基础之上,充分利用了 LuaJIT 所提供的强大性能。

APISIX 主要分为两个部分:

  • APISIX 核心:包括 Lua 插件、多语言插件运行时(Plugin Runner)、Wasm 插件运行时等;
  • 功能丰富的各种内置插件:包括可观测性、安全、流量控制等。

APISIX 在其核心中,提供了路由匹配、负载均衡、服务发现、API 管理等重要功能,以及配置管理等基础性模块。除此之外,APISIX 插件运行时也包含其中,提供原生 Lua 插件的运行框架和多语言插件的运行框架,以及实验性的 Wasm 插件运行时等。APISIX 多语言插件运行时提供多种开发语言的支持,比如 Golang、Java、Python、JS 等。

APISIX 目前也内置了各类插件,覆盖了 API 网关的各种领域,如认证鉴权、安全、可观测性、流量管理、多协议接入等。本文中的可观测性就是基于APISIX 的插件来实现数据上报。

案例介绍

本 demo 案例采用了 Ruoyi 系统 + APISIX 的最佳实践,采用了Opentelemetry + DDtrace 多链路协议的方式,以下是具体版本信息:

DataKit Agent:v1.22.1

DataKit Operator:v1.2.1

APISIX:v3.2 (LTS)

  • Opentelemetry-plugin

Ruoyi:v3.6.3

  • Vue 前端 SDK:Opentelemetry
  • Java 后端 SDK:DDtrace

如何接入

APISIX 的可观测性有多种插件和接入方式,我们以下面的几种插件来举例说明:

种类 接入方式(插件)
Tracers opentelemetry 插件,可用于根据 OpenTelemetry specification 协议规范上报 Tracing 数据。(该插件目前仅支持 http 请求上报)
Loggers 1、file-logger 插件,可用于将日志数据存储到指定位置。2、console 输出方式,可用于修改 APISIX 的 access_log 文件格式
Metrics prometheus 插件,以规定的格式上报指标到 Prometheus 中。

Tracing

1、RUM 接入改造

前端 npm sdk 版本 保持最新版本即可

RUM 接入时需要修改 traceType 修改为 w3c_traceparent

vbnet 复制代码
traceType: 'w3c_traceparent'

开启效果:

开启后,可实现前端 w3c 协议头上报 , 在请求头中可以查看到 w3c 的协议头 Traceparent 请求头至后端,方便客户排障时获取关联的 trace_id 。

2、Opentelemetry 插件开启

官方参考文档: apisix.apache.org/docs/apisix...

APISIX Dashboard opentelemetry 的配置

json 复制代码
{ 
    "additional_attributes": [ 
        "resp_body", 
        "balancer_ip", 
        "route_name" 
    ],
    "disable": false, 
    "sampler": { 
        "name": "always_on" 
    } 
}

在插件市场配置如下所示:

在 Apisix config.yaml 关于 otel 的配置

yaml 复制代码
plugins:
 - opentelemetry
plugin_attr: 
  opentelemetry: 
    resource: 
      service.name: APISIX 
      tenant.id: business_id 
    collector: 
      address: 127.0.0.1:9529/otel 
      request_timeout: 3 
      #request_headers: 
      # foo: bar 
    batch_span_processor: 
      drop_on_queue_full: false 
      max_queue_size: 6 
      batch_timeout: 2 
      inactive_timeout: 1 
      max_export_batch_size: 2

其中 127.0.0.1:9529/otel 是 datakit 的上报 trace 的地址,datakit 完整的上报地址是 127.0.0.1:9529/otel/v1/trace

但是 apisix 上报 trace 的路径是 /v1/traces ,两者路径不一致,需要在 APISIX 上对 datakit 的上报路径做个转发。

3、Datakit 开启 Opentelemetry 采集

1)参考 docs.guance.com/datakit/ope... ,开启 otel 采集器采集;

2)修改 DataKit 默认上报的 Opentelemetry 路径,trace_api 修改为 /otel/v1/traces ,若 key 不存在,添加即可。

  • apisix 默认上报 路径 /v1/traces
  • DataKit 默认接收 路径 /otel/v1/trace
ini 复制代码
[[inputs.opentelemetry]]
  ## During creating 'trace', 'span' and 'resource', many labels will be added, and these labels will eventually appear in all 'spans'
  ## When you don't want too many labels to cause unnecessary traffic loss on the network, you can choose to ignore these labels
  ## with setting up an regular expression list.
  ## Note: ignore_attribute_keys will be effected on both trace and metrics if setted up.
  # ignore_attribute_keys = ["os_*", "process_*"]
  ## The acceptable http_status_ok values will be 200 or 202.
  
   
  [inputs.opentelemetry.http]
   enable = true
   http_status_ok = 200
   trace_api = "/otel/v1/traces"

配置好 opentelemetry.conf 之后,采用 systemctl restart datakit 重启 datakit ,配置生效。

注意:http 协议的路由是不可配置的,请求路径(Trace/Metric)分别为 /otel/v1/trace/otel/v1/metric

上报完成之后,可以在观测云上看的采集 APISIX 的 trace 信息。

最终效果:


Loggers

1、日志改造

1.1、日志文件输出方式

file-loggger 插件

实际配置效果

json 复制代码
{ 
    "disable": false, 
    "include_resp_body": true, 
    "include_resp_body_expr": false, 
    "path": "/usr/local/apisix/logs/file.log" 
}

在插件市场配置如下所示:

注意:path 的路径需要是绝对路径,不能写成相对的,配置成功之后,查看日志文件是否有日志生成。

1.2、console 输出方式

修改配置文件 conf/config.yaml ,修改访问日志格式 access_logger_format 。

makefile 复制代码
nginx_config:
  http:
    access_log_format: '{"remote_addr": "$remote_addr", "remote_user": "$remote_user", "time_local": "$time_local", "http_host": "$http_host", "request": "$request", "status": "$status", "body_bytes_sent": "$body_bytes_sent", "request_time": "$request_time", "http_referer": "$http_referer", "http_user_agent": "$http_user_agent", "upstream_addr": "$upstream_addr", "upstream_status": "$upstream_status", "upstream_response_time": "$upstream_response_time", "upstream_url": "$upstream_scheme://$upstream_host$upstream_uri","x-gc-trace-id": "$http_x_gc_trace_id","x-gc-span-id": "$http_x_gc_span_id","traceparent": "$http_traceparent"}'

其中 traceparent 的值为标准 W3C 128-bit trace_id

2、日志切割

2.1、pipeline 日志切割转换

pipeline 编写参考

scss 复制代码
if vaild_json(_) { # true
  origin = load_json(_)
  add_key(remote_addr,origin["remote_addr"])
  add_key(remote_user,origin["remote_user"])
  add_key(http_host,origin["http_host"])
  add_key(request,origin["request"])
  add_key(http_referer,origin["http_referer"])
  add_key(body_bytes_sent,origin["body_bytes_sent"])
  add_key(upstream_url,origin["upstream_url"])


  add_key(trace_id,origin["traceparent"])
  grok(trace_id, "%{DATA}-%{DATA:trace_id}-%{DATA}") 

}

测试效果如下:

Metric

1、APISIX 开启 Promethues 插件

官方参考链接:apisix.apache.org/docs/apisix...

2、Datakit 开启 Promethues 采集

在观测云平台中,点击「集成」中,选择「APISIX」可以通过 promethues 的方式采集 APISIX 数据。

日志和 trace 数据关联

apisix 导出的日志格式如下:

css 复制代码
{"client_ip":"127.0.0.1","server": 
{"hostname":"localhost.localdomain","version":"2.14.1"},"apisix_latency":0,"upstream":"127. 
0.0.1:9529","upstream_latency":1,"request": 
{"url":"http://127.0.0.1:80/otel/v1/traces","size":836,"uri":"/otel/v1/traces","que 
rystring":{},"headers":{"content-type":"application/x-protobuf","user-agent":"lua-resty- 
http/0.16.1 (Lua) ngx_lua/10021","content-length":"672","traceparent":"00-749cc2e62e47bcf01fb76932c74ec1fe-d0a6101332bca613-01","host":"127.0.0.1"},"method":"POST"},"latency":0.99992752075195,"start_time":1685688047 
197,"service_id":"","route_id":"462899766133524220","response": 
{"size":493,"status":200,"headers":{"access-control-allow-headers":"Content-Type, Content- 
Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X- 
Requested-With, X-Token, X-Datakit-UUID, X-RP, X-Precision, X-Lua","access-control-allow- 
credentials":"true","server":"APISIX/2.14.1","content-length":"0","access-control-allow- 
origin":"*","x-datakit":"1.5.7/2023-03-20 11:50:32","connection":"close","access-control- 
allow-methods":"POST, OPTIONS, GET, PUT","date":"Fri, 02 Jun 2023 06:40:47 GMT"}}}

通过以上日志,我们可以看到 traceparent 信息:

"traceparent":"00-749cc2e62e47bcf01fb76932c74ec1fe-d0a6101332bca613-01"

这是 opentelemetry 所产生的 trace 数据,其中749cc2e62e47bcf01fb76932c74ec1fe 才是对应的 trace_id 信息,这个时候需要通过观测云的 Pipelines 做下切割,切割的脚本可以参考如下:

scss 复制代码
json(_, client_ip, client_ip) 
json(_, upstream, upstream) 
json(_, request.url, url) 
json(_, response.status, http_status) 
json(_, route_id, route_id) 
json(_, request.headers.traceparent, trace_id) 
grok(_, "%{DATA}traceparent":"%{DATA}-%{DATA:trace_id}-%{DATA}"") 

trace_id 就被切割出来了,00-749cc2e62e47bcf01fb76932c74ec1fe-d0a6101332bca613-01 切割成 749cc2e62e47bcf01fb76932c74ec1fe

因为 tracing 的 id 和日志的 id 一致,所以可以通过观测云关联起来,效果如下:

相关推荐
IT_陈寒3 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码4 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo4 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志5 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..5 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects5 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰5 小时前
一些基础和问题解决
后端
陈随易6 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN6 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana6 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端