以下の内容はhttps://tech.kanmu.co.jp/entry/2025/02/12/125604より取得しました。


Goのコネクションプーリングまわりのメトリクス収集

プラットフォームチームの菅原です。

Goでデータベースを使う場合には、以下のメソッドでコネクションプーリングまわりの設定を調整することが多いと思います。

MaxOpenConnsを設定してアプリケーションからの接続がデータベースのリミットを超えないようにしたり、MaxIdleConnsを設定してアイドルコネクションを保持し接続が都度発生しないようにしたりしますが、サービスにデプロイされた後はその設定が正しいか調べるためメトリクスが必要になります。

func (db *DB) Stats()はそれらコネクションプーリングの統計データを返すメソッドで、以下のような構造体を返します。

type DBStats struct {
    MaxOpenConnections int // Maximum number of open connections to the database.

    // Pool Status
    OpenConnections int // The number of established connections both in use and idle.
    InUse           int // The number of connections currently in use.
    Idle            int // The number of idle connections.

    // Counters
    WaitCount         int64         // The total number of connections waited for.
    WaitDuration      time.Duration // The total time blocked waiting for a new connection.
    MaxIdleClosed     int64         // The total number of connections closed due to SetMaxIdleConns.
    MaxIdleTimeClosed int64         // The total number of connections closed due to SetConnMaxIdleTime.
    MaxLifetimeClosed int64         // The total number of connections closed due to SetConnMaxLifetime.
}

カンムのサービスではモニタリング・ログ収集にDatadog、Goアプリからのログ出力にzerologを使っているので、アプリ起動時に以下のようなgoroutineを実行してコネクションプーリングの統計データをログ出力するようにしてみました。

// goroutine
func LogDBStats(db *sql.DB, host string, interval time.Duration, logger *zerolog.Logger) func() {
    ticker := time.NewTicker(interval)
    done := make(chan struct{})

    go func() {
        for {
            select {
            case <-done:
                return
            case <-ticker.C:
                logger.Info().
                    Str("log_type", "db_stats").
                    Str("host", host).
                    Interface("db_stats", db.Stats()).
                    Msg("Database statistics")
            }
        }
    }()

    return func() {
        ticker.Stop()
        close(done)
    }
}
// アプリ側
if cfg.DBStatsIntervalSec > 0 {
    interval := time.Duration(cfg.DBStatsIntervalSec) * time.Second
    cleanup := utils.LogDBStats(db, cfg.DBHost, interval, &logger)
    defer cleanup()
}

こうするとDatadogのログ管理でコネクションプーリングの統計データを見られるようになります。

またログの属性値からグラフを作成することも可能です。

これでコネクションプーリングまわりをモニタリングできるようになって便利になりました…

…と、思っていたのですが、dd-trace-goを調べてみたらv1.63.0でDB Statsを収集するための変更が入っていました。

github.com

なのでcontrib/database/sqlsqltrace.Open()/OpenDB()を使っている場合、WithDBStats()を使えば普通にメトリクスを収集することができます。

db := sqltrace.OpenDB(connector, sqltrace.WithServiceName("my-service"), sqltrace.WithDBStats())

Datadogのログ管理でメトリクスを収集する場合、メトリクスの保持期間がログの保持期間と同じなってしまうので、長期的にメトリクスを保持したい場合はWithDBStats()を使った方が良さそうです。




以上の内容はhttps://tech.kanmu.co.jp/entry/2025/02/12/125604より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14