Потоковая передача больших результирующих наборов из реплики RDS postgres read и sqlalchemy преждевременно завершается

Я пытаюсь выполнить большой запрос с использованием SQLAlchemy со следующим кодом на сервере Postgres 9.4 RDS, настроенном как реплика чтения.

    # self.sa_engine is a SQLAlchemy engine
    with self.sa_engine.connect() as conn:
        conn = conn.execution_options(stream_results=True)

        # pd = pandas
        # self.sql = "select * from mylargetable"
        for chunk in  pd.read_sql(self.sql, conn, chunksize=50000):
            # do stuff, write file, etc....

Проблема в том, что я получаю следующую ошибку примерно через 30-60 секунд. В течение этого времени файлы пишутся как положено.

TransactionRollbackError: terminating connection due to conflict with recovery
DETAIL:  User query might have needed to see row versions that must be removed.

Все, что я гуглил, говорит об установке следующих параметров в реплике чтения в RDS:

hot_standby_feedback=1
max_standby_archive_delay=600000
max_standby_streaming_delay=600000

С этими параметрами я бы ожидал получить вышеуказанную ошибку, только если запрос выполнялся дольше 10 минут, но я получаю его через 30-60 секунд.

Кроме того, я понимаю, что эта проблема возникает только в том случае, если таблица в базе данных master была изменена во время выполнения запроса к реплике. Однако эта таблица не обновлялась месяцами.

Все это работает, когда я запускаю его для основной базы данных (что я не могу сделать в производственной среде) и когда я запускаю его для небольших таблиц в реплике чтения.

Я в полном недоумении и буду признателен за любую помощь.

2 ответа

Сразу после того, как я задал этот вопрос, я искал параметры, которые были установлены на 30 секунд по умолчанию, и нашел решение. Есть еще один параметр, который мне пришлось настроить:

wal_receiver_timeout=600000

Установка, которая сделала свое дело!

Если по какой-либо причине у вас нет доступа для изменения конфигурации базы данных и / или если это не помогает. Полностью исправление на стороне клиента может быть:

С использованием isolation_level="REPEATABLE_READ"

      my_engine = sqlalchemy.create_engine(f"{my_db_url}", isolation_level="REPEATABLE_READ")

Это также предлагается в теме: https://www.postgresql.org/message-id/7F74C5EA-6741-44FC-B6C6-E96F18D761FB@simply.name

Это «исправление», конечно, следует использовать со знанием уровней изоляции: https://www.postgresql.org/docs/14/transaction-iso.html .

Другие вопросы по тегам