各种request_id唯一ID在不同场景的应用

一 背景 

在运维场景中 存在需要唯一ID的情况,很多时候不知道什么时候采取唯一ID比较合适

场景1 不需要唯一ID的情况

1.1 说明:

这种情况下不需要NGINX唯一ID接入,域名和程序都比较明确,链路较短。很容易定位到链路在哪里中断和链路的目的地

场景2  有必要介入唯一ID

2.1 说明:

这种情况下建议引入唯一ID。 中间涉及多个网关和多个NGINX  用户请求不明确。 当客户URL访问异常, 

当用户访问异常:为了确定URL流向

1 必须先登录网关,确定是否为网关问题

2  通过网关流向判断 再次登录后端服务器判断 服务器状态

至少2次服务器登录 和排查 增加了问题排查周期

场景3  非常需要唯一ID

3.1 说明:

这种情况下有必要介入唯一ID。 中间涉及多个网关和K8S-INGRESS(也是一个NGINX)多个NGINX  用户请求不明确。 当客户URL访问异常, 

当用户访问异常:为了确定URL流向

1  必须先登录网关,确定是否为网关问题

2  登录 INGRESS POD 查看日志

2 登录具体了业务POD查看日志

至少3次服务器登录

3.2  复杂情况

在更加复杂的情况下   是存在多个网关 , 网关 和K8S前是存在SLB的。

当用户访问异常:为了确定URL流向

1  先解析域名 确定网关的SLB地址

2  分别登录2个网关

3 分别登录2个SLB

4 登录具体的POD

这里还没引入 服务网关的等场景,引入之后排查流程将会更长

场景4  NGINX唯一ID无法解决

说明: 这种情况下无法通过NGINX唯一ID 解决,需要引入APM 程序 的AGENT

后面我们再介绍 简单引入一个知乎的 关于APM的介绍

APM分为前端和后端 这里主要介绍的是后端。

目前很多企业是前端APM和后端APM 一起来做的2端的唯一ID进行打通。其实是更好的。

前端APM:

开源的:WebMonitoring  WebTracing

前端的开源APM较少

付费阿里云的:应用实时监控服务_全栈性能监控_用户体验监控_迁移与运维管理-阿里云

阿里的是前后端进行打通的。

后端的APM:

https://zhuanlan.zhihu.com/p/660338176

这里是很多开源的。推荐:SkyWalking

二 如何引入NGINX唯一ID

2.1 基本流程是这样的

1  在网关 配置增加 唯一ID 请求头,并且日志打印

2  在后端业务NGINX 或者请求头 并且日志打印

3  业务程序也可以接受这个请求头 在业务日志进行打印 (可选)

        1.项目接受的请求头定义为traceId。

        2.nginx.conf主文件配置增加proxy_set_header traceId $request_id;

        3.nignx.conf主文件日志增加打印日志$request_id 

        最后项目接受到nginx传送的以$request_id 作为traceId的字符串,实现nginx和tomcat的链路串联。

2.2  入口网关的配置

这里网关入口的日志配置 :核心配置 p-request-id=[$request_id] 

2.2.1 NGINX 日志配置
www escape=json 'remote_addr=[$remote_addr] http_x_forward=[$http_x_forwarded_for] time=[$time_local] '
        'request=[$request] status=[$status] byte=[$bytes_sent] elapsed=[$request_time] refer=[$http_referer] '
        'body=[$request_body] ua=[$http_user_agent] cookie=[$http_cookie] gzip=[$gzip_ratio] '
        'log_id=[$hostname] msec=[$msec] '
        'host=[$host] http_host=[$http_host] http_accept=[$http_accept|$http_accept_encoding|$http_accept_language] '
        'upstream_response_time=[$upstream_response_time] sent_http_set_cookie=[$sent_http_set_cookie] '
         'upstreamip=[$upstream_addr] session_id=[$upstream_cookie_rrc_rrc_signed] rrc_tg=[$upstream_cookie_rrc_tg] upsteam_status=[$upstream_status] p-request-id=[$request_id] x-request-id=[$http_x_request_id]   pod_name=[$http_x_downstream_host]'
2.2.2 SERVER  日志配置    

这里是SERVER 的配置  核心配置 

    add_header x-request-id $request_id; (添加请求头 方便调用的时候返回给调用方唯一ID )
    proxy_set_header x-request-id $request_id; (自己生成的唯一ID 向后传递)

server {
  server_name a.com;
  listen 8180;
  location / {
    proxy_pass http://octo-gateway;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_redirect off;
    proxy_cache rrc;
    proxy_cache_key $http_x_forwarded_proto$host$proxy_host$uri$is_args$args;
    proxy_next_upstream http_500 http_502  http_504 error timeout invalid_header;
    proxy_connect_timeout 600;
    proxy_send_timeout 600;
    proxy_read_timeout 600;
    proxy_buffering on;
    proxy_buffer_size 402400k;
    proxy_buffers 8 402400k;
    proxy_busy_buffers_size 402400k;
    proxy_max_temp_file_size 2048m;
    proxy_temp_file_write_size 402400k;
    add_header x-request-id $request_id;
    proxy_set_header x-request-id $request_id;
    add_header X-CACHE-RRC '$upstream_cache_status from $proxy_host-$hostname-$upstream_status';
  }
}

2.3  业务nginx

核心: x-request-id 为上游传递过来的唯一ID

非核心:p-request-id 为本地生成的。根据业务需求引用

www escape=json 'remote_addr=[$remote_addr] http_x_forward=[$http_x_forwarded_for] time=[$time_local] '
        'request=[$request] status=[$status] byte=[$bytes_sent] elapsed=[$request_time] refer=[$http_referer] '
        'body=[$request_body] ua=[$http_user_agent] cookie=[$http_cookie] gzip=[$gzip_ratio] '
        'log_id=[$hostname] msec=[$msec] '
        'host=[$host] http_host=[$http_host] http_accept=[$http_accept|$http_accept_encoding|$http_accept_language] '
        'upstream_response_time=[$upstream_response_time] sent_http_set_cookie=[$sent_http_set_cookie] '
         'upstreamip=[$upstream_addr] session_id=[$upstream_cookie_rrc_rrc_signed] rrc_tg=[$upstream_cookie_rrc_tg] upsteam_status=[$upstream_status] p-request-id=[$request_id] x-request-id=[$http_x_request_id]   pod_name=[$http_x_downstream_host]'

2.3.1 SERVER配置

这里的 唯一ID  proxy_set_header x-request-id $http_x_request_id; 继续向后传递

server {
  server_name a.com;
  listen 8180;
  location / {
    proxy_pass http://octo-gatewa;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_redirect off;
    proxy_cache rrc;
    proxy_cache_key $http_x_forwarded_proto$host$proxy_host$uri$is_args$args;
    proxy_next_upstream http_500 http_502  http_504 error timeout invalid_header;
    proxy_connect_timeout 600;
    proxy_send_timeout 600;
    proxy_read_timeout 600;
    proxy_buffering on;
    proxy_buffer_size 402400k;
    proxy_buffers 8 402400k;
    proxy_busy_buffers_size 402400k;
    proxy_max_temp_file_size 2048m;
    proxy_temp_file_write_size 402400k;
    proxy_set_header x-request-id $http_x_request_id;
    add_header X-CACHE-RRC '$upstream_cache_status from $proxy_host-$hostname-$upstream_status';
  }
}
2.3.2 业务代码 

获取唯一ID 打印

import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RestController;  
import javax.servlet.http.HttpServletRequest;  
 
@RestController 
public class RequestIdController { 
    @GetMapping("/getRequestId") 
    public String getRequestId(HttpServletRequest request) { 
        // 从请求头中获取 X-Request-Id 
        String requestId = request.getHeader("X-Request-Id");  
        if (requestId != null) { 
            return "X-Request-Id: " + requestId; 
        } else { 
            return "X-Request-Id not found in the request headers."; 
        } 
    } 
} 

三  如何查找问题

我们网页打开 访问URL  F12,或curl -I  网址  就可以看到这个唯一ID

我们就可以根据这个唯一ID 追述问题。

这里我们还是需要登录服务器来查询指定唯一ID的问题更方便的方案 是需要对NGINX 日志收集集中查看

常用的方案 ELK

 如果不会收集这里我引用一个ELK其他博文:

ELK 日志采集使用_elk日志-CSDN博客

当然K8S日志收集也有专门的收集器。 都是一样的  日志读取--最终写入到ES里。 我们通过各种界面工具去查看ES的结果。方便争端问题

后续:

1 可以通过Kibana argus 等去查询ES

2 python运维开发去调用ES的数据进行故障分析 故障复盘 结合其他的运维定位工具 统一定位问题

最近我们通过dify工具流和大模型 来调用ES 来追踪链路,使链路结果更佳清洗。后面我专门搞一个文章来写一下 基于dify工具流和大模型的 链路追踪定位

### 解决 Python 中 `AttributeError: 'NoneType' object has no attribute 'request_id'` 错误 当遇到 `'NoneType' object has no attribute 'request_id'` 的错误时,通常意味着尝试访问的对象实际上是一个 `None` 类型而不是预期的数据结构。这可能是由于函数返回了 `None` 或者对象未被正确初始化。 #### 原因分析 该类错误的根本原因在于某个变量或属性期望指向一个具有特定方法或属性的对象实例,但实际上却为 `None`。此情况可以发生在多种场景下,比如网络请求失败、文件读取异常或是数据库查询无果等[^1]。 #### 解决策略 为了有效处理此类问题,建议采取以下措施: - **检查前置操作的结果** 在调用任何成员之前先验证目标对象是否确实存在并已被成功赋值。可以通过简单的条件判断来实现这一点。 ```python if my_object is not None and hasattr(my_object, "request_id"): request_id = my_object.request_id else: print("Object does not exist or lacks the required attribute.") ``` - **调试与日志记录** 使用断点工具或者增加详细的日志输出以便追踪到具体哪一步出现了问题以及为何会得到 `None` 结果。这对于理解程序流非常重要。 - **改进异常捕获机制** 对可能出现异常的地方添加 try-except 语句块,从而优雅地应对意外状况而不至于让整个应用程序崩溃。 ```python try: request_id = my_object.request_id except AttributeError as e: logging.error(f"Failed to access request_id due to {e}") ``` - **确认数据源可靠性** 如果是从外部获取的数据(如API响应),则应确保接口稳定可靠,并考虑加入重试逻辑以提高成功率;对于内部生成的内容,则要仔细审查相关业务流程是否存在漏洞[^4]。 通过上述手段能够大大降低遭遇 `AttributeError` 风险的同时也增强了代码健壮性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值