storj/satellite/dbcleanup/chore.go
stefanbenten c6c8b923af satellite/dbcleanup: run cleanup more frequently
As the tables that get cleaned up by this job get a lot of inserts and deletes over the course of a day, the autovacuum process on PostgreSQL struggles fairly easily/quickly.
Due to its limitation, it can only delete 180,000,000 tuples in one go, before it has to rescan the entire table/index.

With the current load, the most busy satellites accumulate about 1,000,000,000 tuples per day (consumed_serials). With our current 24h interval that results in ~6-7 scans, slowing the entire database down for a quite long time.
This PR reduces the interval to 4 hours, which under a constant load, results in less than 180,000,000 entries per run.
That way, we do not scan twice for only a small gain over said amount. Reducing the interval further would also increase the DB load unnecessary, as each run scans the entire tables at least once.

For future reference, we might need to adjust the interval, if the load is significantly changing.

Change-Id: I18fdd45d93d468cff126e719c8380c29a49f43dd
2020-06-10 18:32:15 +00:00

84 lines
1.9 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package dbcleanup
import (
"context"
"time"
"github.com/spacemonkeygo/monkit/v3"
"github.com/zeebo/errs"
"go.uber.org/zap"
"storj.io/common/sync2"
"storj.io/storj/satellite/orders"
)
var (
// Error the default dbcleanup errs class.
Error = errs.Class("dbcleanup error")
mon = monkit.Package()
)
// Config defines configuration struct for dbcleanup chore.
type Config struct {
SerialsInterval time.Duration `help:"how often to delete expired serial numbers" default:"4h"`
}
// Chore for deleting DB entries that are no longer needed.
//
// architecture: Chore
type Chore struct {
log *zap.Logger
orders orders.DB
Serials *sync2.Cycle
}
// NewChore creates new chore for deleting DB entries.
func NewChore(log *zap.Logger, orders orders.DB, config Config) *Chore {
return &Chore{
log: log,
orders: orders,
Serials: sync2.NewCycle(config.SerialsInterval),
}
}
// Run starts the db cleanup chore.
func (chore *Chore) Run(ctx context.Context) (err error) {
defer mon.Task()(&ctx)(&err)
return chore.Serials.Run(ctx, chore.deleteExpiredSerials)
}
func (chore *Chore) deleteExpiredSerials(ctx context.Context) (err error) {
defer mon.Task()(&ctx)(&err)
chore.log.Debug("deleting expired serial numbers")
now := time.Now()
deleted, err := chore.orders.DeleteExpiredSerials(ctx, now)
if err != nil {
chore.log.Error("deleting expired serial numbers", zap.Error(err))
} else {
chore.log.Debug("expired serials deleted", zap.Int("items deleted", deleted))
}
deleted, err = chore.orders.DeleteExpiredConsumedSerials(ctx, now)
if err != nil {
chore.log.Error("deleting expired serial numbers", zap.Error(err))
} else {
chore.log.Debug("expired serials deleted", zap.Int("items deleted", deleted))
}
return nil
}
// Close stops the dbcleanup chore.
func (chore *Chore) Close() error {
chore.Serials.Close()
return nil
}