如何在不考虑依赖项持续时间的情况下评估 Application Insights 请求 "own" 持续时间?

How to evaluate Application Insights requests "own" duration, without considering duration of dependencies?

我正在尝试生成一个 Kusto 查询来测量请求的“自己”持续时间(减去依赖项的持续时间)。但是,我真的不知道如何通过纯 Kusto 查询来解决这个问题。

为了更好地理解预期结果,下面是一个示例案例:

高级视图(其中 R 是请求,Dx 是依赖项)

 R    =============================== (31ms)
 D1     ******* (7ms)
 D2          ******** (8ms)
 D3                        ****** (6ms)
 D4                          ** (2ms)
 D5         **** (4ms)

 Proj ==*************======******====

给定以下测试平台数据集

let reqs = datatable (timestamp: datetime, id:string, duration: real)
[
  datetime("2020-12-15T08:00:00.000Z"), "r1", 31    // R
];
let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
  datetime("2020-12-15T08:00:00.002Z"), "r1", 7,    // D1
  datetime("2020-12-15T08:00:00.007Z"), "r1", 8,    // D2
  datetime("2020-12-15T08:00:00.021Z"), "r1", 6,    // D3
  datetime("2020-12-15T08:00:00.023Z"), "r1", 2,    // D4
  datetime("2020-12-15T08:00:00.006Z"), "r1", 4,    // D5
];

在这种特殊情况下,连接两个数据表的 Kusto 查询应该能够检索 12(请求持续时间,删除所有依赖项),即

Expected total duration = 31 - (7 + 8 - 2) - (6) = 12

如果能帮助推动这一进程,我们将不胜感激 <3

看看下面的查询是否能满足您的要求:

let reqs = datatable (timestamp: datetime, id:string, duration: real, key1:string)
[
  datetime("2020-12-15T08:00:00.000Z"), "r1", 31 , "k1"   // R
];

let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real,name:string)
[
  datetime("2020-12-15T08:00:00.002Z"), "r1", 7, "D1", 
  datetime("2020-12-15T08:00:00.007Z"), "r1", 8, "D2", 
  datetime("2020-12-15T08:00:00.021Z"), "r1", 6, "D3", 
  datetime("2020-12-15T08:00:00.023Z"), "r1", 2, "D4", 
  datetime("2020-12-15T08:00:00.006Z"), "r1", 4, "D5"
];

let d2 = deps
| where name !in ("D4","D5")
| summarize a=sum(duration)-2
| extend key1="k1";

reqs 
| join d2 on key1
| extend result = duration - a
| project result

测试结果:

我使用 row_window_session(). This is a Window function. You can read more about it at Window functions overview.

成功解决了这个问题

解决方法是:

let reqs = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
  datetime("2020-12-15T08:00:00.000Z"), "r1", 31    // R
];
let deps = datatable (timestamp: datetime, operation_ParentId:string, duration: real)
[
  datetime("2020-12-15T08:00:00.002Z"), "r1", 7,    // D1
  datetime("2020-12-15T08:00:00.007Z"), "r1", 8,    // D2
  datetime("2020-12-15T08:00:00.021Z"), "r1", 6,    // D3
  datetime("2020-12-15T08:00:00.006Z"), "r1", 4,    // D5
  datetime("2020-12-15T08:00:00.023Z"), "r1", 2,    // D4
];
deps
| extend endTime = timestamp + totimespan(duration * 10000)
| sort by timestamp asc 
| serialize | extend SessionStarted = row_window_session(timestamp, 1h, 1h, timestamp > prev(endTime))
| summarize max(endTime) by operation_ParentId, SessionStarted
| extend diff = max_endTime - SessionStarted
| summarize todouble(sum(diff)) by operation_ParentId
| join reqs on operation_ParentId
| extend diff = duration - sum_diff / 10000
| project diff 

这里的思路是按照打开时间对条目进行排序,只要下一个上一个结束时间晚于当前开始时间,我们就不会打开新的会话。让我们解释一下这个查询的每一行,看看这是如何完成的:

  1. 根据持续时间计算endTime。为了规范化数据,我将持续时间乘以 10000:
    | extend endTime = timestamp + totimespan(duration * 10000)
    
  2. 按开始时间排序:
    | sort by timestamp asc 
    
  3. 这是本解法的关键。它是在 timestamp 列上计算的。接下来的两个参数是何时开始新桶的限制。由于我们不想根据过去的时间来密封桶,因此我提供了 1 小时,该时间不会影响此输入。第四个参数帮助我们创建一个基于数据的新会话。只要有更多的行会导致 timestamp > prev(endTime),它们就会有相同的开始时间。
    | serialize | extend SessionStarted = row_window_session(timestamp, 1h, 1h, timestamp > prev(endTime))
    
  4. 现在每个会话开始时我们有多个行。所以我们只想保留每个会话的最新时间。我们还保留 operation_ParentId 以便稍后加入该键:
    | summarize max(endTime) by operation_ParentId, SessionStarted
    
  5. 计算每个会话的时间:
    | extend diff = max_endTime - SessionStarted
    
  6. 总结所有会话时间:
    | summarize todouble(sum(diff)) by operation_ParentId
    
  7. 加入 req 以获得总开始时间:
    | join reqs on operation_ParentId
    
  8. 计算总时间和会话时间之间的差异。非规范化数据:
    | extend diff = duration - sum_diff / 10000
    
  9. 投影最终结果:
    | project diff 
    

您可以在 Kusto Samples open database 找到此查询 运行。

话虽如此,请注意这是线性运算。这意味着如果有 2 个后续段,它们应该在同一段下,但它们不相交,它将失败。例如,将以下内容添加到 deps 中:

datetime("2020-12-15T08:00:00.026Z"), "r1", 1,    // D6

这不应该在计算中添加任何东西,导致它行为不端。这是因为d4是前一个点,它与d6没有任何联系,虽然d3涵盖了两者。 要解决这个问题,您需要重复步骤 3-5 的相同逻辑。不幸的是,Kusto 没有递归,因此您无法为任何类型的输入解决此问题。但是假设没有真正深度的案例打破这个逻辑,我认为这已经足够了。