加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

在“COMMIT”之后收到“终止”(‘X’)后的PostgreSQL后端行为

发布时间:2020-12-13 15:52:42 所属栏目:百科 来源:网络整理
导读:我们运行postgres服务器v9.2.8,并使用epgsql(erlang)作为客户端库.在某些情况下,我们在生产环境中生产但无法在开发环境中重现,我们正在丢失数据. 我们的应用程序中的一个函数(应该被杀死)允许运算符在正在运行的连接上更改会话参数.由于连接通常在生产时总是
我们运行postgres服务器v9.2.8,并使用epgsql(erlang)作为客户端库.在某些情况下,我们在生产环境中生产但无法在开发环境中重现,我们正在丢失数据.

我们的应用程序中的一个函数(应该被杀死)允许运算符在正在运行的连接上更改会话参数.由于连接通常在生产时总是很忙,因此“SET SESSION bla-bla”查询总是会崩溃pgsql_connection进程.

在崩溃之前,pgsql_connection通过pgsql_sock(tcp套接字的包装器)向后端发送“终止”(‘X’)信号.同时另一个erlang进程(让我们称之为“worker”)正在等待postgres后端使用相同套接字的响应.

现在的问题是:收到客户端的“终止”信号后,即使已经在“COMMIT”语句中发送了“OK”,后端也可以取消最后一次交易吗?

因为如果可能的话,工作人员将有机会向主申请流程报告成功写入的交易,而事务确实已被取消.

或者,我在哪里可以阅读有关此的更多详细信息?文件说(http://www.postgresql.org/docs/9.2/static/protocol-flow.html):

For either normal or abnormal termination,any open transaction is
rolled back,not committed. One should note however that if a frontend
disconnects while a non-SELECT query is being processed,the backend
will probably finish the query before noticing the disconnection. If
the query is outside any transaction block (BEGIN … COMMIT sequence)
then its results might be committed before the disconnection is
recognized.

– 不是一个清晰的声明.

解决方法

Now the question: is it possible that upon receiving a “Terminate” signal from a client,backend can cancel last transaction even if it has sent an “OK” on “COMMIT” statement already?

从根本上说不可能.如果它已经提交,那么它已经提交,并且没有回头路.这就是“提交”的意思.

Pg可能在提交命中磁盘之前返回成功的唯一时间是持久性的,如果你通过设置synchronous_commit = off来告诉它.

如果您发现任何不同的情况发生,那么很可能是因为尝试在多个进程之间共享单个连接(当您在fork()之前建立连接)而没有正确的锁定或其他互斥以确保连接被锁定时一个命令在飞行中.

请注意,反之亦然,这可能是您在引用的文档段落中所考虑的内容.如果客户端在发出commit命令后消失(崩溃,丢失连接等),则可以在不向客户端返回成功OK的情况下提交事务.

应用程序正在做什么,它在有线协议上发送不同步消息的地方完全被破坏了.它保证会导致不可预测的问题.该协议有点健壮,因此您不太可能得到类似意外提交的内容,但您很可能会中断事务或突然断开整个会话.

如果您需要能够回滚/中止已提交的事务,那么您的应用程序设计就会出现问题.当你说COMMIT时,你还没准备好提交.如果应用程序进程崩溃或整个服务器在提交事务的Pg和您需要做的任何事情之间崩溃,则会遇到同样的问题.

如果您无法修复应用程序设计以避免这种情况,那么您将不得不使用两阶段事务,直接使用PREPARE TRANSACTION然后COMMIT PREPARED,或间接通过XA API.这在性能和管理开销方面会产生很大的成本,但如果您需要在数据库提交后但在“真正完成”之前完成特殊工作,这是唯一的选择.

您引用的文档正在讨论应用程序发送COMMIT但在接收后端确认提交之前断开连接的情况.因为TCP / IP是缓冲的,所以不能保证COMMIT被刷新到Pg,如果确实这样做,则无法保证它不会伴随终止连接的RST.因此,在这种特定情况下,交易是否会提交有些不确定.这是一个问题的应用程序需要有一种方法来检查在恢复工作时是否提交了最后一个工作单元,或者如果它不能使用两阶段事务.你引用的文档没有提到在完成后取消提交,因为你不能.永远.

假设应用程序在提交后必须执行某种额外的工作,例如移动文件或发送电子邮件或在另一个数据存储上工作,那么您可能需要两阶段事务.即使这样,除非分布式事务中的所有各方都支持两阶段提交,否则你很容易受到攻击,因为你的“其他位”可以完成,那么你的工作者或服务器可能会在确认完成之前发送到数据库以完成阶段提交的二.

您可以在DB中保留自己的两阶段提交日志,而不是使用真正的2PC:

>主数据库是否正常工作并将记录写入工作日志表,其中写着“我已完成数据库中的工作,我即将完成下一部分工作”.
>做下一部分;和
>更新工作日志以说明下一部分已完成.

…但是这有同样的问题,第2部分和第3部分之间的崩溃导致应用程序忘记它执行了第2部分并在启动时重复它.如果您不能忍受这种情况,您需要找到一种方法来使第2部分提交完成可验证,这样您就可以判断它是否已完成,或者找到一种方法使其能够进行两阶段提交.

要了解有关此主题的更多信息,请阅读有关XA,分布式事务,两阶段提交等的信息.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读