Нагрузочное тестирование Django+Gunicorn[gevent] с использованием Locust
Изначально был следующий сетап nginx
+gunicorn[gevent] 33 workers
+django3
+psycopg2
+postgresql
.
В ходе проведения нагрузочного тестирования при помощи locust
возник ряд трудностей, в результате решения которых я пришел к следующему сетапу: nginx
+gunicorn[gevent] 73 workers
+ django3
+ psycopg2, пропатченный при помощи psycogreen
+ pgbouncer с параметром pool_size=200
+ postgresqsl
. Django общается с pgbouncer при помощи unix-сокета (иначе не хватало TCP-портов, параметр ядра net.ipv4.ip_local_port_range).
На данном этапе при нагрузке, начиная с ~17к locust-пользователей при ~250 RPS начинают сыпаться ошибки в locust:
- RemoteDisconnected('Remote end closed connection without response')
- ConnectionResetError(104, 'Connection reset by peer')
- HTTPError('502 Server Error: Bad Gateway')
- HTTPError('500 Server Error: Internal Server Error for url) - Возникает из-за ошибки, описанной ниже
В логах gunicorn вылетают ошибки GreenletExit, связанные с:
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/django/db/backends/postgresql/base.py", line 277, in _set_autocommit
self.connection.autocommit = autocommit
psycopg2.InterfaceError: connection already closed
А также:
connection to server on socket "/pgbouncer_stuff/postgresql/.s.PGSQL.6432" failed: Resource temporarily unavailable
Is the server running locally and accepting connections on that socket?
Помимо этого есть непонятное предупреждение от gunicorn'а: IGNORING EPIPE
Отсюда возникают следующие вопросы:
- Как интерпретировать описанные результаты (при том, что серверы приложения и базы не нагружены на 100%)?
- Что есть норма, то есть как должны соответствовать RPS и количество пользователей, ведь один пользователь может делать 1 запрос в минуту, а другой 50 запросов?
Конфигурация сервера приложений: 24 ядра, 32 ГБ RAM
Конфигурация сервера БД: 24 ядра, 16 ГБ RAM, postgresql.conf модифицирован согласно https://pgtune.leopard.in.ua/