客户端连接池
通过 ActiveRecord 访问数据库的 Ruby 进程,会根据并发性自动计算该进程的连接池大小。
由于 Ruby on Rails 管理数据库连接 的方式,我们拥有的连接数至少要和线程数一样多。虽然 database.yml 中有一个 ‘pool’ 设置,但这不太实用,因为你需要与应用线程数保持同步维护。因此,我们根据配置的应用线程数来覆盖数据库连接池中允许的连接数。
Gitlab::Runtime.max_threads 是进程配置的用户端应用线程数。我们还有一些使用数据库连接的辅助线程。由于随着应用的演进,准确统计辅助线程的数量并不简单,我们只是在用户端线程数上增加一个固定的余量。如果这个数字过大也没关系,因为连接是延迟实例化的。
连接池问题排查
每个环境的连接池使用情况可以在 连接池饱和度仪表板 中看到。
如果连接池太小,这会在应用程序中表现为 ActiveRecord::ConnectionTimeoutError。由于我们在几乎所有的连接都被使用时会发出警报,我们应该在超时发生前就知道这个问题。如果发生这种情况,我们可以通过将 DB_POOL_HEADROOM 环境变量设置为比硬编码值(10)更大的值来修复。
此时,我们需要调查是什么使用了比预期更多的连接。为此,我们可以使用 gitlab_ruby_threads_running_threads 指标。例如,这个图表 按名称显示了所有连接到数据库的运行线程。标记为 puma worker 或 sidekiq_worker_thread 的线程是定义 Gitlab::Runtime.max_threads 的线程,这些已经被计入。如果有超过 10 个其他线程在运行,我们可以考虑提高默认的余量。
连接生命周期
对于 Web 请求,在首次进行数据库查询时从连接池获取连接。请求完成后,连接会返回到连接池。
对于后台任务,行为非常相似。线程在首次查询时获取连接,并在任务完成后返回它。
这是由 Rails 内部管理的。