увеличение максимального количества соединений tcp / ip в linux

<p>я программирую сервер, и кажется, что мое количество подключений ограничено, поскольку пропускная способность не насыщается, даже если я установил количество подключений как "неограниченное".</p><p>как я могу увеличить или исключить максимальное количество подключений, которое мой ubuntu linux может открывать одновременно? ос ограничивает это, или это маршрутизатор или провайдер? или что-то еще?</p>

<p>на максимальное количество соединений влияют определенные ограничения как на стороне клиента, так и на стороне сервера, хотя и немного по-разному.</p><p><strong> на стороне клиента: </strong> увеличьте диапазон внешних портов и уменьшите <code>tcp\_fin\_timeout</code></p><p>чтобы узнать значения по умолчанию:</p><pre><code>sysctl net.ipv4.ip\_local\_port\_range sysctl net.ipv4.tcp\_fin\_timeout </code></pre><p>диапазон внешних портов определяет максимальное количество исходящих сокетов, которое хост может создать из определенного i.p. адрес. код <code>fin\_timeout</code> определяет минимальное время, в течение которого эти сокеты будут находиться в состоянии <code>time\_wait</code> (невозможно использовать после однократного использования). обычные системные настройки по умолчанию:</p><ul> <li><code>net.ipv4.ip\_local\_port\_range = 32768 61000</code></li> <li><code>net.ipv4.tcp\_fin\_timeout = 60</code></li> </ul><p>по сути, это означает, что ваша система не может постоянно гарантировать более чем <code>(61000 - 32768) / 60 = 470</code> сокетов в секунду. если вас это не устраивает, вы можете начать с увеличения <code>port\_range</code>. установка диапазона на <code>15000 61000</code> довольно распространена в наши дни. вы можете еще больше увеличить доступность, уменьшив <code>fin\_timeout</code>. предположим, что вы делаете оба, вы должны видеть более 1500 исходящих подключений в секунду, с большей готовностью.</p><p><strong> чтобы изменить значения </strong>:</p><pre><code>sysctl net.ipv4.ip\_local\_port\_range="15000 61000" sysctl net.ipv4.tcp\_fin\_timeout=30 </code></pre><p>вышесказанное не следует интерпретировать как факторы, влияющие на способность системы устанавливать исходящие соединения в секунду. но скорее эти факторы влияют на способность системы обрабатывать параллельные соединения устойчивым образом в течение больших периодов "активности".</p><p>значения sysctl по умолчанию в типичной коробке linux для <code>tcp\_tw\_recycle</code> & <code>tcp\_tw\_reuse</code> будут</p><pre><code>net.ipv4.tcp\_tw\_recycle=0 net.ipv4.tcp\_tw\_reuse=0 </code></pre><p>они не разрешают соединение из "используемого" сокета (в состоянии ожидания) и заставляют сокеты длиться полный цикл <code>time\_wait</code>. я рекомендую установить:</p><pre><code>sysctl net.ipv4.tcp\_tw\_recycle=1 sysctl net.ipv4.tcp\_tw\_reuse=1 </code></pre><p>это позволяет быстро переключать сокеты в состоянии <code>time\_wait</code> и повторно использовать их. но перед тем, как вы сделаете это изменение, убедитесь, что оно не конфликтует с протоколами, которые вы используете для приложения, которому нужны эти сокеты. обязательно прочитайте пост <a href="https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux">"как справиться с tcp time-wait" от винсента берната</a> , чтобы понять последствия. параметр <code>net.ipv4.tcp\_tw\_recycle</code> <strong> довольно проблематичен для общедоступных серверов, поскольку он не будет обрабатывать подключения с двух разных компьютеров за одним и тем же устройством nat </strong>, которая является проблемой, которую трудно обнаружить и ожидающей, чтобы укусить вас. обратите внимание, что <code>net.ipv4.tcp\_tw\_recycle</code> был <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4396e46187ca5070219b81773c4e65088dac50cc">удален</a> из linux4.12.</p><p><strong> на стороне сервера: </strong> значение <code>net.core.somaxconn</code> играет важную роль. это ограничивает максимальное количество запросов в очереди к сокету прослушивания. если вы уверены в возможностях вашего серверного приложения, увеличьте его значение по умолчанию со 128 до 128 - 1024. теперь вы можете воспользоваться этим увеличением, изменив переменную listen backlog в вызове listen вашего приложения на равное или большее целое число.</p><pre><code>sysctl net.core.somaxconn=1024 </code></pre><p>параметр <code>txqueuelen</code> ваших сетевых карт также играет определенную роль. значения по умолчанию - 1000, поэтому увеличьте их до 5000 или даже больше, если ваша система справится с этим.</p><pre><code>ifconfig eth0 txqueuelen 5000 echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local </code></pre><p>аналогичным образом увеличьте значения для <code>net.core.netdev\_max\_backlog</code> и <code>net.ipv4.tcp\_max\_syn\_backlog</code>. их значения по умолчанию 1000 и 1024 соответственно.</p><pre><code>sysctl net.core.netdev\_max\_backlog=2000 sysctl net.ipv4.tcp\_max\_syn\_backlog=2048 </code></pre><p>теперь не забудьте запустить ваши клиентские и серверные приложения, увеличив значения fd в командной консоли.</p><p>помимо вышесказанного, еще одна популярная техника, используемая программистами, заключается в уменьшении количества вызовов <em> tcp write </em>. я предпочитаю использовать буфер, в который я отправляю данные, которые я хочу отправить клиенту, а затем в соответствующие моменты записываю буферизованные данные в реальный сокет. этот метод позволяет мне использовать большие пакеты данных, уменьшить фрагментацию, уменьшить загрузку процессора как на уровне пользователя, так и на уровне ядра.</p>

<p>есть пара переменных для установки максимального количества соединений. скорее всего, у вас заканчиваются номера файлов в первую очередь. проверьте ulimit -n. после этого в/proc есть настройки, но они по умолчанию равны десяткам тысяч.</p><p>что еще более важно, кажется, что вы делаете что-то не так. одно соединение tcp должно иметь возможность использовать всю полосу пропускания между двумя сторонами; если это не так:</p><ul> <li>проверьте, достаточно ли велика настройка окна tcp. стандартные настройки linux хороши для всего, кроме очень быстрой инет-связи (сотни мбит/с) или быстрой спутниковой связи. какова ваша пропускная способность * задержка продукта?</li> <li>проверьте потерю пакетов с помощью ping с большими пакетами (<code>ping -s 1472</code> ...)</li> <li>проверьте ограничение скорости. в linux это настраивается с помощью <code>tc</code></li> <li>подтвердите, что пропускная способность, которую вы считаете существующей, действительно существует, например, <code>iperf</code></li> <li>подтвердите, что ваш протокол вменяемый. запомни латентность.</li> <li>если это гигабит + локальная сеть, можете ли вы использовать гигантские пакеты? ты?</li> </ul><p>возможно, я неправильно понял. может быть, вы делаете что-то вроде bittorrent, где вам нужно много соединений. если это так, вам нужно выяснить, сколько соединений вы на самом деле используете (попробуйте <code>netstat</code> или <code>lsof</code>). если это число является существенным, вы можете:</p><ul> <li>имеют большую пропускную способность, например, 100 мбит/с +. в этом случае вам может понадобиться код <code>ulimit -n</code>. тем не менее, ~ 1000 подключений (по умолчанию в моей системе) довольно много.</li> <li>проблемы с сетью, которые замедляют ваши соединения (например, потеря пакетов)</li> <li>есть что-то еще, что замедляет вас, например, io пропускная способность, особенно если вы ищете. вы проверяли <code>iostat -x</code>?</li> </ul><p>кроме того, если вы используете маршрутизатор nat потребительского уровня (linksys, netgear, dlink и т.д.), имейте в виду, что его возможности могут превысить тысячи подключений.</p><p>я надеюсь, что это поможет. вы действительно задаете сетевой вопрос.</p>

<p>чтобы улучшить ответ, данный деробертом,</p><p>вы можете определить, какое ограничение на количество подключений к вашей ос вы можете, выполнив команду nf\_conntrack\_max.</p><p>например: cat/proc/sys/net/netfilter/nf\_conntrack\_max</p><p>вы можете использовать следующий скрипт для подсчета количества соединений tcp с заданным диапазоном портов tcp. по умолчанию 1-65535.</p><p>это подтвердит, превышаете ли вы максимальный лимит соединения с вашей ос.</p><p>вот сценарий.</p><pre><code>#!/bin/bash os=$(uname) case "$os" in 'sunos') awk=/usr/bin/nawk ;; 'linux') awk=/bin/awk ;; 'aix') awk=/usr/bin/awk ;; esac netstat -an | $awk -v start=1 -v end=65535 ' $nf ~ /time\_wait|established/ && $4 !~ /127.0.0.1/ { if ($1 ~ /\./) {sip=$1} else {sip=$4} if ( sip ~ /:/ ) {d=2} else {d=5} split( sip, a, /:|\./ ) if ( a[d] >= start && a[d] <= end ) { ++connections; } } end {print connections}' </code></pre>

<p>на уровне приложения разработчик может сделать следующее:</p><p><strong> со стороны сервера: </strong></p><ol> <li> <p>проверьте, правильно ли работает балансировщик нагрузки (если есть).</p> </li> <li> <p>превратите медленные tcp тайм-ауты в 503 быстрое немедленное реагирование. если вы правильно работаете с балансировщиком нагрузки, он должен выбрать рабочий ресурс для обслуживания, и это лучше, чем зависать там с неожиданными сообщениями об ошибках.</p> </li> </ol><p>например: если вы используете сервер узлов, вы можете использовать toobusy из npm. реализация что-то вроде:</p><pre><code>var toobusy = require('toobusy'); app.use(function(req, res, next) { if (toobusy()) res.send(503, "i'm busy right now, sorry."); else next(); }); </code></pre><p>почему 503? вот несколько полезных советов по перегрузке: <a href="http://ferd.ca/queues-don-t-fix-overload.html">http://ferd.ca/queues-don-t-fix-overload.html</a> </p><p><strong> мы можем также поработать на стороне клиента: </strong></p><ol> <li> <p>попробуйте сгруппировать звонки в пакетном режиме, уменьшить трафик и общее количество запросов ч/б клиент и сервер.</p> </li> <li> <p>попробуйте создать кэш среднего уровня для обработки ненужных дубликатов запросов.</p> </li> </ol>