自定义 C# 反向代理打破了 New Relic 分布式跟踪

问题描述 投票:0回答:1

我们有一个在 AWS ECS 中运行的 ASP .NET Core 反向代理应用程序,最初是在 .NET Core 3.1 中构建的,目前以 .NET6 运行。

AppA (AWS)
  ---> ProxyB  (AWS)
          ---> AppC (on-prem)

New Relic 从我们的代理应用程序到我们其他内部应用程序的分布式跟踪始终有效。但有一天我们问,既然我们所有人现在都属于同一个企业 NR 主帐户,为什么我们看不到从我们的一些姐妹组织开始的痕迹。

我们最初认为也许我们的姐妹组织只是没有打开分布式跟踪。但很快就确定事实并非如此。

我们最初专注于代理应用程序,它看起来很像此处描述的,包括以下方法。

private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
//snipped
foreach (var header in context.Request.Headers)
{
   requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}

我们添加了 AppA、ProxyB 和 AppC 标头的一些附加日志记录。我们的日志显示传出跟踪标头,

traceparent, tracestate, newrelic
我们期望从 AppA 接收并按 ProxyB 的预期输出。

但是 AppC 收到的标头值并不是从 ProxyB 记录为出站的值。

可以想象,ProxyB 和 AppC 之间有很多硬件/软件。我们不知道标题在哪里被更改。

asp.net-core http-headers reverse-proxy newrelic
1个回答
0
投票

在与 New Relic 建立支持案例后,他们的工程师能够告诉我们

我们的工程师一直在查看这些数据,目前我们 无法理解它。由于某种原因,尽管 AppC 收到了两个 三个标头中每个标头的不同(逗号分隔)值, 使它们无效。 AppB 发送的标头会附加到新的标头中 值,例如,如果 AppA 发送且 ProxyB 接收并输出:

"traceparent":   "A"
"tracestate":    "B"
"newrelic":      "C"

AppC 正在接收:

"traceparent":   "X, A"
"tracestate":    "Y, B"
"newrelic":      "Z, C"

意识到

X,Y,Z
是有效值,只是作为列表的一部分无效。我们对它们进行了解码并确认它们是由 ProxyB 添加的。

这帮助我们意识到 New Relic APM 代理正在查看 HttpRequestMessage.Headers 而没有看到跟踪标头,而是生成了一组新的跟踪标头。当数据传输到网络上时,它与 HttpRequestMessage.Content.Headers 结合在一起。

似乎没有一种简单且高性能的内置方法来确定哪些入站标头应在请求级别输出,哪些应在内容级别输出;缺少对列表进行硬编码。

但是后来我们找到了 YARP:另一个反向代理 项目,它的代码提供了我们正在寻找的东西。

private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
//snipped
foreach (var header in context.Request.Headers)
{
   if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray())
   {
       requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
   }
}

有趣的是,在请求级别,TryAddWithoutValidation() 将返回 false 并且不添加标头。而在内容级别,无论是否是 Microsoft 确定的“内容”标头,都会添加标头。

© www.soinside.com 2019 - 2024. All rights reserved.