java - Postgres/JDBC/逻辑复制 - 内存不足问题

标签 java postgresql jdbc change-data-capture debezium

我正在开发一个连接到逻辑复制槽的应用程序,以使用 WAL 事件。然后将这些 WAL 事件转发给 MQ 代理。这很好用,但我注意到一段时间后我的内存不足。我设法将问题最小化到负责获取 WAL 事件的代码。它与以下代码一起出现:

final Properties properties = new Properties();

PGProperty.USER.set(properties, "user");
PGProperty.PASSWORD.set(properties, "password");
PGProperty.ASSUME_MIN_SERVER_VERSION.set(properties, "9.4");
PGProperty.REPLICATION.set(properties, "database");
PGProperty.PREFER_QUERY_MODE.set(properties, "simple");

while (true) {
    Connection          connection   = null;
    PGConnection        PGConnection = null;
    PGReplicationStream stream       = null;

    try {
        connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/db", properties);
        PGConnection = connection.unwrap(PGConnection.class);
        stream = PGConnection.getReplicationAPI().replicationStream().logical().withSlotName("slot").start();

        while (true) {
            final ByteBuffer buffer = stream.read();

            // ... logic here ... (disabled during memory test)

            stream.setAppliedLSN(stream.getLastReceiveLSN());
            stream.setFlushedLSN(stream.getLastReceiveLSN());
        }
    } catch (final SQLException e1) {
        Logger.getLogger(getClass()).error(e1);

        if (stream != null) {
            try {
                stream.close();
            } catch (final SQLException e2) {
                Logger.getLogger(getClass()).error(e2);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (final SQLException e2) {
                Logger.getLogger(getClass()).error(e2);
            }
        }
    }
}

我注释掉了解析消息并将其转发给 MQ 代理的逻辑,因为没有这个也会发生内存不足。

我还尝试通过使用轮询方法 readPending() 而不是阻塞方法 read() 来更改此示例(如 https://jdbc.postgresql.org/documentation/head/replication.html 所示),但是问题依然存在。

我还注意到,一段时间后,应用程序的 CPU 使用率达到 100%。这一定是由底层库引起的,因为 read() 在那一刻仍在正常处理(即,它按顺序处理每个 WAL 事件)。

在这些测试期间,我以低速率执行 INSERTUPDATE 查询。

我正在使用以下依赖项:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.1.4</version>
</dependency>

应用程序在 Tomcat8 容器中作为 WAR 运行。

知道发生了什么吗?

更新 1

我知道发生了什么,但目前无法解释。我会详细介绍。

如前所述,我每 10 秒执行一次INSERTUPDATE 查询。这些查询导致 645 个 WAL 事件。所以每 10 秒,我必须 read() 645 个事件。一开始,read() 一个事件需要 0(有时是 1)毫秒。一段时间后,需要 1 毫秒。然后,一段时间后,又需要 2 毫秒。等等……

所以过了一段时间,我无法在 10 秒内 read() 645 个事件,因为 read() 所需的时间不断增加。这解释了 100% 的 CPU 使用率和内存不足。

我仍然不确定如何解释以及如何解决这个问题。我会继续调查。

更新 2

我尝试在循环末尾添加 buffer.clear(),但没有成功。我仍然遇到 100% CPU 和内存问题。这是预期的,因为缓冲区是一个局部变量,所以它在每次循环后都会被 GC 处理。但我认为无论如何都要进行测试是个好主意。

最佳答案

我找到了内存不足的原因。我正在使用 decoderbufs 解码输出插件进行测试,https://github.com/xstevens/decoderbufs .当替换为内置的 test 插件或 wal2json ( https://github.com/eulerto/wal2json ) 时,我没有遇到这些问题。

我会尽量通知decoderbufs插件的作者。

关于java - Postgres/JDBC/逻辑复制 - 内存不足问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46234423/

相关文章:

sql - 无循环依赖的依赖树的PostgreSQL设计

Postgresql:在数字开始之前提取文本

java - 如果有多行可用,如何通过列标题区分行名称

java - JClouds:BlobStore.getBlob() 需要很长时间

java - 为什么在调用 onDestroy() 时服务不停止

c++ - 如何在VS2015中使用PostgreSQL插件静态编译Qt 5.8

java - 线程中的异常 "main"java.lang.ClassNotFoundException : oracle. jdbc.OracleDriver Jdbctype4test.Type4test.main(Type4test.java:21)

sql-server - 带有包含空格的数据库的 JDBC url

java - 如何截取自定义形状的屏幕截图?

java - 与音频服务一起使用时 mContext 类型不匹配