Потоковая передача больших результирующих наборов из реплики 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 .