=== 1. 为什么去掉「显示条数」选择器 === topk 的 N 不影响查询成本(扫描的 chunk 集合完全相同),实测: topk(10) 17833ms / 11 条 topk(30) 18019ms / 34 条 topk(50) 7394ms / 54 条 topk(100) 17553ms / 74 条 波动来自集群负载,与 N 无关 —— 它只决定最后返回多少序列。 所以"选 30"既不更快也不更慢,本质是个翻页开关; 而选它还要重新等一次十几秒的查询,纯亏。 改为:一次 topk(50),前端 10 条/页 → 5 页只需 1 次查询。 附带收益:占比的分母从"前 10 合计"变成"前 50 合计",更接近真实占比。 副标题明确写清"一次取前 50 个应用(占比按这 50 个合计计算)"。 === 2. 零点结算昨天(daily volume)=== 原来只有 30 分钟 ticker 回补,且启动时间不对齐整点 → 昨天最早的一段可能已经超出 Loki 24h 保留期被删, 结算结果系统性偏低,图上却标"完整一天",属静默错数。 新增 nextMidnightFinalize():每天 00:01 触发 FinalizeYesterdayVolume() - 昨天定稿 partial=false - 补一次条数(index/stats,一天一次可接受) - 顺带刷新今天 partial=true 的柱子 ticker 仍保留,负责当天数据的 30 分钟刷新。 === 3. 顺带 === - 去掉每日量"其中 N 天平台没有留存记录"的提示文案(按用户要求) - 修 QuickQueryTemplates.tsx 的未使用变量导致 tsc -b 失败 - 工作区里上一轮中断的"排行体积列"改动一并纳入(app-ranking 返回 bytes, TopAppsTable 增加体积列,快照记录 per-app 字节数) Pod = Hub latest = a16978d2f88b
42 lines
1.9 KiB
Go
42 lines
1.9 KiB
Go
package models
|
|
|
|
import "time"
|
|
|
|
// AppVolumeSnapshot 按小时留存「每个应用」的日志量(条数)。
|
|
//
|
|
// 为什么必须落库:
|
|
//
|
|
// Loki 的 index/volume 只支持 namespace 级聚合(3.4 实测 aggregateBy=app 不生效),
|
|
// 所以"按应用排行"只能读日志内容,成本 ∝ 时间范围:
|
|
// 5 分钟 ≈ 1.3GB ≈ 10 秒
|
|
// 15 分钟 ≈ 3.9GB ≈ 20 秒
|
|
// 6 小时 ≈ 92GB ≈ 5~8 分钟 ← 页面根本等不了
|
|
// 24 小时 ≈ 370GB ≈ 不可用
|
|
// 把 per-app 数据按小时在后台算好存起来,长范围排行就变成读库(毫秒级)。
|
|
//
|
|
// 采集方式:每小时第 5 分钟抓「上一个完整小时」,一条
|
|
//
|
|
// sum by (app, namespace)(count_over_time({...}[1h]))
|
|
//
|
|
// 查询在后台跑,慢一点无所谓;页面永远读库。
|
|
type AppVolumeSnapshot struct {
|
|
ID uint `json:"id"`
|
|
// Hour 小时桶,格式 YYYY-MM-DDTHH(本地时区,按整点对齐)
|
|
Hour string `json:"hour"`
|
|
SourceID uint `json:"sourceId"`
|
|
Namespace string `json:"namespace"`
|
|
App string `json:"app"`
|
|
// Entries 该小时的日志条数(count_over_time,要读日志内容,成本高但准确)
|
|
Entries int64 `json:"entries"`
|
|
// Bytes 该小时的日志体积(字节,来自 index/volume 索引接口)
|
|
//
|
|
// 为什么不跟 Entries 用同一条查询:按 app 取体积在 Loki 里没有"一次扫全集群"的
|
|
// 索引聚合(index/volume 的返回只带 selector 里出现的 label),所以只能一个 app
|
|
// 调一次;换来的是 80ms/次的索引查询,而不是重扫整小时日志内容(约 50s)。
|
|
// 老快照(本字段上线前抓的)Bytes=0,前端据此把"体积未知"和"体积真的是 0"分开。
|
|
Bytes int64 `json:"bytes"`
|
|
// Partial 该小时数据是否不完整(如平台停了一段时间后才回补,超出 Loki 保留期)
|
|
Partial bool `json:"partial"`
|
|
CapturedAt time.Time `json:"capturedAt"`
|
|
}
|