标签
PostgreSQL , quorom based sync replication , 2PC , 0丢失
背景
PostgreSQL 9.6开始支持了quorum based 同步复制机制,当客户端发起事务结束请求时,必须要等这笔事务对应的redo日志复制到了指定副本,主库才响应客户端。
从而保证客户端正常收到主库反馈后,WAL日志一定已经有了多个副本,保证数据的0丢失。
但是在极端情况下,可能无法保障0丢失,为什么呢?
因为WAL日志先落主库,然后等备库复制,最后反馈客户端。
比如用户提交事务前,备库挂了,实际上主库本地的WAL已经写了,数据在本地已经持久化。只是主库要等符合quorum based个数备库那边接收到WAL的位点反馈,才反馈给客户端提交成功。
因此,当客户端在等待过程中,如果连接中断,就会造成本地已提交,但是有可能某些备库没有收到WAL的情况。
客户端如果重新与主库建立连接,它可以看到已提交的数据。
在pg_shardman的介绍中,也提到了类似的问题
https://github.com/postgrespro/pg_shardman
The trade-off is well-known: asynchronous replication is faster, but allows replica to lag arbitrary behind the primary, which might lead to loss of a bunch of recently committed transactions (if primary holder fails), or WAL puffing up in case of replica failure. Synchronous replication is slower, but committed transaction are typically not dropped. Typically, because it is actually still possible to lose them without kind of 2PC commit. Imagine the following scenario:
- Primary's connection with replica is teared down.
- Primary executes a transaction, e.g. adds some row with id 42, commits it locally and blocks because there is no connection with replica.
- Client suddenly loses connection with primary for a moment and reconnects to learn the status of the transaction, sees the row with id 42 and thinks that it has been committed.
- Now primary fails permanently and we switch to the replica. Replica has no idea of that transaction, but client is sure it is committed.
2PC可以保证一次客户端连接丢失带来的问题
预提交成功
2PC提交
备库挂
主库2PC提交成功
客户端丢失连接
客户端重新发起连接,发现主库已经2PC提交成功,可以看到数据
主库挂掉
切换到备库,客户端重新发起连接,发现备库还没有数据,因为2PC还没有结束,可以人为介入处理,不会丢数据。
2PC不可以保证超过一次客户端连接丢失带来的问题
预提交
备库挂
主库预提交成功
客户端丢失连接
客户端重新发起连接,发现主库已经预提交成功,发起2PC提交
客户端丢失连接
客户端重新发起连接,发现主库已经2PC提交成功,可以看到数据
主库挂掉
切换到备库,客户端重新发起连接,发现备库还没有数据,丢数据。
小结
当备库挂掉,无法满足quorum时,客户端提交事务后,会处于等待状态,但是如果客户端丢失连接,再次发起请求,可以看到仅仅在主库提交的数据。对于2PC事务,只要多次丢失连接,同样会造成问题。
参考
《PG多节点(quorum based), 0丢失 HA(failover,switchover)方案》
《PostgreSQL 一主多从(多副本,强同步)简明手册 - 配置、压测、监控、切换、防脑裂、修复、0丢失 - 珍藏级》