From 21461863afc38069c713ea40f0af399e818c9067 Mon Sep 17 00:00:00 2001 From: shaw Date: Wed, 30 Jul 2025 14:49:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=9E=E6=97=B6RPM/?= =?UTF-8?q?TPM=E6=8C=87=E6=A0=87=E6=98=BE=E7=A4=BA=E4=B8=BA0=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加调试日志以追踪数据读取过程 - 修复getRealtimeSystemMetrics中的数据验证逻辑 - 添加测试脚本用于验证时间戳匹配问题 - 改进错误处理和日志记录 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- scripts/test-realtime-metrics.js | 69 +++++++++ src/models/redis.js | 28 +++- web/admin-spa/src/views/DashboardView.vue | 179 +++++++++++++++++++++- 3 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 scripts/test-realtime-metrics.js diff --git a/scripts/test-realtime-metrics.js b/scripts/test-realtime-metrics.js new file mode 100644 index 00000000..ba236822 --- /dev/null +++ b/scripts/test-realtime-metrics.js @@ -0,0 +1,69 @@ +const redis = require('../src/models/redis'); +const logger = require('../src/utils/logger'); + +async function testRealtimeMetrics() { + try { + // 连接Redis + await redis.connect(); + + // 获取当前时间戳 + const now = new Date(); + const currentMinute = Math.floor(now.getTime() / 60000); + + console.log('=== 时间戳测试 ==='); + console.log('当前时间:', now.toISOString()); + console.log('当前分钟时间戳:', currentMinute); + console.log(''); + + // 检查最近5分钟的键 + console.log('=== 检查Redis键 ==='); + const client = redis.getClient(); + for (let i = 0; i < 5; i++) { + const minuteKey = `system:metrics:minute:${currentMinute - i}`; + const exists = await client.exists(minuteKey); + const data = await client.hgetall(minuteKey); + + console.log(`键: ${minuteKey}`); + console.log(` 存在: ${exists ? '是' : '否'}`); + if (exists && data) { + console.log(` 数据: requests=${data.requests}, totalTokens=${data.totalTokens}`); + } + console.log(''); + } + + // 调用getRealtimeSystemMetrics + console.log('=== 调用 getRealtimeSystemMetrics ==='); + const metrics = await redis.getRealtimeSystemMetrics(); + console.log('结果:', JSON.stringify(metrics, null, 2)); + + // 列出所有system:metrics:minute:*键 + console.log('\n=== 所有系统指标键 ==='); + const allKeys = await client.keys('system:metrics:minute:*'); + console.log('找到的键数量:', allKeys.length); + if (allKeys.length > 0) { + // 排序并显示最新的10个 + allKeys.sort((a, b) => { + const aNum = parseInt(a.split(':').pop()); + const bNum = parseInt(b.split(':').pop()); + return bNum - aNum; + }); + + console.log('最新的10个键:'); + for (let i = 0; i < Math.min(10, allKeys.length); i++) { + const key = allKeys[i]; + const timestamp = parseInt(key.split(':').pop()); + const timeDiff = currentMinute - timestamp; + console.log(` ${key} (${timeDiff}分钟前)`); + } + } + + } catch (error) { + console.error('测试失败:', error); + } finally { + await redis.disconnect(); + process.exit(0); + } +} + +// 运行测试 +testRealtimeMetrics(); \ No newline at end of file diff --git a/src/models/redis.js b/src/models/redis.js index 57e4b013..659432db 100644 --- a/src/models/redis.js +++ b/src/models/redis.js @@ -1008,18 +1008,25 @@ class RedisClient { async getRealtimeSystemMetrics() { try { const config = require('../../config/config'); - const windowMinutes = config.system.metricsWindow; + const windowMinutes = config.system.metricsWindow || 5; const now = new Date(); const currentMinute = Math.floor(now.getTime() / 60000); + // 调试:打印当前时间和分钟时间戳 + logger.debug(`🔍 Realtime metrics - Current time: ${now.toISOString()}, Minute timestamp: ${currentMinute}`); + // 使用Pipeline批量获取窗口内的所有分钟数据 const pipeline = this.client.pipeline(); + const minuteKeys = []; for (let i = 0; i < windowMinutes; i++) { const minuteKey = `system:metrics:minute:${currentMinute - i}`; + minuteKeys.push(minuteKey); pipeline.hgetall(minuteKey); } + logger.debug(`🔍 Realtime metrics - Checking keys: ${minuteKeys.join(', ')}`); + const results = await pipeline.exec(); // 聚合计算 @@ -1029,23 +1036,32 @@ class RedisClient { let totalOutputTokens = 0; let totalCacheCreateTokens = 0; let totalCacheReadTokens = 0; + let validDataCount = 0; - results.forEach(([err, data]) => { - if (!err && data) { + results.forEach(([err, data], index) => { + if (!err && data && Object.keys(data).length > 0) { + validDataCount++; totalRequests += parseInt(data.requests || 0); totalTokens += parseInt(data.totalTokens || 0); totalInputTokens += parseInt(data.inputTokens || 0); totalOutputTokens += parseInt(data.outputTokens || 0); totalCacheCreateTokens += parseInt(data.cacheCreateTokens || 0); totalCacheReadTokens += parseInt(data.cacheReadTokens || 0); + + logger.debug(`🔍 Realtime metrics - Key ${minuteKeys[index]} data:`, { + requests: data.requests, + totalTokens: data.totalTokens + }); } }); + logger.debug(`🔍 Realtime metrics - Valid data count: ${validDataCount}/${windowMinutes}, Total requests: ${totalRequests}, Total tokens: ${totalTokens}`); + // 计算平均值(每分钟) const realtimeRPM = windowMinutes > 0 ? Math.round((totalRequests / windowMinutes) * 100) / 100 : 0; const realtimeTPM = windowMinutes > 0 ? Math.round((totalTokens / windowMinutes) * 100) / 100 : 0; - return { + const result = { realtimeRPM, realtimeTPM, windowMinutes, @@ -1056,6 +1072,10 @@ class RedisClient { totalCacheCreateTokens, totalCacheReadTokens }; + + logger.debug(`🔍 Realtime metrics - Final result:`, result); + + return result; } catch (error) { console.error('Error getting realtime system metrics:', error); // 如果出错,返回历史平均值作为降级方案 diff --git a/web/admin-spa/src/views/DashboardView.vue b/web/admin-spa/src/views/DashboardView.vue index c728f5da..7820ed5f 100644 --- a/web/admin-spa/src/views/DashboardView.vue +++ b/web/admin-spa/src/views/DashboardView.vue @@ -1,5 +1,45 @@ \ No newline at end of file