Оптимизация производительного web-сервера на FreeBSD

3jzamb4c2b0e8kuv5.5c56a6a9FreeBSD хорошо зарекомендовала себя как система для построения интранет- и интернет-серверов. Она предоставляет достаточно надёжные сетевые службы и эффективное управление памятью.

Стандартные настройки FreeBSD не позволяют оптимально использовать ресурсы аппаратной части. Рассмотрим пример конфигурации этой ОС для работы в качестве платформы для Web сервера.

Общие настройки

Основной тюнинг FreeBSD происходит посредством внесения изменений в sysctl. Все параметры разделяются на две группы:

  • Параметры применяемые только при загрузке
  • Параметры применяемые на лету

Параметры применяемые при загрузке

Для правки настроек, которые применяются только при загрузке, нужно внести изменения в файл /boot/loader.conf, после чего выполнить перезагрузку ОС.

# Отсутствие ограничений на размер зоны.
kern.ipc.nmbclusters=0
# После исчерпания не возможно выполнить повторную передачи пакетов.
net.inet.tcp.reass.maxsegments=2048
# Для избежания лимита "PV Entry"
vm.pmap.shpgperproc=400
# Позволяет принимать за одно прерывание до 4096 пакетов
hw.em.rxd=4096
# Позволяет передавать за одно прерывание до 4096 пакетов
hw.em.txd=4096
# Минимальная задержка между генерациями прерываний в мкс для приема данных
hw.em.rx_int_delay=100
# Минимальная задержка между генерациями прерываний в мкс для передачу данных
hw.em.tx_int_delay=100
# Максимальная задержка между генерациями прерываний в мкс для приема данных
hw.em.rx_abs_int_delay=1000
# Максимальная задержка между генерациями прерываний в мкс для передачи данных
hw.em.tx_abs_int_delay=1000 dev.em.rx_processing_limit=-1
# Настройка hostcache
net.inet.tcp.hostcache.hashsize=4096
net.inet.tcp.hostcache.bucketlimit=100
net.inet.tcp.hostcache.cachelimit=65536
# Настройка syncache
net.inet.tcp.syncache.hashsize=1024
net.inet.tcp.syncache.bucketlimit=100
net.inet.tcp.syncache.cachelimit=65536
# Таблица TCP control-block
net.inet.tcp.tcbhashsize=4096
# Настройка net.isr
# Очередь netisr
net.isr.defaultqlimit=4096
# Каждая очередь к отдельному ядру
net.isr.bindthreads=1
# Количество потоков netist (равно количеству ядер)
net.isr.maxthreads=8
# Размер очереди исходящий пакетов
net.link.ifqmaxlen=1024
# Модули
# Загружаем драйвер AHCI
ahci_load="YES"
# Асинхронное выполнение IO системных вызовов
aio_load="YES"

Параметры применяемые “на лету”

Для изменения параметров в уже загруженной ОС необходимо выполнить следующую команду:

sysctl param_name=value
# param_name — название параметра, value — значение

Также следует продублировать изменения в файл /etc/sysctl.conf, в противном случае, после перезагрузки, будет применено значение по умолчанию.

# Разрешает пользователям видеть только запущенные ими процессы
security.bsd.see_other_uids=0
# Количество сокетов
kern.ipc.maxsockets=204800
# Mbuf clusters
kern.ipc.nmbclusters=262144
# Запрещает вытеснение Wired памяти в Swap
kern.ipc.shm_use_phys=1
# Размер очереди для приема новых TCP соединений
kern.ipc.somaxconn=4096
# Определяет максимальное число дескрипторов файлов
kern.maxfiles=204800
# Максимальное число файлов на один процесс
kern.maxfilesperproc=200000
# Количество файловых дескрипторов закэшированых в памяти
kern.maxvnodes=256000
# не использовать трафик и прерывания
kern.random.sys.harvest.ethernet=0
# как источник энтропии для random'a
kern.random.sys.harvest.interrupt=0
# Попытаться синхронизировать диски при панике, для избежания fsck после перезагрузки
kern.sync_on_panic=1
# Для защиты от SMURF атак (ICMP echo request на broadcast адрес)
net.inet.icmp.bmcastecho=0
# Игнорировать пакеты icmp redirect
net.inet.icmp.drop_redirect=1
# Не отдавать по icmp маску своей подсети
net.inet.icmp.maskrepl=0
# Размер очереди IP-пакетов (Необходимо увеличивать если net.inet.ip.intr_queue_drops != 0)
net.inet.ip.intr_queue_maxlen=256
# Количество фрагментированных пакетов в очереди
net.inet.ip.maxfragpackets=1024
# Минимальный порт для исходящих соединений
net.inet.ip.portrange.first=1024
# Максимальный порт для исходящих соединений
net.inet.ip.portrange.last=65535
# Не использовать случайные порты для исх. соединений
net.inet.ip.portrange.randomized=0
# Не реагируем на ICMP редирект
net.inet.ip.redirect=0
# Отключение маршрутизации от источника
net.inet.ip.sourceroute=0
net.inet.ip.accept_sourceroute=0
# Не отвечать на все пакеты полученные на закрытый порт
net.inet.tcp.blackhole=2
# Отбрасывать пакеты с флагами SYN+FIN
net.inet.tcp.drop_synfin=1
# FIN_WAIT_2 state fast recycle
net.inet.tcp.fast_finwait2_recycle=1
# FIN_WAIT_2 таймаут
net.inet.tcp.finwait2_timeout=3000
# Время хранение hostcache
net.inet.tcp.hostcache.expire=1200
# Timeout for establishing syn
net.inet.tcp.keepinit=5000
# Максимально количество TIME_WAIT сокетов
net.inet.tcp.maxtcptw=65536
# Количество времени пребывания соединения в состоянии TIME_WAIT (в миллисекундах деленных на 2, 2 x 30000 MSL = 60 секунд)
net.inet.tcp.msl=5000
# Отключить автоподстройку receive буфера
net.inet.tcp.recvbuf_auto=0
# Размер receive буфера
net.inet.tcp.recvspace=65536
# Отключить автоподстройку send буфера
net.inet.tcp.sendbuf_auto=0
# Размер send буфера
net.inet.tcp.sendspace=131072
# Возможность перехода в "TCP SYN cookies" при переполнении syncache
net.inet.tcp.syncookies=1
# Отключаем использование TSO для сетевых карт
net.inet.tcp.tso=0
# Отбрасываются все UDP пакеты, адресованные закрытым портам
net.inet.udp.blackhole=1
# Размер UDP receive буфера
net.inet.udp.recvspace=32768
# Обрабатывать исходящие пакеты непосредственно при попытке отправки
net.isr.direct=1
# Размер исходящей очереди
net.route.netisr_maxqlen=1024
# При большом количестве файлов на сервере
vfs.ufs.dirhash_maxmem=100000000

Запуск приложений

Следующим этапом тюнинга ОС является настройка сети и запуск необходимых приложений в файле /etc/rc.conf.

# Задаем имя сервера
hostname="host.domain.com"
# Настраиваем сеть
ifconfig_em0="inet 172.16.1.5 netmask 255.255.255.0"
ifconfig_em1="inet 10.16.1.51 netmask 255.255.255.0"
defaultrouter="172.16.1.1"
# Запуск SSHD при загрузки
sshd_enable="YES"
# Запрещаем SSHD выполнять запросы к DNS
sshd_flags="-u0"
# Отключаем использование USB
usbd_enable="NO"
# Отключаем sendmail sendmail_enable=NONE
# Запускаем ntpd при старте ОС
ntpd_enable="YES"
# Отключаем NFS
inetd_enable="NO"
portmap_enable="NO"
nfs_client_enable="NO"
nfs_reserved_port_only="NO"
nfs_server_enable="NO"
# Небольшая защита от DDOSа
tcp_drop_synfin="YES"
icmp_drop_redirect="YES"
icmp_log_redirect="NO"
# Запускаем систему журналирования
syslogd_enable="YES"
# Указываем syslog сохранять только локальные сообщений
# и не выполняет DNS запросов
syslogd_flags="-s -n"
# Включить fsck при загрузке
fsck_y_enable="YES"
# Выполнять во время загрузки ОС
background_fsck="NO"
# Сохраняем корки ядра
dumpdir="/home"
dumpdev="AUTO"
# Отключить SNMPD
snmpd_enable="NO"
# Настройка фаервола
firewall_enable="YES"
firewall_script="/etc/rc.ipfw"
И напоследок добавим в файл /etc/rc.local скрипты которые нужно выполнить при загрузке.
# Привязывание очередей прерываний сетевых карт к процессорным ядрам
# по мотивам <a href="http://dadv.livejournal.com/139366.html" target="_blank"> этой статьи</a>.
/usr/local/startup/cpuset-emigb.sh

Скрипты

Скрипт инициализации фаервола /etc/rc.ipfw:

#!/bin/sh

WAN="em0"
LAN="em1"
OPEN_PORT="80,443"
IPFW=`which ipfw`
RET=$?

if [ ${RET} -ne 0 ]; then
echo "IPFW not found."
exit ${RET}
fi

${IPFW} -f flush
${IPFW} -f table 1 flush

${IPFW} add 100 allow ip from any to any via lo0
${IPFW} add 110 deny ip from any to 127.0.0.0/8
${IPFW} add 120 deny ip from 127.0.0.0/8 to any
${IPFW} add 130 allow ip from any to any via ${LAN}
${IPFW} add 140 deny all from table\(1\) to me
${IPFW} add 150 deny all from any to any frag

${IPFW} add 160 allow carp from any to any via ${WAN}
${IPFW} add 180 allow tcp from any to any via ${WAN} established
${IPFW} add 200 check-state
${IPFW} add 210 allow tcp from me to any via ${WAN} setup keep-state
${IPFW} add 220 allow udp from me to any via ${WAN} keep-state
${IPFW} add 230 allow tcp from any to me dst-port ${OPEN_PORT} via ${WAN}
${IPFW} add 240 allow icmp from any to any icmptypes 0,8 via ${WAN}
${IPFW} add 65530 deny ip from any to any

exit 0

Скрипт привязывания прерываний очередей сетевых карт к процессорным ядрам /usr/local/startup/cpuset-emigb.sh:

#!/bin/sh
cpus=`sysctl -n kern.smp.cpus`
DRIVER=`pciconf -l | egrep 'em|igb' | sed -E 's/^([emigb]+).*//' | head -n 1`
case "$DRIVER" in
em)
echo $DRIVER
i=1
vmstat -ai | egrep "em[0-9]:[a-z]x" | sed -E 's/^irq([0-9]+): (em[0-9]):([a-z]+).*/  /' |
while read irq iface queue
do
cpu=$(( $i % $cpus ))
echo "Binding ${iface} queue ${queue} (irq ${irq}) -> CPU${cpu}"
cpuset -l $cpu -x $irq
i=$(( $i + 1 ))
done
;;
igb)
echo $DRIVER
vmstat -ai | sed -E '/^irq.*que/!d; s/^irq([0-9]+): igb([0-9]+):que ([0-9]+).*/  /' |
while read irq iface queue
do
cpu=$(( ($iface+$queue) % $cpus ))
echo "Binding igb${iface} queue ${queue} (irq ${irq}) -> CPU${cpu}"
cpuset -l $cpu -x $irq
done
;;
esac

Самое важное

Выше приведен пример настройки платформы Web сервера для работы под высокими нагрузками. Подстройку параметров следует делать периодически, чтобы адаптировать ОС под изменения в нагрузках.


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Unlix © Все права защищены 2023

Копирование материалов с сайта Unlix.ru без указания полной ссылки на источник ЗАПРЕЩЕНО!