PostgreSQL Сбои при выполнении массовых вставок с Node.js / Sequelize - PullRequest
2 голосов
/ 18 января 2020

Приложение Node.js, использующее Sequelize. js ORM выполняет массовые вставки на сервер PostgreSQL 11.2, работающий внутри контейнера Docker в хост-системе Ma c OSX. Каждая массовая вставка обычно состоит из примерно 1000-4000 строк, причем параллельная параллельная вставка составляет 30, поэтому в любое время можно выполнить до 30 активных операций вставки.

const bulkInsert = async (payload) => {
    try {
        await sequelizeModelInstance.bulkCreate(payload);
    } catch (e) {
        console.log(e);
    }
}

pLimit = require('p-limit')(30);

(function() => {
    const promises = data.map(d => pLimit(() => bulkInsert(d))) // pLimit() controls Promise concurrency
    const result = await Promise.all(promises)
})();

Через некоторое время PostgreSQL сервер начнет выдавать ошибки Connection terminated unexpectedly, после чего the database system is in recovery mode.

После повторения этого несколько раз и проверки моих журналов кажется, что эта ошибка обычно возникает при выполнении пакета из 30 массовых вставок, где несколько массовых вставок содержат более 100 000 строк каждая. Например, один конкретный cra sh возникает при попытке сделать 3 массовых вставки по 190000, 650000 и 150000 строк вместе с 27 вставками по 1000-4000 строк каждая.

Системная память не заполнена, загрузка процессора нормально, достаточно места на диске.

Вопрос: Нормально ли ожидать, что PostgreSQL достигнет sh при таких обстоятельствах? Если да, есть ли настройка PostgreSQL, которую мы можем настроить, чтобы разрешить большие объемные вставки? Если это связано с большими объемными вставками, есть ли у Sequelize функция js, позволяющая разделить объемные вставки для нас?

Работа на PostgreSQL 11.2 в контейнере docker, TimescaleDB 1.5.1, узел v12.6.0, продолжение 5.21.3, Ма c Каталина 10.15.2

PostgreSQL Журналы сразу после возникновения проблемы

2020-01-18 00:58:26.094 UTC [1] LOG:  server process (PID 199) was terminated by signal 9
2020-01-18 00:58:26.094 UTC [1] DETAIL:  Failed process was running: INSERT INTO "foo" ("id","opId","unix","side","price","amount","b","s","serverTimestamp") VALUES (89880,'5007564','1579219200961','front','0.0000784','35','undefined','undefined','2020-01-17 00:00:01.038 +00:00'),.........
2020-01-18 00:58:26.108 UTC [1] LOG:  terminating any other active server processes
2020-01-18 00:58:26.110 UTC [220] WARNING:  terminating connection because of crash of another server process
2020-01-18 00:58:26.110 UTC [220] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2020-01-18 00:58:26.110 UTC [220] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2020-01-18 00:58:26.148 UTC [214] WARNING:  terminating connection because of crash of another server process
2020-01-18 00:58:26.148 UTC [214] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2020-01-18 00:58:26.148 UTC [214] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2020-01-18 00:58:26.149 UTC [203] WARNING:  terminating connection because of crash of another server process
2020-01-18 00:58:26.149 UTC [203] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.

...

2020-01-18 00:58:30.098 UTC [1] LOG:  all server processes terminated; reinitializing
2020-01-18 00:58:30.240 UTC [223] FATAL:  the database system is in recovery mode
2020-01-18 00:58:30.241 UTC [222] LOG:  database system was interrupted; last known up at 2020-01-18 00:50:13 UTC
2020-01-18 00:58:30.864 UTC [224] FATAL:  the database system is in recovery mode
2020-01-18 00:58:31.604 UTC [225] FATAL:  the database system is in recovery mode
2020-01-18 00:58:32.297 UTC [226] FATAL:  the database system is in recovery mode
2020-01-18 00:58:32.894 UTC [227] FATAL:  the database system is in recovery mode
2020-01-18 00:58:33.394 UTC [228] FATAL:  the database system is in recovery mode
2020-01-18 01:00:55.911 UTC [222] LOG:  database system was not properly shut down; automatic recovery in progress
2020-01-18 01:00:56.856 UTC [222] LOG:  redo starts at 0/197C610
2020-01-18 01:01:55.662 UTC [229] FATAL:  the database system is in recovery mode

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

У меня была похожая проблема при выполнении миграций, но решение может быть применено к этому вопросу.

Идея состоит в том, чтобы разделить полезную нагрузку на управляемые куски. В моем случае 100 записей одновременно казались управляемыми.

const payload = require("./seeds/big-mama.json"); //around 715.000 records

module.exports = {
    up: (queryInterface) => {
        const records = payload.map(function (record) {
            record.createdAt = new Date();
            record.updatedAt = new Date();
            return record;
        });

        let lastQuery;
        while (records.length > 0) {
            lastQuery = queryInterface.bulkInsert(
                "Products",
                records.splice(0, 100),
                {}
            );
        }

        return lastQuery;
    },

    down: (queryInterface) => {
        return queryInterface.bulkDelete("Products", null, {});
    }
};

1 голос
/ 20 января 2020

Ваш Postgresql сервер, вероятно, погибает от OOM Killer (Out of Memory Killer) из Docker ОС.

Вы можете:

  1. Увеличить память доступно для Postgres, 2 ГБ - это низкое значение для количества выполняемых операций.
  2. Уменьшите размер групповых вставок и ограничьте их параллелизм.
  3. Настройте установку Postgres для соответствия ваше оборудование:
    • shared_buffers: здесь рекомендуется должно занимать 25% памяти в вашей системе, это рекомендация, вы всегда должны тестировать и оценивать свой сценарий и выбирать значения, которые кажутся подходящими для вашей среды.
    • work_mem: Как объяснено здесь :

Этот размер применяется к каждой сортировке, выполняемой каждым пользователем, и сложные запросы могут использовать несколько буферов сортировки рабочей памяти. Установите 50 МБ, и 30 пользователей будут отправлять запросы, и вы скоро используете 1,5 ГБ реальной памяти. Кроме того, если запрос включает в себя слияние 8 таблиц, для этого требуется 8 раз work_mem. Вы должны рассмотреть, что вы установили max_connections, чтобы правильно определить размер этого параметра. Это параметр, в котором системы хранилища данных, где пользователи отправляют очень большие запросы, могут легко использовать много гигабайт памяти.

Существует множество конфигураций, которые вы можете изменить на своем Postgres чтобы улучшить производительность и стабильность. Postgres будет прекрасно работать с настройками по умолчанию, но в производственных средах или в средах с большой нагрузкой вам придется его настраивать неизбежно.

Рекомендуемые значения:

  1. Настройка вашей PostgreSQL системы
  2. PostgreSQL Документация: потребление ресурсов
  3. Настройка памяти на PostgreSQL
...