誤解を招く設定
Vaporでコネクションプールを設定する際(Redis、PostgreSQL、その他のデータベースを問わず)、maximumActiveConnectionsというパラメータに出会います。自然に考えると、これはアプリケーション全体の最大接続数を設定するものだと思うでしょう。実際はそうではありません。NIOのEventLoopごとの最大値を設定します。
この違いは本番環境で非常に重要です。
驚かされた計算
一般的なサーバーでは、Swift NIOはCPUコアごとに1つのEventLoopを作成します。つまり、実際の最大接続数は以下の通りです:
actual max = maximumActiveConnections * CPU cores * number of dynos/instancesmaximumActiveConnectionsを8に設定し、2つのdynoでRedis接続を妥当な16に制限していると思っていました。実際の数値は:
8 (per event loop) * 8 (cores) * 2 (dynos) = 128 potential connections意図した数の1桁多い値で、トラフィックスパイク時にRedisプロバイダーの接続制限を超えていました。

症状
障害モードは特に厄介です:負荷がかかった時にだけ現れる断続的な500エラー。通常のトラフィックでは実際の接続制限に達しないため、すべて正常に動作します。スパイク時には、すべてのevent loop全体で接続が同時に積み上がり、プロバイダーの制限を超えます。エラーはランダムに見え、開発マシンは通常コア数が少ないためローカルでの再現が困難です。
適切な値の計算方法
プロバイダーの接続制限を、すべてのインスタンスの合計event loop数で割ります:
// Provider limit: 40 connections
// 2 dynos * 8 cores = 16 event loops total
// 40 / 16 = 2.5, round down to 2
app.redis.configuration = .init(
pool: .init(maximumActiveConnections: 2)
)この保守的な設定により、何ヶ月も悩まされていたTranslateKitの稀に発生する500エラーがようやく修正されました。デプロイ前には必ずクラウドプロバイダーの接続制限を確認し、掛け算をしてください。
