feat(db): implement PostgreSQL monitoring and maintenance features
CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 2m11s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m27s
CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 2m11s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m27s
Added PostgreSQL monitoring and maintenance capabilities to the API, including new endpoints for instance-level metrics, maintenance operations, and job scheduling. Updated the HTTP API to support PostgreSQL monitoring routes and integrated a background scheduler for metrics collection. Enhanced the CLI with database commands for maintenance tasks. Updated documentation to reflect these changes.
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package pgmonitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Recommendations builds heuristic items from live stats and snapshots.
|
||||
func (s *Service) Recommendations(ctx context.Context) (RecommendationsResponse, error) {
|
||||
now := time.Now().UTC()
|
||||
var items []RecommendationItem
|
||||
|
||||
ov, err := s.Overview(ctx)
|
||||
if err == nil {
|
||||
if ov.Database.CacheHitPct > 0 && ov.Database.CacheHitPct < 90 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "warn",
|
||||
Code: "low_cache_hit",
|
||||
Title: "Низкий cache hit ratio",
|
||||
Detail: "Buffer cache hit ниже 90%; проверьте shared_buffers и горячие seq scan.",
|
||||
})
|
||||
}
|
||||
if ov.Database.Deadlocks > 0 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "warn",
|
||||
Code: "deadlocks",
|
||||
Title: "Зафиксированы deadlocks",
|
||||
Detail: "Проверьте конкурирующие транзакции и порядок блокировок.",
|
||||
})
|
||||
}
|
||||
if ov.Connections.MaxConnections > 0 &&
|
||||
float64(ov.Connections.Total)/float64(ov.Connections.MaxConnections) > 0.8 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "critical",
|
||||
Code: "connections_high",
|
||||
Title: "Много подключений к PostgreSQL",
|
||||
Detail: "Использование max_connections выше 80%; увеличьте pool tuning или лимит.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
tables, err := s.Tables(ctx, 30)
|
||||
if err == nil {
|
||||
for _, t := range tables {
|
||||
if t.SeqScan > 1000 && t.IdxScan < t.SeqScan/10 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "warn",
|
||||
Code: "missing_index",
|
||||
Title: "Высокий seq_scan",
|
||||
Detail: "Таблица часто сканируется последовательно; рассмотрите индекс.",
|
||||
Refs: []string{t.Relname},
|
||||
})
|
||||
}
|
||||
if t.BloatRatio > 0.2 && t.DeadTuples > 5000 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "info",
|
||||
Code: "autovacuum_lag",
|
||||
Title: "Возможный bloat / мёртвые строки",
|
||||
Detail: "Высокая доля n_dead_tup; запланируйте VACUUM.",
|
||||
Refs: []string{t.Relname},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if snap, ok, _ := s.loadSnapshot(ctx, "unused_indexes", 30*time.Minute); ok {
|
||||
type unused struct {
|
||||
Index string `json:"index"`
|
||||
SizeBytes int64 `json:"size_bytes"`
|
||||
}
|
||||
var list []unused
|
||||
if decodePayload(snap.Payload, &list) == nil {
|
||||
for _, u := range list {
|
||||
if u.SizeBytes < 1024*1024 {
|
||||
continue
|
||||
}
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "info",
|
||||
Code: "unused_index",
|
||||
Title: "Неиспользуемый индекс",
|
||||
Detail: "idx_scan=0; проверьте перед удалением.",
|
||||
Refs: []string{u.Index},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q, err := s.TopQueries(ctx, 5)
|
||||
if err == nil {
|
||||
for _, qs := range q.Items {
|
||||
if qs.MeanExecMs > 500 {
|
||||
items = append(items, RecommendationItem{
|
||||
Severity: "warn",
|
||||
Code: "slow_query",
|
||||
Title: "Медленный запрос",
|
||||
Detail: "Среднее время выполнения выше 500ms.",
|
||||
Refs: []string{qs.Query},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RecommendationsResponse{CollectedAt: now, Items: items}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user