Я разрабатываю код, имитирующий сетевое оборудование.Мне нужно запустить несколько тысяч симулированных «агентов», и каждому нужно подключиться к сервису.Проблема в том, что после открытия 1023 подключений время начала соединения истекает, и все это рушится.
Основной код на Go, но я написал очень тривиальный скрипт на python, который воспроизводитпроблема.
Единственное, что несколько необычно, это то, что нам нужно установить локальный адрес в сокете при его создании.Это связано с тем, что оборудование, к которому подключаются агенты, ожидает, что видимый IP будет соответствовать тому, что, как мы говорим, должно быть.Для этого я настроил 10 000 виртуальных интерфейсов (от eth0: 1 до eth0: 10000).Им присваиваются уникальные IP-адреса в частной сети.
Сценарий python как раз такой (работает только до 2000 соединений):
import socket
i = 0
for b in range(10, 30):
for d in range(1, 100):
i += 1
ip = "1.%d.1.%d" % (b, d)
print("Conn %i %s" % (i, ip))
s = socket.create_connection(("1.6.1.1", 5060), 10, (ip, 5060))
Если я удаляю последний аргумент для socket.create_connection(исходный адрес), тогда я могу получить все 2000 соединений.
Особенность, отличающаяся использованием локального адреса, заключается в том, что необходимо выполнить привязку, прежде чем можно будет установить соединение, поэтому вывод этогоПрограмма, запущенная под strace, выглядит следующим образом:
Conn 1023 1.20.1.33
bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.20.1.33")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.6.1.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
Если я запускаю без локального адреса, привязка AF_INET исчезает, и она работает.
Итак, похоже, что-то должно бытьограничения на количество связываний, которые могут быть сделаны.Я пробежал по всевозможным ссылкам о настройке TCP в Linux, и я попытался возиться с tcp_tw_reuse / recycle, уменьшил fin_timeout и сделал другие вещи, которые не могу вспомнить.
Это работает в Ubuntu Linux (11.04, ядро 2.6.38 (64 бит). Это виртуальная машина в кластере VMWare ESX.
Непосредственно перед публикацией я попытался запустить второй экземплярсценарий python, с дополнительным, начиная с 1.30.1.1. Первый сценарий пропустил до 1023 подключений, но второй даже не смог выполнить первое, указывая на то, что проблема связана с большим количеством виртуальных интерфейсов.какая-то внутренняя структура данных ограничена? Какой-то максимальный параметр памяти где-то?
Кто-нибудь может подумать о каком-то ограничении в Linux, которое может вызвать это?
Обновление:
Сегодня утром я решил попробовать эксперимент. Я изменил скрипт на python, чтобы использовать IP "основного" интерфейса в качестве IP-адреса источника и эфемерные порты вДиапазон 10000+.Сценарий теперь выглядит следующим образом:
import socket
i = 0
for i in range(1, 2000):
print("Conn %i" % i)
s = socket.create_connection(("1.6.1.1", 5060), 10, ("1.1.1.30", i + 10000))
Этот сценарий работает просто отлично, поэтому это добавляет мне уверенности в том, что проблема связана с большим количеством псевдонимов IP-адресов.