Postgres LISTEN/NOTIFY - 低延迟,实时?
Posted
技术标签:
【中文标题】Postgres LISTEN/NOTIFY - 低延迟,实时?【英文标题】:Postgres LISTEN/NOTIFY - low latency, realtime? 【发布时间】:2015-12-31 01:58:13 【问题描述】:我打算使用 postgres LISTEN/NOTIFY 方法来获取表中记录的插入时间(实际事务提交时间)。为了实现这一点,我计划做以下事情。我在插入时发出通知,如下所示。
BEGIN;
INSERT INTO table_name(id, ...) values (id,....);
select pg_notify('test_channel', 'id - ' || id || ' trans start time - ' || now() || ' notify start time - ' || clock_timestamp());
END;
然后我打算使用https://pythonhosted.org/psycopg2/advanced.html#asynchronous-notifications 来接收这些通知。
我想知道的是事务提交发生的确切时间(记录可读取)到微秒
我知道 NOTIFY(pg_notify) 实际上是在事务提交后立即发送通知,但我不知道如何找出它发生的确切时间。我在 NOTIFY 中拥有的时钟时间戳值不是实际的事务提交时间。
我猜我收听通知的时间将接近事务提交时间,但我不确定它有多接近。首先,在我的代码中进行侦听时的轮询之间有一段时间(无论它多么小),其次,我不确定 NOTIFY/LISTEN 通信本身之间是否存在任何滞后。
有什么想法吗?
更新(问题的完整描述):我们有一个阅读器使用“检查点”时间分批选择行,其中每个批次获取上一个批次中最后一个时间戳之后的行,我们缺少行。 (原因:时间戳值基于插入发生的时间(00.00.00)。在重负载下,如果事务需要更长的时间,它会被插入,比如说 10 秒后(00.00.10),读者会错过这一行(row1) 如果它在那 10 秒内读取并找到其 INSERT 时间比 row1 更晚的时间(00.00.05) 的行。问题的完整描述类似于此博客中所写的。http://blog.thefourthparty.com/stopping-time-in-postgresql/ )
【问题讨论】:
呃……为什么?你想用这个来达到什么目的?您试图解决的根本问题是什么,您需要它的原因是什么? 我在描述中更新了我们试图解决的问题。 所以您只是想实现一个具有多个写入器和一个读取器的可靠队列?试图以这种方式修复无序提交和可见性问题是行不通的。考虑在实际的基础主题上发布一个新的单独问题,即当队列读取器扫描表然后在读取后提交正在进行的事务时如何避免丢失行。令人沮丧的是你之前忽略了我的问题。 在这里发布了一个单独的问题。 ***.com/questions/32946852/… 【参考方案1】:我想知道的是事务提交发生的确切时间(记录可读取)到微秒
方便地,PostgreSQL 9.5 刚刚以支持提交时间戳的形式添加了这一点。见commit timestamps。请注意,您必须启用 track_commit_timestamp
才能使用它,并且有关提交时间戳的信息不会永远保留,因此相当旧的行只会得到空结果。
您可以在交易过程中的任何时候使用txid_current()
获取交易ID。例如,也许使用insert ... returning ...
。然后,您可以在提交后的后续查询中查找提交时间戳。
对于旧版本,您应该只在您的insert ... returning ...
子句中包含clock_timestamp
。这将是插入记录的时间,而不是提交时间,但这确实是可能获得的最接近的时间。
我猜我收听通知的时间将接近事务提交时间,但我不确定它有多接近。
“相当”。这将取决于网络延迟、CPU 调度延迟等。它肯定不会精确到微秒。
例如,在 Windows 上,它最多可以精确到毫秒,但默认情况下,它会精确到最接近的 15 毫秒计时器滴答声。
首先,在我的代码中的轮询之间有一些时间在听(不管它有多小)
不要投票。 select()
套接字,因此您在有数据要读取的那一刻就被唤醒了。在 Linux 上,您最好为此使用 epoll()
系统调用。
其次,我不确定 NOTIFY/LISTEN 通信本身之间是否有任何延迟。
有些,是的,因为事务提交需要时间。因此,在您发出 NOTIFY
和将事件发送给侦听器之间存在一些非零时间。
【讨论】:
总结您回答中的最后三个响应.....因此,如果我们排除事务提交所花费的时间,因为在事务提交后立即发送通知并且如果我使用 select() NOTIFY 和 LISTEN 之间的唯一时间延迟不是轮询,而是由于网络延迟、CPU 调度等原因。我的理解是否正确?据了解,NOTIFY的payload中的clock_timestamp值没有交易结束时间。 嗯,提交不是即时的,就可见性而言,它只是原子的。如果你说的是微秒,那开始很重要。在提交后工作期间,在 clog 中设置提交后发送通知。有关详细信息,请参阅源代码。此外,select()
和 epoll()
不一定是零延迟;事实上,由于内核中的延迟、系统管理中断等,它们很容易在数据变得可读和通知您的应用程序之间有几毫秒的延迟。您需要一个实时进程和低延迟内核才能拥有任何明智的 -是的。
听起来您正在尝试将 PostgreSQL 用作实时系统,但事实并非如此。它不是设计的。它在 LWLocks 中可能有很长的锁定延迟。它可以在文件系统操作期间阻塞关系扩展锁。它可以在检查点期间被缓冲区引脚延迟。各种各样的事情意味着即使延迟通常很低,它们也不是有界,也不是总是低。如果你有很多负载和运气不好,你可能会在提交和处理通知之间有很大的延迟。你永远不会知道你的方法。不可靠。
还有,psycopg2 和 python?对于超低延迟/实时?认真的吗?
除了为此目的使用 psyconpg2 和 python 之外,您还有其他建议吗?【参考方案2】:
now() 将始终小于事务提交且对读者可见的实际时间(除非您将脏读作为隔离级别)。
一种更好的方法(没有竞争条件的方法)是调用 pg_notify() 并在事务结束后立即使用 clock_timestamp()(并且仅在事务提交时)。
【讨论】:
使用NOTIFY
与 pg_notify()
完全没有区别。不过,使用clock_timestamp
而不是now()
(这是交易的current_timestamp
)是一个很好的建议。我不明白您所说的“交易结束后”是什么意思。 tx 结束后你不能做任何事情,除非你做另一笔交易。
您的意思是在“插入后”设置一个触发器,它会有 NOTIFY 语句吗?根据我的理解,触发器是当前交易的一部分,会增加总交易时间的时间吗?在提交之后我还能如何添加一个 NOTIFY?
您是正确的,after insert
触发器在事务期间触发,并且作为事务的一部分。通知由触发器排队,然后在提交后传递。以上是关于Postgres LISTEN/NOTIFY - 低延迟,实时?的主要内容,如果未能解决你的问题,请参考以下文章
postgres数据库入门, python 操作postgres
Postgres:将自定义类型从 Java 传递给 postgres 函数