Случайные отключения баз данных с Django и Postgresql в AWS

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

Небольшая предыстория - я использую этот стек, развернутый в AWS в течение многих лет без проблем:

  • Ubuntu (в данном случае 20.04 LTS)
  • Nginx
  • Uwsgi
  • Postgresql (v12 в RDS - пробовали v13, но те же ошибки)

Балансировщик нагрузки AWS направляет трафик на экземпляр Ubuntu, который обрабатывается Nginx, который перенаправляет его на Django (3.2.6), работающий в Uwsgi. Django подключается к базе данных с помощью psycopg2 (2.9.1). Обычно эта установка работает идеально для меня

Проблема, с которой я столкнулся, заключается в том, что соединение с базой данных, похоже, закрывается случайным образом. Django сообщает об ошибках, подобных этой:

Traceback (most recent call last):
  [my code...]
    for answer in q.select_related('entry__session__player'):
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/query.py", line 280, in __iter__
    self._fetch_all()
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/query.py", line 1324, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/query.py", line 51, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/sql/compiler.py", line 1173, in execute_sql
    cursor = self.connection.cursor()
  File "/usr/local/lib/python3.8/dist-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/base/base.py", line 259, in cursor
    return self._cursor()
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/base/base.py", line 237, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/usr/local/lib/python3.8/dist-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/base/base.py", line 237, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/usr/local/lib/python3.8/dist-packages/django/utils/asyncio.py", line 26, in inner
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/postgresql/base.py", line 236, in create_cursor
    cursor = self.connection.cursor()
django.db.utils.InterfaceError: connection already closed

Место в моем коде может быть разным. Иногда (реже) я получаю и это:

Traceback (most recent call last):
  [my code...]
    group = contest.groups.create(restaurant = restaurant, supergroup = supergroup)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/fields/related_descriptors.py", line 677, in create
    return super(RelatedManager, self.db_manager(db)).create(**kwargs)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/query.py", line 453, in create
    obj.save(force_insert=True, using=self.db)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/base.py", line 726, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/base.py", line 763, in save_base
    updated = self._save_table(
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/base.py", line 868, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/base.py", line 906, in _do_insert
    return manager._insert(
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/query.py", line 1270, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/usr/local/lib/python3.8/dist-packages/django/db/models/sql/compiler.py", line 1416, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/utils.py", line 78, in _execute
    self.db.validate_no_broken_transaction()
  File "/usr/local/lib/python3.8/dist-packages/django/db/backends/base/base.py", line 447, in validate_no_broken_transaction
    raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

Опять же, место в моем коде меняется, и это не всегда в простом вызове create - иногда это bulk_create, иногда get_or_create. Я предполагаю, что основная причина, вероятно, та же, что и ошибка 'connection_closed', но я не уверен.

Вот что говорит мне Django. Журнал Postgresql не содержит никаких ошибок, совпадающих по времени с ошибками, о которых сообщает Django. Единственные ошибки в журнале имеют такую форму:

LOG: could not receive data from client: Connection reset by peer

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

Итак, Postgresql не сообщает о соответствующих ошибках - я могу только предположить, что соединение было закрыто должным образом, и Django не ожидал этого. В журнале systemd вообще нет ошибок на экземпляре Ubuntu.

Я не знаю, как действовать дальше. Я сомневаюсь, что это ошибка в Django, но никакой другой компонент в системе не жалуется, и это должно быть проблемой низкого уровня. Это случается довольно редко, но достаточно, чтобы вызывать беспокойство - что-то около 1 из 1000 запросов.

Любые идеи или предложения о том, как исследовать это дальше, будут приняты с благодарностью :)

Вернуться на верх