数据库负载均衡
- 从专业版移动到免费版于 14.0 版本。
- 为 Sidekiq 引入于 14.1 版本。
使用数据库负载均衡,只读查询可以分布在多个 PostgreSQL 节点上以提高性能。
此功能在 Rails 和 Sidekiq 中本地提供,可以将它们配置为以循环方式平衡其数据库读取查询,而无需任何外部依赖:
启用数据库负载均衡的要求
要启用数据库负载均衡,请确保:
- HA PostgreSQL 设置具有一个或多个复制主节点的次要节点。
- 每个 PostgreSQL 节点都使用相同的凭据和相同的端口连接。
对于 Omnibus GitLab,您还需要在每个 PostgreSQL 节点上配置 PgBouncer,以便在配置多节点设置时汇集所有负载均衡连接。
配置数据库负载均衡
可以通过以下两种方式之一配置数据库负载平衡:
Hosts
要配置主机列表,在您要配置负载均衡的每个环境的所有 Rails (Sidekiq) 节点上执行以下步骤:
- 编辑
/etc/gitlab/gitlab.rb
文件。 -
在
gitlab_rails['db_load_balancing']
中,创建一个要负载均衡的只读副本数组。不要添加主要主机。例如,在主机primary.example.com
、host1.example.com
、host2.example.com
和host3.example.com
上运行 PostgreSQL 的环境中运行:gitlab_rails['db_load_balancing'] = { 'hosts' => ['host1.example.com', 'host2.example.com', `host3.example.com`] }
这些副本必须可以在使用
gitlab_rails['db_port']
配置的相同端口上访问。 - 保存文件并重新配置极狐GitLab。
服务发现
服务发现允许极狐GitLab 自动检索要使用的 PostgreSQL 主机列表。它定期检查 DNS A
记录,使用此记录返回的 IP 作为辅助服务器的地址。要使服务发现工作,您只需要一个 DNS 服务器和一个包含辅助服务器 IP 地址的 A
记录。
使用 Omnibus GitLab 时,提供的 Consul 服务用作 DNS 服务器,并通过 postgresql-ha.service.consul
记录返回 PostgreSQL 地址。例如:
- 在每个 Rails/Sidekiq 节点上,编辑
/etc/gitlab/gitlab.rb
并添加以下内容:
gitlab_rails['db_load_balancing'] = { 'discover' => {
'nameserver' => 'localhost'
'record' => 'postgresql-ha.service.consul'
'record_type' => 'A'
'port' => '8600'
'interval' => '60'
'disconnect_timeout' => '120'
}
}
- 保存文件并重新配置极狐GitLab,使更改生效。
选项 | 描述 | 默认值 |
---|---|---|
nameserver
| 用于查找 DNS 记录的名称服务器。 | localhost |
record
| 要查找的记录。此选项是服务发现工作所必需的。 | |
record_type
| 要查找的可选记录类型,可以是 A 或 SRV 。
| A
|
port
| 名称服务器的端口。 | 8600 |
interval
| 检查 DNS 记录之间的最短时间(以秒为单位)。 | 60 |
disconnect_timeout
| 更新主机列表后关闭旧连接的时间(以秒为单位)。 | 120 |
use_tcp
| 使用 TCP 而不是 UDP 查找 DNS 资源。 | false |
如果 record_type
设置为 SRV
,则极狐GitLab 继续使用循环算法并忽略记录中的 weight
和 priority
。由于 SRV
记录通常返回主机名而不是 IP,极狐GitLab 需要在 SRV
响应的附加部分中查找返回的主机名的 IP。
如果没有找到主机名的 IP,极狐GitLab 需要为每个这样的主机名查询配置的 nameserver
的 ANY
记录,以寻找 A
或 AAAA
记录,如果无法解析它的 IP,最终从轮替中删除此主机名。
interval
值指定检查之间的最短时间。如果 A
记录的 TTL 大于此值,则服务发现会尊重该 TTL。例如,如果 A
记录的 TTL 为 90 秒,那么服务发现在再次检查 A
记录之前至少等待 90 秒。
更新主机列表时,可能需要一段时间才能终止旧连接。disconnect_timeout
设置可用于强制终止所有旧数据库连接所需的时间上限。
处理过时的读取
从专业版移到免费版于 14.0 版本。
为了防止从过时的次要节点读取数据,负载均衡器会检查它是否与主节点同步。如果数据足够新,则使用次要节点数据,否则将被忽略。为了减少这些检查的开销,我们只在特定的时间间隔执行它们。
影响此行为的三个配置选项:
选项 | 描述 | 默认值 |
---|---|---|
max_replication_difference
| 当次要节点有一段时间没有复制数据时,它允许滞后的数据量(以字节为单位)。 | 8 MB |
max_replication_lag_time
| 在我们停止使用次要节点之前,它允许滞后的最大秒数。 | 60 seconds |
replica_check_interval
| 在检查次要节点状态之前,我们必须等待的最小秒数。 | 60 seconds |
对于大多数用户来说,默认值应该足够了。
要使用主机列表配置这些选项,请使用以下示例:
gitlab_rails['db_load_balancing'] = {
'hosts' => ['host1.example.com', 'host2.example.com', `host3.example.com`]
'max_replication_difference' => 16777216 # 16 MB
'max_replication_lag_time' => 30
'replica_check_interval' => 30
}
日志记录
负载均衡器在 database_load_balancing.log
中记录各种事件,例如:
- 当主机被标记为离线时
- 当主机重新上线时
- 当所有从属节点都离线时
- 由于查询冲突而在不同主机上重试读取时
日志由每个条目构成一个 JSON 对象,其中至少包含:
- 用于过滤的
event
字段。 - 一个人类可读的
message
字段。 - 一些特定于事件的元数据。例如,
db_host
。 - 始终记录的上下文信息。例如,
severity
和time
。
例如:
{"severity":"INFO","time":"2019-09-02T12:12:01.728Z","correlation_id":"abcdefg","event":"host_online","message":"Host came back online","db_host":"111.222.333.444","db_port":null,"tag":"rails.database_load_balancing","environment":"production","hostname":"web-example-1","fqdn":"gitlab.example.com","path":null,"params":null}
实施细节
均衡查询
只读 SELECT
查询所有给定主机之间的平衡。
其他所有内容(包括事务)都在主节点上执行。
诸如 SELECT ... FOR UPDATE
之类的查询也在主节点上执行。
准备好的语句
准备好的语句不适用于负载平衡,并且在启用负载平衡时会自动禁用。这不应该影响响应时间。
主节点粘结
执行写入后,极狐GitLab 会在一段时间内坚持使用主节点,范围仅限于执行写入的用户。极狐GitLab 在它们赶上或 30 秒后恢复使用次要节点。
故障转移处理
如果发生故障转移或数据库无响应,负载均衡器会尝试使用下一个可用主机。如果没有可用的次要节点,则改为在主节点上执行操作。
如果在写入数据时发生连接错误,该操作会使用指数回退重试最多 3 次。
使用负载均衡时,您应该能够安全地重新启动数据库服务器,而不会立即导致向用户显示错误。