在 haproxy 中的写入故障转移期间,进行中的 mysql 事务会发生什么情况?

What happens to in-flight mysql transactions during a write failover in haproxy?

我目前已将 haproxy 配置为对一组 mysql 服务器进行负载平衡和故障转移。我有一个为写入事务配置的后端,如下所示:

backend pool_mysql_write
timeout connect 10s
timeout server 1m
mode tcp
option mysql-check user haproxy_check
server primary <primary_node>:3306 check fastinter 1000
server secondary <secondary_node>:3306 check fastinter 1000 backup

存在 "backup" 指令,以便所有写入仅进入主数据库节点,并且仅当主数据库发生故障时才会故障转移到辅助节点。

编辑:数据库节点处于主-主复制模式。

我的问题是,当 haproxy 正在故障转移到辅助数据库节点 时,正在运行的 mysql 写入查询会发生什么情况?例如,如果 haproxy 需要 5 秒来提升辅助数据库节点以进行写入,那么在故障转移时间的 5 秒内可能一直试图写入数据库的所有写入查询会发生什么情况?

他们就这样消失了吗?它们是否在某个地方排队,以便在辅助数据库节点提升后可以提交它们?

当(由客户端)发起到 haproxy 的新 TCP 连接时,它又打开到上游服务器的新 TCP 连接。一旦建立了上游 TCP 连接,haproxy 就会将这些 TCP 连接连接在一起,来回中继通信。

如果这些 TCP 连接中的任何一个(即它与客户端的连接,或它与上游服务器的连接)断开,haproxy 只会断开另一个——换句话说,haproxy不会将现有 TCP 连接移交给替代服务器(它只是重定向新连接)。交易对手负责决定下一步做什么。 (对于更智能的方法,您需要像 MariaDB MaxScale 这样的第 7 层代理,它可以重新路由现有连接)。

通常,如果其连接意外断开,客户端将尝试重新连接(此时 haproxy 可能最终将其连接到不同的上游服务器,例如因为原始服务器不再可用)。

问题是,如果客户端向原始服务器发送了会改变其状态的命令怎么办?

  • 如果客户端在连接断开之前收到了提交确认,则客户端将了解其写入已提交。因此,您必须确定 primary 在将写入复制到 secondary 之前不会确认提交——因此我在上面询问您如何执行该复制:至少,您想要 Semisynchronous Replication :

    MySQL replication by default is asynchronous. The master writes events to its binary log but does not know whether or when a slave has retrieved and processed them. With asynchronous replication, if the master crashes, transactions that it has committed might not have been transmitted to any slave. Consequently, failover from master to slave in this case may result in failover to a server that is missing transactions relative to the master.

    Semisynchronous replication can be used as an alternative to asynchronous replication:

    [ deletia ]

    While the master is blocking (waiting for acknowledgment from a slave), it does not return to the session that performed the transaction. When the block ends, the master returns to the session, which then can proceed to execute other statements. At this point, the transaction has committed on the master side, and receipt of its events has been acknowledged by at least one slave.

  • 如果客户端在连接断开之前未收到提交确认,则客户端应假定写入未提交并进行相应处理——例如建立新连接后重新尝试交易。

    然而,可能 primary 实际上已经提交了写入(并且确实将它们复制到 secondary),但就在它之前失败了发送了提交确认,或者它发送了提交确认但在客户端收到之前连接失败。我认为对此无能为力(请发表评论?),但风险非常小(因为在完成提交和发送确认之间没有任何处理)。