Error errno 99 cannot assign requested address

My server software says errno99: cannot assign requested address while using an ip address other than 127.0.0.1 for binding. But if the IP address is 127.0.0.1 it works. Is it related to namespace...

This error will also appear if you try to connect to an exposed port from within a Docker container, when nothing is actively serving the port.

On a host where nothing is listening/bound to that port you’d get a No connection could be made because the target machine actively refused it error instead when making a request to a local URL that is not served, eg: localhost:5000. However, if you start a container that binds to the port, but there is no server running inside of it actually serving the port, any requests to that port on localhost will result in:

  • [Errno 99] Cannot assign requested address (if called from within the container), or
  • [Errno 0] Error (if called from outside of the container).

You can reproduce this error and the behaviour described above as follows:

Start a dummy container (note: this will pull the python image if not found locally):

docker run --name serv1 -p 5000:5000 -dit python

Then for [Errno 0] Error enter a Python console on host, while for [Errno 99] Cannot assign requested address access a Python console on the container by calling:

docker exec -it -u 0 serv1 python

And then in either case call:

import urllib.request
urllib.request.urlopen('https://localhost:5000')

I concluded with treating either of these errors as equivalent to No connection could be made because the target machine actively refused it rather than trying to fix their cause — although please advise if that’s a bad idea.


I’ve spent over a day figuring this one out, given that all resources and answers I could find on the [Errno 99] Cannot assign requested address point in the direction of binding to an occupied port, connecting to an invalid IP, sysctl conflicts, docker network issues, TIME_WAIT being incorrect, and many more things. Therefore I wanted to leave this answer here, despite not being a direct answer to the question at hand, given that it can be a common cause for the error described in this question.

Problem:

When binding a socket, you see an error message like

Traceback (most recent call last):
  File "run.py", line 91, in <module>
    server = start_server(loop, ('192.168.1.100', 8080))
  File "run.py", line 86, in start_server
    transport, server = loop.run_until_complete(t)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1332, in create_datagram_endpoint
    raise exceptions[0]
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1316, in create_datagram_endpoint
    sock.bind(local_address)
OSError: [Errno 99] Cannot assign requested address

Solution:

In my case, the issue was that I was trying to bind the specific IP address 192.168.1.100 but the computer running the script did not have said IP address configured on any interface.

server = start_server(loop, ('192.168.1.100', 8080))

so I needed to change the bind IP address to either 0.0.0.0 to listen to ANY IP address or I needed to change 192.168.1.100 to the IP address of the host computer I am running the script on.

Docker container [Errno 99] Cannot assign requested address

Note that for Docker containers, either you need to run them in network_mode: host to use the host’s network systemd, or you need to bind to the container’s IP address. You can not bind to the host’s IP address from the contaienr unless using network_mode: host! But you can forward the ports from the host, binding to a specific IP address.

Содержание

  1. Nginx 99: Cannot assign requested address to upstream
  2. Введение
  3. Причины возникновения
  4. Диагностирование
  5. Решение
  6. Тюнинг ядра
  7. Изменение адреса назначения
  8. Настройка keepalive
  9. Тюнинг ядра. Ещё раз [2]
  10. Заключение
  11. Получаю ошибку OSError: [Errno 99] Cannot assign requested address
  12. Антон
  13. Socket Error 99 for ipython notebook #6193
  14. Comments
  15. Errno 99 Cannot assign requested address when running scapy in namespace #938
  16. Comments

Nginx 99: Cannot assign requested address to upstream

Введение

В данной статье описаны причины возникновения и решения проблемы с Nginx, когда периодически возникает ошибка вида [crit] 12889#0: *32401195 connect() to 127.0.0.1:80 failed (99: Cannot assign requested address) while connecting to upstream.

В моем случае сложности добавляло следующее: используется Nginx Ingress Controller в kubernetes, был установлен сложный релиз с множеством нового функционала и маршрутизацией для микросервисов. Поэтому было не сразу понятно, в чем проблема и куда смотреть, и прежде чем я пришёл к решению проблемы, было перелопачено много access-логов и конфигов в k8s, т.к. основными симптомами являлись периодические 502 ошибки в одной из частей приложения, а основная часть работала без проблем.

Причины возникновения

Перед тем, как рассказать о решении проблемы, необходимо иметь минимальный багаж знаний о работе TCP. В частности, как происходит сеанс установки TCP-соединения (в данной статье описывается лишь частично в рамках исследуемой проблемы):

  • На стороне клиента создается сокет
  • По аналогии сокет создается и на сервере, к которому обращается клиент
  • Оба сокета соединяются для создания пары сокетов, которая называется quadruplet
  • quadruplet состоит из локального IP-адреса и порта, а также удаленного IP-адреса и порта клиента. В RFC quadruplet описывается так: и по сути представляет собой кортеж из значений IP и портов.

Чтобы сразу понимать, как это выглядит в Linux, можно запустить команду netstat или ss для просмотра сетевых соединений на порту, который прослушивает Nginx:

Из команды выше адрес 10.89.108.137 – клиент, а 1879 – порт, связанный с клиентом только на время соединения и поэтому называется эфемерным . Когда соединение будет разорвано, временный порт будет доступен для повторного использования уже в рамках другого соединения.

Клиентский порт назначается автоматически из определенного диапазона, который указан в ядре по пути:

По умолчанию размер диапазона составляет 60999-32768=28231 (в моем случае на RHEL 7), что не так уж и много для высоконагруженных систем с большим количеством клиентов.

Диагностирование

Итак, определившись с текущим объемом ip_local_port_range – 28231, необходимо диагностировать, сколько соединений используется. Для этого можно воспользоваться также netstat или ss:

В примере выше, общее кол-во соединений составляет 47773. Соединений в состоянии established не так и много, а вот на соединения timewait стоит обратить внимание, т.к. они являются активными потребителями диапазона в данном случае (к тому же их кол-во постоянно меняется). Можно сразу смотреть их кол-во без лишнего вывода:

netstat в моём случае отработал быстрее, а ss с ощутимой задержкой

И вот она проблема – почти 37 тысяч соединений, а в лимите разрешено всего 28231. У такой проблемы есть даже название “Ephemeral Port Exhaustion”, т.е. эфемерное истощение портов, если перевести дословно.

Решение

Тюнинг ядра

Первым делом можно сразу же увеличить лимит по умолчанию – это будет самым простым и верным решением. Для этого:

Главное помнить, что лимит не резиновый и не стоит ставить меньше 4096 (порты для системных нужд) и выше 65000 + на различных портах могут слушать различные демоны прикладного ПО. Я выставил 49000 для начала. Хотя допустимо минимальным значением диапазона выставить 1024, но нужно помнить, что могут быть проблемы с другими службами и фаерволом, если сделать бездумно.

Изменение адреса назначения

Помните, что каждое соединение состоит из 4 частей (называемых quadruplet) с исходным IP и исходным портом, целевым IP и целевым портом? Так вот если нет возможности изменить исходный порт или IP-адрес, можно изменить IP-адреса назначения и тем самым избежать ограничений по лимиту из ip_local_port_range.

Наглядно это будет выглядеть так: например, конечный endpoint слушает на всех портах сетевых интерфейсов, т.е. на 0.0.0.0. А значит к нему можно обратиться по разным адресам – локальному, внешнему, loopback или добавить алиасы на интерфейс. Для этого создается апстрим с именем backend:

И далее можно проксировать трафик в вышеописанный upstream:

Тем самым будет достигнута экономия локальных портов из диапазона ip_local_port_range, т.к. вместо одного адреса уже будет два или более – в зависимости от настроек.

Настройка keepalive

Есть ещё одно решение – это настройка keepalive между Nginx и серверами в upstream. Keepalive-соединение будет поддерживаться открытым, а потому его можно использовать повторно уже другими клиентами, не создавая новых и опять же не расходуя лимиты ip_local_port_range.

Для настройки нужно указать директиву keepalive и её значение в блоке upstream:

При использовании keepalive, необходимо также использовать следующие директивы:
proxy_http_version 1.1;
proxy_set_header Connection «»;
И учитывать, что для протокола WebSocket это может быть критично.

Тюнинг ядра. Ещё раз [2]

После того, как лимиты в ip_local_port_range увеличены, количество соединений всё равно может увеличиваться. Особенно это актуально для веб-сервера, к которому происходят множественные обращения. Как правило, основным потребителем являются соединения в состоянии TIME_WAIT, и занимают большую часть диапазона ip_local_port_range. В таком случае ошибка Cannot assign requested address может снова повториться.

Сгладить ситуацию поможет параметр ядра net.ipv4.tcp_tw_reuse=1. Как видно из названия, он позволяет использовать повторно соединения TW, не создавая новых. Проблем с применением этого параметра на работающем сервере быть не должно.

Есть также другой параметр tcp_tw_recycle, который позволяет сократить время нахождения соединения в TIME-WAIT, но известно, что при его использовании могут быть проблемы у клиентов за NAT. Не рекомендуется использовать данный параметр, а в новых версиях ядра он вообще удален.

Заключение

В итоге получилось, что для решения ошибки Nginx Cannot assign requested address while connecting to upstream можно использовать целый комплекс мер – увеличить лимиты в ядре, настроить keepalive и сконфигурировать upstream. Но также не стоит забывать, что нужно искать проблему не там, где кажется на первый взгляд, т.к. могут получаться такие совпадения, связанные с выкаткой нового функционала. Грешил на одно, а проблема оказалась в итоге совсем в другом месте. В идеале же нужно применять всё в зависимости от ситуации, а также не могу не упомянуть про мониторинг.

В моем случае после решения данной проблемы, я настроил в Zabbix простой мониторинг кол-ва TCP-соединений через netstat -nt для 80 и 443 на нужном мне порту, где запущен Nginx Ingress Controller, чтобы понимать динамику загрузки и оперативно принять меры.

Для более глубокого понимания проблемы рекомендую изучить ссылки в используемых источниках ниже, особенно из блога Nginx.

Источник

Получаю ошибку OSError: [Errno 99] Cannot assign requested address

Антон

Новичок

ОС Ubuntu
Среда anaconda/spyder/ Python 3.8

При запуске выдает ошибку:

runfile(‘/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py’, wdir=’/home/anton/Загрузки/AutoRCCar-master/test’)
Traceback (most recent call last):

File «/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py», line 50, in
VideoStreamingTest(h, p)

File «/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py», line 12, in __init__
self.server_socket.bind((host, port))

OSError: [Errno 99] Cannot assign requested address

import numpy as np
import cv2
import socket

class VideoStreamingTest(object):
def __init__(self, host, port):

self.server_socket = socket.socket()
self.server_socket.bind((host, port))
self.server_socket.listen(0)
self.connection, self.client_address = self.server_socket.accept()
self.connection = self.connection.makefile(‘rb’)
self.host_name = socket.gethostname()
self.host_ip = socket.gethostbyname(self.host_name)
self.streaming()

try:
print(«Host: «, self.host_name + ‘ ‘ + self.host_ip)
print(«Connection from: «, self.client_address)
print(«Streaming. «)
print(«Press ‘q’ to exit»)

# need bytes here
stream_bytes = b’ ‘
while True:
stream_bytes += self.connection.read(1024)
first = stream_bytes.find(b’xffxd8′)
last = stream_bytes.find(b’xffxd9′)
if first != -1 and last != -1:
jpg = stream_bytes[first:last + 2]
stream_bytes = stream_bytes[last + 2:]
image = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow(‘image’, image)

if cv2.waitKey(1) & 0xFF == ord(‘q’):
break
finally:
self.connection.close()
self.server_socket.close()

if __name__ == ‘__main__’:
# host, port
h, p = «192.168.1.100», 8000
VideoStreamingTest(h, p)

Источник

Socket Error 99 for ipython notebook #6193

Hi
when trying to open a notebook I get a socket error 99 «Cannot assign requested address». This happened after a system update, although Ipython was updated only from 2.1.0-62 to 2.1.0-63 (SuSE package) I checked the following without any sucess:

  1. checked if loopback device is running (it is with inet addr:127.0.0.1 Mask:255.0.0.0)
  2. checked with netstat -lp if standard port is already assigned (it was not)
  3. run a small test script to start tornado web server at port 8888, it worked
  4. Create a default profile and run ipython again
  5. Started ipython with explicit host and (random) port (ipython notebook —init —ip=’localhost’ —port=49151)
  6. Tried is as root
  7. Checked that the firewall is not blocking
  8. Checked that I am able to write to tmp (in case that is needed)

So I am at a loss what else I can do. Any pointer on what else I can do are appreciated.

The start-up message is
tmp/> ipython notebook —init —log-level=50 —ip=’localhost’ —port=49151 [15:46:39]
Traceback (most recent call last):
File «/usr/bin/ipython», line 5, in
start_ipython()
File «/usr/lib/python2.7/site-packages/IPython/init.py», line 120, in start_ipython
return launch_new_instance(argv=argv, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 563, in launch_instance
app.initialize(argv)
File «», line 2, in initialize
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 92, in catch_config_error
return method(app, *args, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/terminal/ipapp.py», line 320, in initialize
super(TerminalIPythonApp, self).initialize(argv)
File «», line 2, in initialize
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 92, in catch_config_error
return method(app, _args, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/core/application.py», line 381, in initialize
self.parse_command_line(argv)
File «/usr/lib/python2.7/site-packages/IPython/terminal/ipapp.py», line 315, in parse_command_line
return super(TerminalIPythonApp, self).parse_command_line(argv)
File «», line 2, in parse_command_line
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 92, in catch_config_error
return method(app, _args, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 475, in parse_command_line
return self.initialize_subcommand(subc, subargv)
File «», line 2, in initialize_subcommand
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 92, in catch_config_error
return method(app, _args, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 413, in initialize_subcommand
self.subapp.initialize(argv)
File «», line 2, in initialize
File «/usr/lib/python2.7/site-packages/IPython/config/application.py», line 92, in catch_config_error
return method(app, _args, *_kwargs)
File «/usr/lib/python2.7/site-packages/IPython/html/notebookapp.py», line 745, in initialize
self.init_webapp()
File «/usr/lib/python2.7/site-packages/IPython/html/notebookapp.py», line 632, in init_webapp
self.http_server.listen(port, self.ip)
File «/usr/lib64/python2.7/site-packages/tornado/tcpserver.py», line 116, in listen
sockets = bind_sockets(port, address=address)
File «/usr/lib64/python2.7/site-packages/tornado/netutil.py», line 103, in bind_sockets
sock.bind(sockaddr)
File «/usr/lib64/python2.7/socket.py», line 224, in meth
return getattr(self._sock,name)(*args)
error: [Errno 99] Cannot assign requested address

My system configuration is
<‘commit_hash’: ‘681fd77’,
‘commit_source’: ‘installation’,
‘default_encoding’: ‘UTF-8’,
‘ipython_path’: ‘/usr/lib/python2.7/site-packages/IPython’,
‘ipython_version’: ‘2.1.0’,
‘os_name’: ‘posix’,
‘platform’: ‘Linux-3.11.10-17-default-x86_64-with-SuSE-13.1-x86_64’,
‘sys_executable’: ‘/usr/bin/python’,
‘sys_platform’: ‘linux2’,
‘sys_version’: ‘2.7.6 (default, Nov 21 2013, 15:55:38) [GCC]’>

My tornado version is
Name: python-tornado/Version: 3.2.1-2.1/Arch: x86_64

The text was updated successfully, but these errors were encountered:

Источник

Errno 99 Cannot assign requested address when running scapy in namespace #938

I’m trying to run a simple scapy application (test.py) that sends an ICMP packet.

I run this command in a network namespace, as follows:

ip netns exec nic_1_ns python test.py

And get the following error:

Details of the namespace ip configuration is:

I’m using:
Python 2.7.5
scapy (2.3.3)
CentOS 7.3

If I run the command outside the namespace, the code works fine.
It seems that ioctl command is failing and it can’t bind to the loopback IP address. Ideally, it should try to run this command within the namespace itself. Is there any configuration file where I can add this namespace specific info? Is there any workaround for this or does scapy not have support to work within network namespaces?

The text was updated successfully, but these errors were encountered:

try to set the loopback device up before calling your script:

(it was not shown in the output of your call to ifconfig and that indicates the interface is down. you can force non active interfaces to show up by appending option -a —or— use ip link to get the list & state of all your interfaces)

After enabling the loopback interface, I can see that the program outputs «Sent 1 packet». However, this packet isn’t actually being sent across the network (didnt show up in the wire shark capture).

Why does the loop back interface need to be up and running for this to work anyway? It doesn’t make sense to me. Could you please elaborate?

After enabling the loopback interface, I can see that the program outputs «Sent 1 packet». However, this packet isn’t actually being sent across the network (didnt show up in the wire shark capture).

as you run the script in a namespace I guess there is no route available. what is the output of

(there is usually no default route added so you may end up with a single entry to 192.168.121.0/24 — but you try to send the message to a host in another sub net 192.168.251.0/24)

Why does the loop back interface need to be up and running for this to work anyway? It doesn’t make sense to me. Could you please elaborate?

during the bootstrap of Scapy a table containing all available routes is created. this table also includes the loopback device — the error message will guide you to the relevant piece of code:

if the loopback was never up before no address (usually 127.0.0.1) was assigned. SIOCGIFADDR tries to return an INET address and will fail if no address is available. therefore the ioctl fails if the namespace was created without bringing up the loopback.

Источник

Hi there,

I just started using Codenvy. I wanted to run jupyter notebook (http://jupyter.org) but it gave me the following error:

It could be that I am just not getting the concept right, I’m completely new to this program. If that’s the case, please point me in the right direction 👍

Thanks!

Traceback (most recent call last):                                                                                                                                                                                            
  File "/usr/local/bin/jupyter-notebook", line 11, in <module>                                                                                                                                                                
    sys.exit(main())                                                                                                                                                                                                          
  File "/usr/local/lib/python3.4/dist-packages/jupyter_core/application.py", line 267, in launch_instance                                                                                                                     
    return super(JupyterApp, cls).launch_instance(argv=argv, **kwargs)                                                                                                                                                        
  File "/usr/local/lib/python3.4/dist-packages/traitlets/config/application.py", line 657, in launch_instance                                                                                                                 
    app.initialize(argv)                                                                                                                                                                                                      
  File "<decorator-gen-7>", line 2, in initialize                                                                                                                                                                             
  File "/usr/local/lib/python3.4/dist-packages/traitlets/config/application.py", line 87, in catch_config_error                                                                                                               
    return method(app, *args, **kwargs)                                                                                                                                                                                       
  File "/usr/local/lib/python3.4/dist-packages/notebook/notebookapp.py", line 1296, in initialize                                                                                                                             
    self.init_webapp()                                                                                                                                                                                                        
  File "/usr/local/lib/python3.4/dist-packages/notebook/notebookapp.py", line 1120, in init_webapp                                                                                                                            
    self.http_server.listen(port, self.ip)                                                                                                                                                                                    
  File "/usr/local/lib/python3.4/dist-packages/tornado/tcpserver.py", line 142, in listen                                                                                                                                     
    sockets = bind_sockets(port, address=address)                                                                                                                                                                             
  File "/usr/local/lib/python3.4/dist-packages/tornado/netutil.py", line 197, in bind_sockets                                                                                                                                 
    sock.bind(sockaddr)                                                                                                                                                                                                       
OSError: [Errno 99] Cannot assign requested address 

Reproduction Steps:

  • Create a new workspace
  • Select ubuntu(latest) as OS
  • When inside the IDE, do:
sudo apt update
sudo apt install python3-pip
sudo pip3 install -vU setuptools
sudo pip3 install jupyter
jupyter notebook

Codenvy version: 5.17.0

OS and version: Not sure (it’s on codenvy.io, no self-hosted)

Docker version: Also not sure

Codenvy cli.log output: N/a

ОС Ubuntu
Среда anaconda/spyder/ Python 3.8

При запуске выдает ошибку:

runfile(‘/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py’, wdir=’/home/anton/Загрузки/AutoRCCar-master/test’)
Traceback (most recent call last):

File «/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py», line 50, in <module>
VideoStreamingTest(h, p)

File «/home/anton/Загрузки/AutoRCCar-master/test/stream_server_test.py», line 12, in __init__
self.server_socket.bind((host, port))

OSError: [Errno 99] Cannot assign requested address

Сам текст кода:

__author__ = ‘zhengwang’

import numpy as np
import cv2
import socket

class VideoStreamingTest(object):
def __init__(self, host, port):

self.server_socket = socket.socket()
self.server_socket.bind((host, port))
self.server_socket.listen(0)
self.connection, self.client_address = self.server_socket.accept()
self.connection = self.connection.makefile(‘rb’)
self.host_name = socket.gethostname()
self.host_ip = socket.gethostbyname(self.host_name)
self.streaming()

def streaming(self):

try:
print(«Host: «, self.host_name + ‘ ‘ + self.host_ip)
print(«Connection from: «, self.client_address)
print(«Streaming…»)
print(«Press ‘q’ to exit»)

# need bytes here
stream_bytes = b’ ‘
while True:
stream_bytes += self.connection.read(1024)
first = stream_bytes.find(b’xffxd8′)
last = stream_bytes.find(b’xffxd9′)
if first != -1 and last != -1:
jpg = stream_bytes[first:last + 2]
stream_bytes = stream_bytes[last + 2:]
image = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow(‘image’, image)

if cv2.waitKey(1) & 0xFF == ord(‘q’):
break
finally:
self.connection.close()
self.server_socket.close()

if __name__ == ‘__main__’:
# host, port
h, p = «192.168.1.100», 8000
VideoStreamingTest(h, p)

Содержание

  1. Введение
  2. Причины возникновения
  3. Диагностирование
  4. Решение
  5. Тюнинг ядра
  6. Изменение адреса назначения
  7. Настройка keepalive
  8. Тюнинг ядра. Ещё раз [2]
  9. Заключение
  10. Используемые источники

Введение

В данной статье описаны причины возникновения и решения проблемы с Nginx, когда периодически возникает ошибка вида [crit] 12889#0: *32401195 connect() to 127.0.0.1:80 failed (99: Cannot assign requested address) while connecting to upstream.

В моем случае сложности добавляло следующее: используется Nginx Ingress Controller в kubernetes, был установлен сложный релиз с множеством нового функционала и маршрутизацией для микросервисов. Поэтому было не сразу понятно, в чем проблема и куда смотреть, и прежде чем я пришёл к решению проблемы, было перелопачено много access-логов и конфигов в k8s, т.к. основными симптомами являлись периодические 502 ошибки в одной из частей приложения, а основная часть работала без проблем.

Причины возникновения

Перед тем, как рассказать о решении проблемы, необходимо иметь минимальный багаж знаний о работе TCP. В частности, как происходит сеанс установки TCP-соединения (в данной статье описывается лишь частично в рамках исследуемой проблемы):

  • На стороне клиента создается сокет
  • По аналогии сокет создается и на сервере, к которому обращается клиент
  • Оба сокета соединяются для создания пары сокетов, которая называется quadruplet
  • quadruplet состоит из локального IP-адреса и порта, а также удаленного IP-адреса и порта клиента. В RFC quadruplet описывается так: {A, B, Port.A, Port.B} и по сути представляет собой кортеж из значений IP и портов.

Чтобы сразу понимать, как это выглядит в Linux, можно запустить команду netstat или ss для просмотра сетевых соединений на порту, который прослушивает Nginx:

# netstat -nt | grep ":443 " | grep EST

tcp        0      0 10.89.108.182:443       10.89.108.137:1879      ESTABLISHED

Из команды выше адрес 10.89.108.137 – клиент, а 1879 – порт, связанный с клиентом только на время соединения и поэтому называется эфемерным . Когда соединение будет разорвано, временный порт будет доступен для повторного использования уже в рамках другого соединения.

Клиентский порт назначается автоматически из определенного диапазона, который указан в ядре по пути:

# cat /proc/sys/net/ipv4/ip_local_port_range

32768	60999

По умолчанию размер диапазона составляет 60999-32768=28231 (в моем случае на RHEL 7), что не так уж и много для высоконагруженных систем с большим количеством клиентов.

Диагностирование

Итак, определившись с текущим объемом ip_local_port_range – 28231, необходимо диагностировать, сколько соединений используется. Для этого можно воспользоваться также netstat или ss:

# ss -s
Total: 8253 (kernel 8381)
TCP:   47773 (estab 5439, closed 42021, orphaned 92, synrecv 0, timewait 41675/0), ports 0

Transport Total     IP        IPv6
*         8381      -         -
RAW       0         0         0
UDP       69        18        51
TCP       5752      5705      47
INET      5821      5723      98
FRAG      0         0         0

В примере выше, общее кол-во соединений составляет 47773. Соединений в состоянии established не так и много, а вот на соединения timewait стоит обратить внимание, т.к. они являются активными потребителями диапазона в данном случае (к тому же их кол-во постоянно меняется). Можно сразу смотреть их кол-во без лишнего вывода:

# ss -a | grep TIME-WAIT | wc -l
36169
# netstat -nt | grep WAIT | wc -l
36376

Information

netstat в моём случае отработал быстрее, а ss с ощутимой задержкой

И вот она проблема – почти 37 тысяч соединений, а в лимите разрешено всего 28231. У такой проблемы есть даже название “Ephemeral Port Exhaustion”, т.е. эфемерное истощение портов, если перевести дословно.

Решение

Тюнинг ядра

Первым делом можно сразу же увеличить лимит по умолчанию – это будет самым простым и верным решением. Для этого:

echo "net.ipv4.ip_local_port_range = 15000    64000" >>/etc/sysctl.d/99-sysctl.conf
sysctl -p

Главное помнить, что лимит не резиновый и не стоит ставить меньше 4096 (порты для системных нужд) и выше 65000 + на различных портах могут слушать различные демоны прикладного ПО. Я выставил 49000 для начала. Хотя допустимо минимальным значением диапазона выставить 1024, но нужно помнить, что могут быть проблемы с другими службами и фаерволом, если сделать бездумно.

Изменение адреса назначения

Помните, что каждое соединение состоит из 4 частей (называемых quadruplet) с исходным IP и исходным портом, целевым IP и целевым портом? Так вот если нет возможности изменить исходный порт или IP-адрес, можно изменить IP-адреса назначения и тем самым избежать ограничений по лимиту из ip_local_port_range.

Наглядно это будет выглядеть так: например, конечный endpoint слушает на всех портах сетевых интерфейсов, т.е. на 0.0.0.0. А значит к нему можно обратиться по разным адресам – локальному, внешнему, loopback или добавить алиасы на интерфейс. Для этого создается апстрим с именем backend:

upstream backend {
  server 127.0.0.1:80;
  server 192.168.10.1:80;
  server ${PUBLIC_IP}:80;
}

И далее можно проксировать трафик в вышеописанный upstream:

server {
  listen 443;
  ...
  location / {
    proxy_pass http://backend;
    ...
  }
}

Тем самым будет достигнута экономия локальных портов из диапазона ip_local_port_range, т.к. вместо одного адреса уже будет два или более – в зависимости от настроек.

Настройка keepalive

Есть ещё одно решение – это настройка keepalive между Nginx и серверами в upstream. Keepalive-соединение будет поддерживаться открытым, а потому его можно использовать повторно уже другими клиентами, не создавая новых и опять же не расходуя лимиты ip_local_port_range.

Для настройки нужно указать директиву keepalive и её значение в блоке upstream:

upstream backend {
  server 127.0.0.1:80;
  server 192.168.10.1:80;
  server ${PUBLIC_IP}:80;
  keepalive 128;
}

Warning

При использовании keepalive, необходимо также использовать следующие директивы:
proxy_http_version 1.1;
proxy_set_header Connection "";
И учитывать, что для протокола WebSocket это может быть критично.

Тюнинг ядра. Ещё раз [2]

После того, как лимиты в ip_local_port_range увеличены, количество соединений всё равно может увеличиваться. Особенно это актуально для веб-сервера, к которому происходят множественные обращения. Как правило, основным потребителем являются соединения в состоянии TIME_WAIT, и занимают большую часть диапазона ip_local_port_range. В таком случае ошибка Cannot assign requested address может снова повториться.

Сгладить ситуацию поможет параметр ядра net.ipv4.tcp_tw_reuse=1. Как видно из названия, он позволяет использовать повторно соединения TW, не создавая новых. Проблем с применением этого параметра на работающем сервере быть не должно.

Есть также другой параметр tcp_tw_recycle, который позволяет сократить время нахождения соединения в TIME-WAIT, но известно, что при его использовании могут быть проблемы у клиентов за NAT. Не рекомендуется использовать данный параметр, а в новых версиях ядра он вообще удален.

Заключение

В итоге получилось, что для решения ошибки Nginx Cannot assign requested address while connecting to upstream можно использовать целый комплекс мер – увеличить лимиты в ядре, настроить keepalive и сконфигурировать upstream. Но также не стоит забывать, что нужно искать проблему не там, где кажется на первый взгляд, т.к. могут получаться такие совпадения, связанные с выкаткой нового функционала. Грешил на одно, а проблема оказалась в итоге совсем в другом месте. В идеале же нужно применять всё в зависимости от ситуации, а также не могу не упомянуть про мониторинг.

В моем случае после решения данной проблемы, я настроил в Zabbix простой мониторинг кол-ва TCP-соединений через netstat -nt для 80 и 443 на нужном мне порту, где запущен Nginx Ingress Controller, чтобы понимать динамику загрузки и оперативно принять меры.

Для более глубокого понимания проблемы рекомендую изучить ссылки в используемых источниках ниже, особенно из блога Nginx.

Используемые источники

  • https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/
  • https://ma.ttias.be/nginx-cannot-assign-requested-address-for-upstream/
  • https://www.nginx.com/blog/overcoming-ephemeral-port-exhaustion-nginx-plus/
  • https://habr.com/ru/company/flant/blog/343348/
  • https://tools.ietf.org/html/rfc1379
  • https://man7.org/linux/man-pages/man7/ip.7.html
  • https://gryzli.info/2018/03/05/nginx-cannot-assign-requested-address/
  • https://stackoverflow.com/questions/6426253/tcp-tw-reuse-vs-tcp-tw-recycle-which-to-use-or-both

Skip to content

So you want to run the IPython Notebook… and you’re using Anaconda 2.1.0 on some version of Linux.

You are already able to run ipython successfully…

$ ipython
IPython 2.2.0 -- An enhanced Interactive Python
[1]: exit()

But from the command line, when you try to run the IPython Notebook:

$ ipython notebook

You get a bunch of errors… something about sockets. The last error sticks out…

...
    return getattr(self._sock,name)(*args
error: [Errno 99] Cannot assign requested address

A bit of googling shows you some relevant links:

We summarize the two steps needed to get the Anaconda IPython Notebook working here.

1) From the command line run:

$ ipython profile create

This should create a bunch of profile info:

[ProfileCreate] Generating default config file: u'/your/path/.ipython/profile_default/ipython_config.py'
[ProfileCreate] Generating default config file: u'/your/path/.ipython/profile_default/ipython_qtconsole_config.py'
[ProfileCreate] Generating default config file: u'/your/path/.ipython/profile_default/ipython_notebook_config.py'
[ProfileCreate] Generating default config file: u'/your/path/.ipython/profile_default/ipython_nbconvert_config.py'

Note the location of the line with the ipython_noteboook_config.py (third line).

/your/path/.ipython/profile_default/

2) Navigate to and open ipython_noteboook_config.py

Within this file you should see these lines:

# The IP address the notebook server will listen on.
# c.NotebookApp.ip = 'localhost'

Simply add this line:

# The IP address the notebook server will listen on.
# c.NotebookApp.ip = 'localhost'
c.NotebookApp.ip = '127.0.0.1'

and save the file.

Now run:

$ ipython notebook

and it should work!

Понравилась статья? Поделить с друзьями:
  • Error enoent no such file or directory scandir
  • Error enoent no such file or directory open etc ksc web console setup json
  • Error enoent no such file or directory lstat index pug
  • Error english cover
  • Error endl was not declared in this scope