Pymemcache OSError: [Errno 99] Невозможно присвоить запрашиваемый адрес
Контекст:
У нас есть приложение django, запущенное в контейнере на нашем облачном инстансе. Недавно мы начали видеть ошибки, когда пытаемся получить доступ к значению из кэша django в конечной точке api.
cache.get('key')
К этой конечной точке api очень часто обращаются наши пользователи.
Полная версия ошибки, которую мы видим, прикреплена ниже.
Трассировка ошибки
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/srv/www/iridize/tipcms/views.py", line 2141, in cross_app_new
cache_value = cache.get(cache_key, {})
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/cache/backends/memcached.py", line 75, in get
return self._cache.get(key, default)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/hash.py", line 347, in get
return self._run_cmd("get", key, default, default=default, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/hash.py", line 322, in _run_cmd
return self._safely_run_func(client, func, default_val, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/hash.py", line 211, in _safely_run_func
result = func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/base.py", line 1494, in get
return client.get(key, default)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/base.py", line 687, in get
return self._fetch_cmd(b"get", [key], False, key_prefix=self.key_prefix).get(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/base.py", line 1133, in _fetch_cmd
self._connect()
File "/usr/local/lib/python3.11/site-packages/pymemcache/client/base.py", line 424, in _connect
sock.connect(sockaddr)
OSError: [Errno 99] Cannot assign requested address
Мы используем memcached для кэширования, и наш конфиг кэша в django выглядит следующим образом.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': os.environ.get('MEMCACHE_SERVICE', '127.0.0.1:11211'),
'OPTIONS': {
"use_pooling": True
}
}
}
Мой коллега заподозрил, что у нас в капсуле могут быть не открыты порты, и провел небольшое расследование
Это можно легко проверить, подсчитав занятые порты в стручке с помощью:
cat /proc/net/tcp|wc -l В pods мы наблюдали 25k занятых портов или даже больше, когда максимальное количество портов составляет около 30k.
Также более конкретная команда ищет номер порта memcache (11211 = hex 2BCB) может быть выполнена с помощью этого, Также добавлен фильтр 03:, который учитывает только не освобожденные порты (они не заняты больше не заняты, но WAIT_TIME все еще в процессе, поэтому они еще не освобождены)
cat /proc/net/tcp|grep 2BCB|grep « 03:»|wc -l
Некоторый контекст относительно вышеприведенного блока: Если мы пытаемся выполнить на нашем сервере несколько сотен запросов, количество портов, связанных с memcached, продолжает расти.
Вопрос:
Почему pymemcached открывает новое соединение для каждого запроса cache.get, поскольку на наш сервер поступает огромное количество запросов, у нас заканчиваются порты, так как соединения открываются очень часто. Мы подумали, что pymemcached открывает несколько соединений и использует их повторно вместо того, чтобы каждый раз открывать новые соединения. Мы пытались контролировать это с помощью параметров max_pool_size, pool_idle_timeout, где параметр timeout, имеющий значение 0, не должен отбрасывать соединения, и мы предполагали, что произойдет некоторое повторное использование соединений, но этого не происходит doc link: https://pymemcache.readthedocs.io/en/latest/apidoc/pymemcache.client.hash.html, но все еще не удается предотвратить множество соединений, открытых pymemcached.
Версии программного обеспечения: Django==4.2.15 pymemcache==4.0.0