Прокачиваем сетевой стек для iSCSI

 Статья была написана 29 мая 2011 г. Перенесена из старого блога.

Все начинается с того, что сетевая подсистема большинства дистрибутивов в том числе и OpenFiler’a используемого в качестве iSCSI-Target’a оптимизирована для большого спектра применений. В нашем же случае, для взаимодействия хостов(Proxmox или XenServer) с общим сетевым хранилищем по протоколу iSCSI нужны быстрые сетевые каналы с минимальным временем отклика.

Используя 1G Ethernet мы по большему счету(в сравнении с FC) не получаем широких каналов и уж тем более приемлемого, критичного для ВМ времени отклика. В таком случае, упираясь в производительность сетевого оборудования остается только попробовать оптимизировать работу сетевых протоколов, для получения максимального эффекта от того что имеем:)

Увеличение MTU сетевых контроллеров

Увелечение MTU(Maximum Transmission Unit) до 9000 байт позволит сетевым контроллерам пропускать сверхдлинные Ethernet-кадры(Jumbo-кадры)

В RedHat-подобных дистрибутивах(OpenFiler, XenServer)это делается в файле настроек конкретной сетевой карточки(/etc/sysconfig/network-scripts/ifcfg-<ИмяУстройства> где имя устройства, обычно eth0, eth1 и т.д.). Меняем стандартное значение MTU=1500 на MTU=9000.

Это увеличит размер передаваемых данных за раз(максимальный размер блока), что значительно повысит производительность в не зависимости от типа трафика т.к размер блока устанавливается на канальном уровне модели OSI прозрачно для высокоуровневых протоколов(NFS, iSCSI, CIFS и прочие)

Сетевые параметры ядра Linux

Список наиболее важных параметров ядра, имеющих отношение к эффективности и производительности сети;
net.core.somaxconn  = 256 (по умолчанию 128 ) — Максимальное число открытых сокетов, ждущих соединения. Имеет смысл увеличить значение при большем количестве соединений. Для высоко нагруженных серверов советуют значения в районе 15000-20000.

В нашем случае, количество соединений не большее(это не веб и не майл сервер) поэтому можно и не увеличивать.

net.core.rmem_max = 1073741824 (по умолчанию 124928) — Устанавливает максимальный размер буфера на прием для всех протоколов.

net.core.wmem_max = 1073741824 (по умолчанию 124928) — Устанавливает максимальный размер буфера на передачу для всех протоколов.
net.ipv4.tcp_reordering = 20 (по умолчанию 3) Иногда увеличение времени прохождения пакета в локальной сети может считаться потерей пакета. Для таких случаев увеличение значения этого параметра повышает производительность.

net.ipv4.tcp_rmem = 1048576 16777216 1073741824 (по умолчанию 4096 87380 937024)
Соответственно минимум, по умолчанию и максимум. Переменная в файле tcp_rmem содержит 3 целых числа, определяющих размер приемного буфера сокетов TCP.
Минимум: каждый сокет TCP имеет право использовать эту память по факту своего создания. Возможность использования такого буфера гарантируется даже при достижении порога ограничения (moderate memory pressure). Размер минимального буфера по умолчанию составляет 8 Кбайт (8192).
Значение по умолчанию: количество памяти, допустимое для буфера передачи сокета TCP по умолчанию. Это значение применяется взамен параметра /proc/sys/net/core/rmem_default, используемого другими протоколами. Значение используемого по умолчанию буфера обычно (по умолчанию) составляет 87830 байт. Это определяет размер окна 65535 с заданным по умолчанию значением tcp_adv_win_scale и tcp_app_win = 0, несколько меньший, нежели определяет принятое по умолчанию значение tcp_app_win.
Максимум: максимальный размер буфера, который может быть автоматически выделен для приема сокету TCP. Это значение не отменяет максимума, заданного в файле /proc/sys/net/core/rmem_max. При “статическом” выделении памяти с помощью SO_RCVBUF этот параметр не имеет значения. Используемый по умолчанию максимум составляет 87380 * 2 байт.

net.ipv4.tcp_wmem = 1048576 16770216 1073741824 (по умолчанию 4096 16384b937024 )
Переменная в файле tcp_wmem содержит 3 целочисленных значения, определяющих минимальное, принятое по умолчанию и максимальное количество памяти, резервируемой для буферов передачи сокета TCP.

Минимум: каждый сокет TCP имеет право использовать эту память по факту своего создания. Размер минимального буфера по умолчанию составляет 4 Кбайт (4096)
Значение по умолчанию: количество памяти, допустимое для буфера передачи сокета TCP по умолчанию. Это значение применяется взамен параметра /proc/sys/net/core/wmem_default, используемого другими протоколами и обычно меньше, чем /proc/sys/net/core/wmem_default. Размер принятого по умолчанию буфера обычно (по умолчанию) составляет 16 Кбайт (16384)
Максимум: максимальное количество памяти, которое может быть автоматически выделено для буфера передачи сокета TCP. Это значение не отменяет максимум, заданный в файле /proc/sys/net/core/wmem_max. При “статическом” выделении памяти с помощью SO_SNDBUF этот параметр не имеет значения. По умолчанию размер максимального буфера составляет 128 Кбайт (131072).

ВНИМАНИЕ: Максимальные значения параметров net.ipv4.tcp_rmem, net.ipv4.tcp_wmem не должны превышать значения параметров net.core.rmem_max и net.core.wmem_max!

net.ipv4.tcp_mem = 1048576 16770216 1073741824 (по умолчанию 21960 29282 43920)
Переменная в файле tcp_mem содержит 3 целых числа (порога), определяющих отношение протокола TCP к выделению памяти.
Нижний порог: при значениях ниже этого уровня TCP не заботится о расходе памяти.
Порог ограничения: при достижении этого порога TCP контролирует размер выделяемой памяти и переходит в режим memory pressure (нехватка памяти), из которого выходит при снижении расхода памяти до нижнего порога.
Верхний порог: число страниц памяти, доступных для создания очередей всеми сокетами TCP.
Значения всех порогов рассчитываются во время загрузки ОС с учетом доступной на компьютере памяти.

net.ipv4.tcp_window_scaling = 1 (по умолчанию обычно 1) — Активирует масштабирование окна, как определено в RFC 1323; должен быть включен(1) для поддержки окон размером больше, чем 64KB.

net.ipv4.tcp_sack = 1
(по умолчанию обычно 1) — Активирует выборочное подтверждение (selective acknowledgment), которое улучшает производительность, выборочно подтверждая пакеты, полученные вне очереди (в результате отправитель повторно передает только пропущенные сегменты); должен быть включен (для большой области сетевых коммуникаций), но может усилить использование CPU.

net.ipv4.tcp_fack = 1
(по умолчанию обычно 1) — Включает Forward Acknowledgment (прогнозное подтверждение), которое оперирует с выборочным подтверждением (SACK — Selective Acknowledgment) для уменьшения перегрузки; должен быть включен(1).

net.ipv4.tcp_timestamps = 1
(по умолчанию обычно 1) — Активирует вычисление RTT более достоверным способом (смотрите RFC 1323), чем интервал для повторной передачи; должен быть включен для быстродействия.

net.ipv4.tcp_low_latency = 0
(по умолчанию обычно 0)Разрешает стеку TCP/IP отдавать предпочтение низкому времени ожидания перед более высокой пропускной способностью. Вот здесь спорный момен. Если каналы высоконагруженны то лучше не включать. Если трафик не большей и более важно время отклика то лучше включить.

Установить значения приведенных выше параметров можно воспользовавшись командой:
#sysctl -w <имяПараметра>=<Значение>

Например:
#sysctl -w net.ipv4.tcp_low_latency=1
устанавливает новое значение параметра net.ipv4.tcp_low_latency

Изменение значений параметров с помощью утилиты sysctl, действуют только до перезагрузки системы. Для установки постоянных значений необходимо прописать соответствующие параметры и их значения в вайле /etc/sysctl.conf

Посмотреть текущие значения параметров можно в соответствующих файлах виртуальной файловой системы /proc;
#cat /proc/sys/net/ipv4/tcp_low_latency
просмотр текущего значения параметра net.ipv4.tcp_low_latency.

Изменение значения перечисленных выше параметров в разной степени но все же оказываю влияние на потребление памяти и ресурсов CPU.

Все перечисленные выше параметры не являются панацеей, но в какой то степени позволяют использовать имеющиеся каналы более эффективно в контексте виртуализации.