=== 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
=== 问题(实测)=== 按应用排行必须读日志内容(Loki 3.4 的 index/volume 不支持 app 维度聚合, aggregateBy=app 无效),成本 ∝ 时间范围: 5 分钟 ≈ 1.3GB → 9.8s 15 分钟 ≈ 3.9GB → 19.5s 1 小时 ≈ 15GB → 预计 60~90s 6 小时 ≈ 92GB → 5~8 分钟 24 小时 ≈ 370GB → 不可用 用户在时间范围里选 6h/24h 时,页面必然卡死。 === 方案 === 新增 models.AppVolumeSnapshot + services/app_volume.go: - 后台任务每小时第 5 分钟抓「上一个完整小时」的 per-app 条数 - 用**瞬时查询**(/loki/api/v1/query + [1h])而不是 query_range: 单点评估、扫描量相同、省掉多步开销;并绕开 LokiMetrics 的 90s 上限 与重型查询信号量(后台任务不该和前台抢令牌) - 每源每小时只留 top 50 应用,保留 90 天 - 幂等:同 (hour, source, ns, app) 更新而非重复插入 - 超出 Loki 26h 保留期的窗口跳过(抓也抓不到,白等几分钟) 新增 GET /api/v1/logs/app-ranking?sourceId&from&to&limit → 读库毫秒级 前端:analysis 判断范围 > 60 分钟就走预聚合接口,并停掉实时重查询 (rankingEnabled 置 false);表格副标题说明「读的是预聚合快照,已留存 N 小时, 不含错误数与趋势」。 === 顺带修掉的根因 bug === useInView 原来用 useRef + useEffect([inView]):分析页首屏 data===null 时 内容块不渲染,ref.current 为 null,effect 直接 return;等数据到了 DOM 才挂上, 但依赖没变 → effect 不重跑 → IntersectionObserver 从未创建 → inView 永远 false → 重查询永不发出 → 页面一直显示"没有应用维度的数据"。 改成 callback ref(节点挂载即作为依赖),并加 scroll/resize 兜底 + 挂载瞬间量一次。 另外分析页加 8 秒无条件兜底:可见性判定再失灵,8 秒后也一定查一次。 默认时间范围 15 分钟 → 5 分钟(19.5s → 9.8s)。 === 实测 === Pod = Hub latest = 98de87e7f895 5 分钟窗口 by-app:9.8s(75 序列);15 分钟:19.5s