Skip to content

Commit 638b58a

Browse files
committed
Update.
1 parent 2453dca commit 638b58a

File tree

3 files changed

+121
-5
lines changed

3 files changed

+121
-5
lines changed

cmd/dashboard/controller/api_v1.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func (v *apiV1) monitorHistoriesById(c *gin.Context) {
154154
if singleton.Conf.DatabaseType == "badger" {
155155
// BadgerDB 模式下使用 MonitorAPI,只查询最近7天的ICMP/TCP监控数据
156156
if singleton.MonitorAPI != nil {
157-
// 根本性性能优化:恢复3天数据,但优化查询方式
157+
// 恢复3天数据展示,通过优化查询效率解决性能问题
158158
endTime := time.Now()
159159
startTime := endTime.AddDate(0, 0, -3) // 恢复3天数据
160160

@@ -177,12 +177,12 @@ func (v *apiV1) monitorHistoriesById(c *gin.Context) {
177177

178178
log.Printf("服务器 %d 的ICMP/TCP监控器ID列表: %v", server.ID, icmpTcpMonitorIDs)
179179

180-
// 性能优化:直接查询指定服务器和监控器的记录
180+
// 根本性能优化:使用高效的数据库查询,恢复合理的数据量
181181
var networkHistories []*model.MonitorHistory
182182

183183
for _, monitorID := range icmpTcpMonitorIDs {
184-
// 为每个监控器单独查询,避免全表扫描
185-
histories, err := monitorOps.GetMonitorHistoriesByServerAndMonitor(server.ID, monitorID, startTime, endTime, 200)
184+
// 使用优化的查询方法,每个监控器200条记录(3天数据)
185+
histories, err := monitorOps.GetMonitorHistoriesByServerAndMonitorOptimized(server.ID, monitorID, startTime, endTime, 200)
186186
if err != nil {
187187
log.Printf("查询监控器 %d 的历史记录失败: %v", monitorID, err)
188188
continue

db/model_ops.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,122 @@ func (o *MonitorHistoryOps) GetMonitorHistoriesByServerAndMonitor(serverID, moni
254254
return histories, nil
255255
}
256256

257+
// GetMonitorHistoriesByServerAndMonitorOptimized 高效查询特定服务器和监控器的历史记录
258+
func (o *MonitorHistoryOps) GetMonitorHistoriesByServerAndMonitorOptimized(serverID, monitorID uint64, startTime, endTime time.Time, limit int) ([]*model.MonitorHistory, error) {
259+
var histories []*model.MonitorHistory
260+
261+
// 关键优化:使用更精确的key前缀,减少扫描范围
262+
// BadgerDB中的key格式通常是 "monitor_history:timestamp:serverid:monitorid" 或类似格式
263+
// 我们需要找到最优的扫描策略
264+
265+
err := o.db.db.View(func(txn *badger.Txn) error {
266+
opts := badger.DefaultIteratorOptions
267+
opts.PrefetchValues = false // 先不预取值,只扫描key
268+
opts.PrefetchSize = 1000
269+
it := txn.NewIterator(opts)
270+
defer it.Close()
271+
272+
prefix := "monitor_history:"
273+
count := 0
274+
275+
// 第一阶段:快速扫描key,过滤出匹配的记录
276+
var matchingKeys [][]byte
277+
278+
for it.Seek([]byte(prefix)); it.ValidForPrefix([]byte(prefix)) && count < limit*2; it.Next() {
279+
item := it.Item()
280+
key := item.Key()
281+
282+
// 快速检查:先获取值来判断是否匹配条件
283+
err := item.Value(func(val []byte) error {
284+
// 快速解析:只解析必要的字段
285+
var quickCheck struct {
286+
ServerID uint64 `json:"ServerID"`
287+
MonitorID uint64 `json:"MonitorID"`
288+
CreatedAt time.Time `json:"CreatedAt"`
289+
}
290+
291+
if err := json.Unmarshal(val, &quickCheck); err != nil {
292+
return nil // 跳过无效记录
293+
}
294+
295+
// 快速过滤
296+
if quickCheck.ServerID == serverID &&
297+
quickCheck.MonitorID == monitorID &&
298+
quickCheck.CreatedAt.After(startTime) &&
299+
quickCheck.CreatedAt.Before(endTime) {
300+
// 复制key以避免BadgerDB的内存重用问题
301+
keyCopy := make([]byte, len(key))
302+
copy(keyCopy, key)
303+
matchingKeys = append(matchingKeys, keyCopy)
304+
count++
305+
}
306+
307+
return nil
308+
})
309+
310+
if err != nil {
311+
return err
312+
}
313+
}
314+
315+
// 第二阶段:只处理匹配的记录,按时间排序
316+
type recordWithTime struct {
317+
history *model.MonitorHistory
318+
time time.Time
319+
}
320+
321+
var records []recordWithTime
322+
323+
for _, key := range matchingKeys {
324+
item, err := txn.Get(key)
325+
if err != nil {
326+
continue
327+
}
328+
329+
err = item.Value(func(val []byte) error {
330+
var history model.MonitorHistory
331+
if err := json.Unmarshal(val, &history); err != nil {
332+
return nil
333+
}
334+
335+
records = append(records, recordWithTime{
336+
history: &history,
337+
time: history.CreatedAt,
338+
})
339+
340+
return nil
341+
})
342+
343+
if err != nil {
344+
return err
345+
}
346+
}
347+
348+
// 按时间排序(最新的在前)
349+
sort.Slice(records, func(i, j int) bool {
350+
return records[i].time.After(records[j].time)
351+
})
352+
353+
// 限制结果数量
354+
maxResults := limit
355+
if len(records) < maxResults {
356+
maxResults = len(records)
357+
}
358+
359+
for i := 0; i < maxResults; i++ {
360+
histories = append(histories, records[i].history)
361+
}
362+
363+
return nil
364+
})
365+
366+
if err != nil {
367+
return nil, fmt.Errorf("failed to query monitor histories optimized: %w", err)
368+
}
369+
370+
return histories, nil
371+
}
372+
257373
// CleanupOldMonitorHistories removes monitor histories older than maxAge
258374
func (o *MonitorHistoryOps) CleanupOldMonitorHistories(maxAge time.Duration) (int, error) {
259375
// Get all monitor IDs

resource/template/theme-default/network.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@
426426
return $.ajax({
427427
url: "/api/v1/monitor/"+id,
428428
method: "GET",
429-
timeout: 10000, // 10秒超时
429+
timeout: 10000, // 超时时间10秒
430430
cache: true // 启用缓存
431431
});
432432
},

0 commit comments

Comments
 (0)