Настройка ядра FreeBSD через sysctl

Евгений «j1m» Зобнин.

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

Историческая справка

Во времена ранних версий BSD пользователям, желавшим получить доступ к настройкам ядра или изменить его конфигурацию, приходилось прибегать к замысловатым приемам и техникам. Обычно для этого создавались небольшие вспомогательные утилиты, которые читали файл /dev/kmem (образ памяти ядра), находили в нем необходимые структуры данных и передавали их пользователю. Для изменения параметров применялся похожий прием с последующей записью информации по определенному адресу. Практика использования файла /dev/kmem как интерфейса конфигурирования ядра обнаружила множество недостатков такого подхода. Структуры данных могли как перемещаться в памяти, так и просто исчезать из нее. Поэтому всегда существовал риск того, что программа запишет данные в неверно выбранный участок памяти с последствиями в виде классического kernel panic. Процедура поиска значительно нагружала процессор, который в те годы и без того не мог похвастаться производительностью. Меры ограничения доступа к файлу /dev/kmem ослаблялись, так как администраторам приходилось считаться с потребностями программ-конфигураторов. И, в конце концов, все это крепко пахло грязным хаком, который был совершенно несвойственен элегантному UNIX.

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

Реализация

Все настройки ядра хранятся в специальных переменных, организованных в древовидную структуру, называемую MIB (Management Information Base), а совокупность всех переменных именуется состоянием ядра. Структура MIB очень напоминает древовидную организацию файлов и каталогов в файловой системе. Каждая ветвь такого дерева ссылается на определенную тематическую область конфигурации ядра (сведения об ОС, безопасность, подсистема виртуальной памяти, подсистема ввода-вывода и т.д.), позволяя легко найти нужную переменную. При этом ветви могут быть многократно вложены, разбивая разделы на подразделы.

Не все переменные доступны для записи, так же как не все переменные служат для настройки ядра. Многие из них используются для получения сведений о ядре и операционной системе. Другие предназначены для получения различной статистики, третьи - для наблюдения за состоянием ядра. Специальный раздел отведен для информации о железной составляющей ПК: ISA- и PCI-устройства, жесткие диски, ACPI. Многие переменные привязаны к определенной подсистеме или механизму ядра, и в случае отсутствия одного из его компонентов структура MIB будет неполной. Так, например, если ядро собрано без поддержки пакетного фильтра ipfw, все запросы к переменным ветви net.inet.ip.fw приведут к сообщению об ошибке.

В FreeBSD версии 6.1 доступно более тысячи переменных, разбитых на 12 основных разделов.

Корневые ветви дерева MIB
kern - основные настройки ядра;
vm - подсистема виртуальной памяти;
vfs - подсистема VFS;
net - стек сетевых протоколов;
debug - отладочная информация;
hw - настройки аппаратного обеспечения;
machdep - настройки, зависящие от аппаратной платформы;
user - ограничения пользователей;
p1003_1b - совместимость со стандартом POSIX 1003.1b;
compat - совместимость с другими операционными системами;
security – безопасность;
dev - информация об аппаратных устройствах.

Начинаем

Специально для манипуляции переменными ядра в BSD была введена специальная утилита /sbin/sysctl. С ее помощью можно просмотреть список доступных переменных, узнать и изменить их значение, а также получить описание переменной. Так, для получения значения переменной используется команда «sysctl путь.до.переменной», для записи нового значения – «sysctl путь.до.переменной=значение». Для получения списка переменных можно использовать флаг -a, а чтобы узнать описание переменной - флаг -d.



sysctl -a: значения всех переменных


Кроме того, предусмотрен специальный конфигурационный файл /etc/sysctl.conf, куда следует вносить переменные, значения которых должны быть изменены во время инициализации системы. Замечу, что некоторые переменные не могут быть изменены во время работы ядра (в основном это переменные раздела hw), их необходимо поместить в файл /boot/loader.conf, который читается еще до загрузки ядра.



sysctl -ad: описание всех переменных


Подавляющее большинство переменных не дает практического эффекта пользователям, а значение некоторых и вовсе понятно лишь разработчикам ядра. Поэтому сегодня мы рассмотрим наиболее интересные из них.

Основные настройки ядра

К основным настройкам ядра можно отнести почти все переменные раздела kern. Здесь хранится информация о ядре и его версии, времени последней сборки ядра, сетевое имя машины, различные ограничения. Давай рассмотрим эти переменные:

Основные настройки ядра FreeBSD

Информация о ядре (только для чтения):
kern.ostype - тип ОС, всегда FreeBSD.
kern.osrelease - версия, например 6.1-RELEASE.
kern.osreldate - дата выхода данной версии.
kern.osrevision - время ревизии ОС.
kern.version - тип ОС, ее версия и время последней сборки.
kern.posix1version - с какой версией POSIX.1 совместима ОС.
kern.ident - идентификатор ядра; строка, указанная в конфиге ядра после директивы ident.
kern.boottime - время последней загрузки ядра.

Инициализация ядра (могут быть изменены через /boot/loader.conf):
kern.bootfile - путь до ядра (директива bootfile).
kern.module_path - путь до каталога с модулями (директива module_path).
kern.init_path - путь до программы init (директива init_path).

Сетевое имя:
kern.hostname - сетевое DNS-имя машины.
kern.domainname - домен службы NIS.

Ограничения:
kern.maxproc - максимально допустимое число процессов.
kern.maxfiles - максимально допустимое число открытых файлов.
kern.maxfilesperproc - максимальное число открытых файлов на каждый процесс.
kern.maxusers - максимально допустимое число зарегистрированных пользователей в системе.

Другое:
kern.disks - список доступных жестких дисков (ro).
kern.malloc - список буферов, динамически выделяемых ядром для собственных нужд, и их размер.
kern.coredump - включить/выключить создание core-файлов при крахе программы. На домашней машине лучше указать 0.
kern.corefile - место, куда складывать core-файлы. По умолчанию core-файлы попадают в текущий каталог. Возможным решением будет строка «/tmp/%U.%N.core».
kern.sched.name - используемый планировщик процессов (ro).
kern.sched.quantum - квант времени в микросекундах, выделяемый на каждый процесс. Для лучшей отзывчивости программ значение можно поднять до 250000. На серверах рекомендуется оставить значение по умолчанию (100000).
kern.sched.preemption - при необходимости позволить ядру вытеснять работающий процесс. Повысит отзывчивость системы.

SMP:
kern.smp.maxcpus - максимальное число процессоров, поддерживаемых ядром. Задается при сборке ядра.
kern.smp.active - число активных процессоров (найденных ядром и готовых к выполнению задачи).
kern.smp.disabled - число отключенных процессоров.
kern.smp.cpus - число задействованных в данный момент процессоров.

Несколько ремарок. По умолчанию переменная kern.module_path содержит строку «/boot/kernel;/boot/modules». Первый каталог для модулей, поставляемых с ядром, второй - для модулей сторонних разработчиков. Модифицировать значения переменных kern.max* в большинстве случаев не имеет смысла, потому как времена, когда эти значения были вшиты в ядро, прошли. Сегодня FreeBSD способна сама определять оптимальные величины и не требует от пользователя бессмысленных вычислений. Единственным случаем, когда все-таки может понадобиться увеличение числа открытых файлов, является нагруженный веб-сервер или любая другая программа, работающая с множеством файлов. Для вычисления оптимального значения можно обратиться к переменной kern.openfiles, которая содержит текущее число открытых файлов.



Системная информация


Сетевая подсистема

Настройка сетевой подсистемы обычно сводится:

а) к повышению некоторых лимитов, что в итоге позволяет ядру обрабатывать больше подключений, отправлять большее количество данных в секунду и эффективнее работать с сетевым оборудованием;

б) к изменению настроек таким образом, чтобы защитить ядро от различных видов атак и подстроить его под выполнение определенной задачи.

Этими двумя пунктами мы и будем руководствоваться.

Увеличение производительности:
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=48000 - увеличиваем диапазон портов, доступных программам. Стоит изменять только на нагруженных серверах, использующих много исходящих подключений, таких как веб-прокси и ftp.
kern.polling.enable=1 - включаем device polling. Осуществляется самостоятельный опрос устройств вместо генерирования прерываний устройством, что позволяет значительно увеличить производительность при больших нагрузках на сетевую карту. Ядро должно быть собрано с опциями «options DEVICE_POLLING» и «options HZ=1000».
kern.ipc.somaxconn=2048 - увеличиваем очередь входящих подключений со 128 до 2048, что помогает нагруженному серверу принять больше подключений, а также затрудняет SYN-флуд.

Защита от сетевых атак:
net.inet.tcp.blackhole=1
net.inet.udp.blackhole=1 - превращаем машину в черную дыру. Ядро не будет отправлять RST-пакет в ответ на обращение к незанятым портам. Сканеры портов не любят этого.
net.inet.icmp.drop_redirect=1
net.inet.ip.redirect=0 - запрещаем ICMP-сообщения, приводящие к изменению таблицы маршрутизации (тип 5: IP Redirect). Удивительно, но FreeBSD даже в 2007 году разрешает такие сообщения по умолчанию.
net.inet.ip.forwarding=0 - отключаем перенаправление пакетов с одного сетевого интерфейса на другой.

Счастливые обладатели высокоскоростных соединений (это, в первую очередь, Gigabit Ethernet) могут поэкспериментировать с размерами входных и выходных сетевых TCP-буферов, увеличивая значение переменных net.inet.tcp.sendspace и net.inet.tcp.recvspace. Но стоит помнить, что слишком объемные буферы быстро приведут к исчерпанию памяти при большом количестве подключений. Для веб-сервера, который принимает много коротких запросов и отправляет большие объемы данных, размер выходного буфера рекомендуется увеличить в ущерб входного.

Производительность samba и squid можно увеличить, изменив значение переменной net.inet.tcp.delayed_ack на 0 и запретив таким образом отправку ответных ACK-сообщений вместе с данными. В случае интерактивных протоколов, таких как POP, IMAP, SMTP, SSH и FTP, это изменение приведет к заполнению сети лишними пакетами, содержащими лишь ACK-сообщения, и снижению производительности.

Полезные и не очень мелочи

В заключительной части статьи мы рассмотрим несколько интересных (с точки зрения практической выгоды) переменных. Для начала обратимся к неизменяемым переменным, которые будут полезны как источник информации. В первую очередь, это переменная vm.vmtotal, которая в удобной для чтения форме показывает информацию о количестве процессов в системе, размере виртуальной и физической памяти, а также о количестве свободной. Далее - переменная vm.loadavg, содержащая таинственное значение «загруженности системы». Вкратце объяснить эти числа невозможно, поэтому скажу только, что если все три числа подойдут к отметке «5», то, значит, где-то в системе создалось узкое место, которое может быть где угодно: в оперативной памяти, жестком диске, или заключаться в какой-то внутренней неполадке.

Теперь о переменных, изменять значение которых имеет смысл. К ним относится vfs.usermount, установив значение которой в единицу, мы позволим любому пользователю монтировать файловые системы к точке, принадлежащей ему. Далее - hw.snd.pcm0.vchans и hw.snd.maxautovchans, позволяющие создать несколько виртуальных каналов для одной звуковой карты, что дает возможность одновременно слышать звук из нескольких источников без использования звуковых демонов. На домашней машине рекомендуется создать 4 канала - этого вполне достаточно для повседневных нужд.

Напоследок скажем пару слов об управлении питанием. Очень часто на форумах можно встретить вопросы вроде: «Как отключить кнопку «power»?» или «Как отключить кнопку «sleep» на клавиатуре?». Ответ прост. Пишем в файл /etc/sysctl.conf строку «hw.acpi.power_button_state=NONE» или «hw.acpi.sleep_button_state=NONE» в зависимости от желаемого результата. Также можно не отключать клавишу совсем, а просто изменить ее поведение, назначив ей любое из доступных состояний ACPI, перечисленных в переменной hw.acpi.supported_sleep_state. При этом S1 - самый низкий уровень энергосбережения (сон), а S5 - самый высокий (выключение).

Дорогу молодым

К сожалению, многое из того, что я хотел рассказать в этом материале, так и осталось в моей голове и на страницах многочисленных заметок. Читателям, жаждущим идти дальше, я предлагаю распечатать вывод команды sysctl -ad и читать его на ночь, время от времени заглядывая в англо-русский словарик. Те, кого интересуют переменные, связанные с jail, могут обратиться к моей статье «Тюрьма для чертенка», где они и описаны.

P.S.: Главное правило оптимизатора

Перед тем как приступать к изменению настроек ядра, стоит запомнить одну простую истину. По умолчанию ядро настроено на оптимальную производительность, и, как заметил Пол-Хеннинг Камп, улучшая производительность одной подсистемы, мы понижаем производительность другой. А компетентность этого человека в этом вопросе неоспорима.

http://www.xakep.ru/post/36954/default.asp,

Обновлено: 12.03.2015