我有一个 PostgreSQL 场景,其中有一个包含数据包捕获的数据库表(每个数据包都有时间戳和长度),我想计算正在使用的“当前”带宽。我目前正在使用 100 毫秒的滑动窗口,如下所示(出于可读性原因,从完整查询进行了简化):
WITH
counted AS (
SELECT pkttimestamp, pktlen,
sum(pktlen) OVER (
ORDER BY pkttimestamp
-- 0.1 PRECEDING ⇒ 100ms sliding window
RANGE BETWEEN 0.1 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW
) AS lensum, min(pkttimestamp) OVER (
ORDER BY pkttimestamp
-- same sliding window as above!
RANGE BETWEEN 0.1 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW
) AS smallesttimestamp
FROM packets
),
divided AS (
SELECT pkttimestamp, pktlen,
lensum / (pkttimestamp - smallesttimestamp) AS currentbandwidth
FROM counted
)
SELECT * FROM divided; -- any final query
在此,我使用窗口函数来计算前 100 毫秒数据包长度的总和,以及该范围内最旧数据包的时间戳,然后使用它(与当前数据包的时间戳)来划分从最早的时间戳到“此”数据包之前已发送的字节通过时间戳差发送,以获得滑动平均带宽。
这效果很好,当流量很少时(例如,
iperf
测试之前的区域,只有偶尔出现的数据包),限制为 100 毫秒可以使生成的图表“良好”。然而,在使用高带宽设置的 iperf
测试中,100 毫秒太粗糙(特别是如果可用带宽突然下降,图表需要 100 毫秒才能赶上)。
减少滑动窗口是一种选择,但它会导致在低带宽场景中出现更多锯齿状、不太“好”的图形(范围内没有足够的数据包)。
我可以重写窗口函数,在顶部添加“额外限制”,以便选择前面的 0.1 秒,但只选择最接近的 50 行吗? (考虑到我如何根据窗口中的第一个/最低时间戳进行任何进一步的计算,如果选择较少的行,它不会影响计算。)
仅切换到
ROWS BETWEEN 50 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW
不是一个选择,因为当仅在几分钟内捕获最后 50 个数据包时,它会产生非常糟糕的结果。
您可以更改 SQL 查询以根据给定时间范围内的行数调整窗口大小,从而在 PostgreSQL 中完成带宽计算的动态窗口大小调整。这使得在低流量时可以实现较粗的粒度,在高带宽时可以实现较细的粒度。 修改后的查询首先确定当前时间戳
currenttimestamp
以及每行数据包长度的累积和 lensum
。然后使用 lag
窗口函数检索前一行的时间戳。最后,在动态计算带宽时考虑当前行和前一行的时间戳之间的时间差。通过这种方法,可以保证窗口大小根据网络流量条件进行调整,从而实现更精确和响应更灵敏的带宽预测,这在流量负载波动的场景中特别有用。您可以通过更改行数和所需的时间范围来微调此策略以满足您的独特需求。