СЕРГЕЙ СУПРУНОВ
Как работает Sendmail? Полезные подробности
Часть 3: Вопросы администрирования
Если ваш почтовый сервер перестал справляться с возросшей нагрузкой или работает недостаточно стабильно, не спешите покупать более мощное «железо». Возможно, проблема решится после грамотной настройки Sendmail.
Пользователи и права
Сначала коснёмся общих вопросов безопасности, связанных с работой Sendmail. Как мы видели в первой части статьи [1], Sendmail, обеспечивающий функционирование почтового сервера, выполняет несколько различных задач. Рассмотрим этот процесс с точки зрения необходимых прав.
Процесс, прослушивающий 25-й порт в ожидании входящих соединений, должен обладать правами root, поскольку порты до 1024-го относятся к привилегированным и не могут быть связаны с процессами, принадлежащими обычным пользователям.
Дочерний процесс, порождаемый для обработки входящего соединения, должен иметь право на запись сообщений в каталог очереди и на чтение конфигурационных баз, таких как aliases.db. Причём в Sendmail реализован некоторый защитный механизм, позволяющий снизить возможность проблем неправильной настройки. В частности, принимая решение о доставке сообщения, Sendmail руководствуется файлом псевдонимов и данными пользовательских .forward-файлов (если они используются). Следовательно, он должен обладать правами на их чтение. В то же время право на запись в .forward-файл должен иметь только его владелец, иначе этот файл будет проигнорирован. Аналогично права на запись в файл aliases должны иметь только пользователи, перечисленные в списке доверенных (параметр TrustedUser).
Говоря о правах доступа, сразу скажу о том, с какими правами обрабатываются перенаправления. Если .forward-файл настроен на передачу сообщения на стандартный вход некоторой программы (по конвейеру), то процесс Sendmail, выполняющий это перенаправление, получит права пользователя-владельца .forward-файла. Аналогично ссылки, содержащиеся в файлах, подключенных к базе aliases с помощью конструкции :include:, будут обрабатываться с правами владельца соответствующего include-файла. Если его владельцем является root, то обработка выполняется с правами пользователя, указанного в конфигурации опцией DefaultUser (в mc-файле директива define(`confDEFAULT_USER’, `имя_пользователя’), по умолчанию используется mailnull).
В первой части статьи уже упоминалось, что по умолчанию во FreeBSD создаются две конфигурации Sendmail – sendmail.cf для работы в режиме MTA, и submit.cf для процесса, выполняющего роль MDA, то есть для доставки сообщений от локальных пользователей. Сделано это для того, чтобы отказаться от suid-бита на пользователя root. Теперь Sendmail обходится suid-битом на группу smmsp, что позволяет выполнять запуск процесса с правами локального пользователя (обратите внимание, что права на очередь clientmqueue должны принадлежать пользователю и группе smmsp). Но процессы, порождаемые для обработки внешних соединений, по умолчанию выполняются с правами суперпользователя.
Root иль не root?
Работа с правами root делает сервер MTA соблазнительной мишенью для взломщиков, поскольку, проникнув в систему с правами этого процесса, можно получить практически неограниченные возможности. Однако в конфигурационный файл Sendmail можно включить параметр, позволяющий настроить то, с какими правами MTA будет выполнять свою работу.
В частности, чтобы порождаемые основным процессом дочерние, выполняющие обработку конкретных соединений, исполнялись от имени непривилегированного пользователя, используется опция RunAsUser. Но для этого требуется решить несколько проблем.
Во-первых, чтобы разместить сообщение в очереди, пользователь, с правами которого будет запущен процесс, должен иметь возможность создавать новые файлы в соответствующем каталоге (по умолчанию – /var/spool/mqueue).
Во-вторых, если письмо предназначено для локальной доставки, процесс Sendmail должен быть способен вызвать программу локальной доставки (по умолчанию mail.local) с правами, достаточными для работы с почтовыми ящиками любых пользователей. Поскольку теперь LDA вызывается процессом, не обладающим правами root, нужно либо предоставить полный доступ непривилегированному пользователю к хранилищу почтовых ящиков пользователей, либо установить на mail.local бит suid.
В-третьих, этот процесс не сможет использовать данные в пользовательских .forward-файлах, либо должен быть обеспечен доступ на чтение к этим файлам.
То есть приходится учитывать целый ряд дополнительных ограничений, и в итоге безопасность может оказаться, наоборот, ослабленной. Впрочем, на почтовых шлюзах, где не практикуется предоставлять пользователям shell-доступ в свои домашние каталоги и право создавать .forward-файлы, подобное ограничение может иметь смысл. Поэтому приведу здесь последовательность действий, позволяющую этого добиться. Во-первых, добавьте такие строки в mc-файл:
define(`confRUN_AS_USER",`mailnull")dnl
define(`confFORWARD_PATH", `")dnl
Вторая строка отключает использование .forward-файлов. Также нужно соответствующим образом изменить права на каталог очереди и на содержащиеся в нём файлы (если таковые имеются), а также на используемые базы данных:
root# chown -R mailnull /var/spool/mqueue
root# chown mailnull aliases aliases.db access access.db
Далее, поскольку mail.local теперь будет вызываться не «рутовым» процессом, то придётся поставить на него suid-бит:
root# chmod 4555 /usr/libexec/mail.local
Иначе натолкнётесь на такую ошибку (в файле maillog):
May 24 17:24:31 host sm-mta[66054]: k4ODO0sN066053: to=<user@server.ru>,
delay=00:00:31, xdelay=00:00:31, mailer=local, pri=65423, relay=local,
dsn=4.3.0, stat=Deferred: 451 4.3.0 lockmailbox /var/mail/user failed;
error code 75
|
Если у вас есть подключаемые фильтры (например, clmilter, обеспечивающий работу антивируса ClamAV), то нужно будет также позаботиться о необходимых правах при обращении к этим программам. Например, попытка запуска «по умолчанию» обернётся сообщением об ошибке:
Starting: sendmail 451 4.0.0 /etc/mail/sendmail.cf: line 1670: Xclmilter:
local socket name /var/run/clamav/clmilter.sock unsafe: Permission denied
|
Чтобы его избежать, нужно позволить пользователю, с правами которого работает Sendmail, осуществлять запись в указанный сокет.
После всех этих корректировок осталось пересобрать конфигурационный файл и перезапустить сервер:
root# cd /etc/mail; make install restart
Теперь процессы sendmail, обрабатывающие входящие соединения, будут работать с правами пользователя mailnull, в чём можно убедиться, просмотрев вывод команды ps:
serg$ ps -axouser,command | grep sendmail
root sendmail: accepting connections (sendmail)
mailnull sendmail: startup with w83-193.abo.wanadoo.fr (sendmail)
mailnull sendmail: server [220.69.161.120] cmd read (sendmail)
|
Как видите, вполне можно обеспечить работу Sendmail с правами обычного пользователя. Однако это ослабит защиту на других участках – suid-бит на файле mail.local, дополнительные права на запись в UNIX-сокеты внешних фильтров и т. д. Так что подобная настройка весьма неоднозначна. Впрочем, окончательное решение принимать вам.
Собираем информацию
Прежде чем перейти к вопросам повышения производительности почтового сервера, пару слов скажу о средствах мониторинга его работы. Ведь чтобы оценить эффект от изменения, необходимо получить некоторые количественные показатели «до» и «после», которые и будут сравниваться. Да и вообще, регулярный мониторинг работы сервера лишним никогда не будет.
Log-файлы
Первое место, куда следует заглянуть, чтобы проконтролировать работу любого сервиса, – это лог-файлы. Sendmail по умолчанию ведёт журнал своей работы в файле /var/log/maillog. Если быть точнее, то используется система Syslog, куда выводятся рабочие сообщения с facility «mail». Дальнейшее уже определяется настройками в /etc/syslog.conf.
Уровни сообщений задаются в опции LogLevel (в mc-файле директивой define(`confLOG_LEVEL’,`9’), где 9 – уровень, используемый по умолчанию. Обычно используется значение от 0 (минимальное количество информации) до 10 (достаточно подробный вывод). Значения выше 10 обычно используются лишь для отладки. В ряде случаев может оказаться полезным уровень 12, на котором протоколируются все SMTP-соединения.
Не забывайте, что ведение лог-файлов создаёт дополнительную нагрузку на дисковую подсистему. На загруженных серверах, по возможности, выносите каталог с лог-файлами на отдельный жёсткий диск либо используйте способность Syslog отправлять сообщения по сети на удалённый хост.
Статистика
Помимо лог-файлов полезной может оказаться и утилита mailstats (рис. 1). Она выводит число принятых и отправленных сообщений (msgsto и msgsfr соответственно), входящий и исходящий трафик (bytes_to и bytes_from), число отклонённых сообщений (в соответствии с базой access). Последние две строки – итоги (строка T) и количество соединений (строка C).
Рисунок 1. Работа утилиты mailstats
Для автоматической обработки может быть полезен запуск с ключом -P, когда не выполняется дополнительное форматирование:
root# mailstats –P
1148036405 1148543708
0 0 0 301 434 0 0 0 prog
1 0 0 43 506 0 0 0 *file*
3 862 51985 2495 129910 24 0 0 local
5 2938 134398 578 50810 513 0 0 esmtp
T 3800 186383 3417 181660 537 0 0
C 16764 720 8149
|
Запуск с ключом -p (обратите внимание на регистр символа) выводит аналогичную информацию, одновременно очищая накопленную статистику. Этим можно воспользоваться, например, для автоматической ежедневной, еженедельной или ежемесячной (в зависимости от нагрузки и требуемой оперативности) обработки статистических данных.
Состояние хостов
В процессе работы Sendmail может собирать статистику доступности хостов-получателей, которую в дальнейшем можно просмотреть с помощью команды hoststat (или sendmail ?bh, что то же самое). Для этого в конфигурационном файле укажите имя каталога (абсолютный путь или путь относительно каталога очереди), в котором будет сохраняться статистическая информация:
define(`confHOST_STATUS_DIRECTORY", `.hoststat")dnl
Cпустя некоторое время вы сможете просмотреть состояния хостов, к которым Sendmail обращался. Так можно получить список хостов, возвративших ошибку «Operation timed out»:
root# hoststat | grep timed
mqg.com 00:58:43 Deferred: Operation timed
dila.com 00:57:28 Deferred: Operation timed
hideakifan.com 00:56:12 Deferred: Operation timed
mxfilter.bayou.com 00:02:33 Deferred: Operation timed
|
Здесь выводится три столбца – имя домена в первом, его состояние в третьем, и между ними – сколько времени прошло с момента определения этого состояния. Sendmail использует эту информацию, чтобы не пытаться установить соединение с сервером, который пару минут назад был недоступен (период, в течение которого состояние хоста считается достоверным, определяется опцией Timeout.hoststatus (define(`confTO_HOSTSTATUS’) в mc-файле), по умолчанию используется значение 30 минут). Однако и системный администратор может получить здесь полезную информацию.
Состояние очереди
Пожалуй, можно считать, что от эффективности обработки почтовой очереди во многом зависит качество работы всего сервера, поскольку именно она создаёт основную нагрузку на дисковую подсистему. В то же время очередь – один из основных показателей этого самого качества. Ведь в неё попадают сообщения, которые из-за каких-то проблем не удалось отправить сразу (в нормальном режиме работы сообщение в очередь, конечно же, попадает, но ненадолго). И чем больше сообщений в очереди, тем больше проблем, которые требуют внимания.
Состав очереди может быть просмотрен с помощью команды mailq (см. рис. 2). Выводимая информация позволяет узнать, сколько сообщений находится в данный момент в очереди, когда они туда попали, от кого и к кому направляются. Почти всегда в очереди можно обнаружить несколько сообщений от MAILER-DAEMON для каких-нибудь загадочных получателей в экзотических доменах – скорее всего, это сообщения об ошибке, сформированные на письма, отправленные спамерами.
Рисунок 2. Очередь сообщений
Общие вопросы эффективности
Производительность работы любой программы определяется тем, насколько эффективно она использует доступные ей ресурсы. Условно ресурсы можно разделить на «дешёвые» и «дорогие». В случае с Sendmail «цена» ресурса определяется прежде всего затратами времени на работу с ним. Например, оперативную память можно отнести к дешёвым, поскольку обращение к ней выполняется максимально быстро. А, скажем, файловая система на жёстком диске относится к дорогим ресурсам, поскольку на перемещение головок винчестера требуется весьма ощутимое по процессорным меркам время.
Таким образом, в первом приближении основной задачей повышения эффективности можно считать задачу минимизации обращений к диску. Однако зачастую «узким местом» становится и сетевое подключение. Естественно, письма должны приниматься и отправляться (для этого, собственно, сервер и существует), поэтому основной способ повысить пропускную способность сети – максимально снизить «накладные» расходы, такие как DNS-запросы. Впрочем, некоторые другие параметры (например, значения тайм-аутов) также могут повысить производительность. Об этом и поговорим чуть подробнее.
Но сперва нужно заметить, что по умолчанию конфигурация Sendmail имеет достаточно разумные параметры, так что если загрузка вашего сервера не подходит вплотную к максимальным возможностям «железа», то, скорее всего, дополнительная настройка либо не обеспечит сколько-нибудь заметного эффекта, либо будет связана с необоснованной потерей функциональности. Поэтому прежде чем приступать к изменению конфигурации, вспомните «золотое правило» системного администратора: «Не сломалось – не чини!».
Вездесущий DNS
Как известно, неправильно настроенные или нестабильно работающие серверы DNS являются источниками очень многих проблем в работе других служб. Электронная почта – не исключение, и её устойчивая работа также во многом зависит от качества работы DNS-сервера. Ведь в процессе обработки сообщений выполняется большое число DNS-запросов: разрешение имён доменов отправителя и получателя; обратное разрешение IP-адресов для проверки хоста, пытающегося установить соединение, по базе access; и так далее. В итоге любые задержки в работе DNS влияют и на скорость работы SMTP-сервера, вынужденного простаивать в ожидании ответов.
Поэтому рекомендуется запускать DNS-сервер (в идеале – кэширующий, обслуживающий только запросы почтового сервера) на той же машине, на которой работает сервер SMTP. В случае высокой загруженности почтового сервера DNS можно вынести на отдельный компьютер, но в любом случае критичным остаётся возможность организовать быстрое и максимально надёжное соединение. Благодаря этому можно будет значительно снизить задержки при обращении к DNS-серверу, что в свою очередь позволит обслуживать большее число запросов в единицу времени.
В ряде случаев, например, при работе через низкоскоростное соединение, для повышения производительности почтового сервера можно сократить до минимума использование DNS, например, отключив канонизацию адресов:
FEATURE(nocanonify)
Но, поскольку в данном случае адреса не будут преобразовываться к стандартному виду, при таких настройках сервер должен работать в сотрудничестве со Smart-хостом, который будет выполнять все необходимые корректировки. В противном случае возможны проблемы при доставке ваших сообщений.
Есть и более кардинальный способ:
FEATURE(nodns)
Так в чём задержка?
Дополнительной оптимизации вы достигнете, если с установите более подходящие для вашего конкретного случая значения тайм-аутов соединений. Используемые по умолчанию значения довольно велики (например, время ожидания ответа на команду HELO составляет 5 минут). Правда, учтите, что в большинстве случаев они соответствуют принятым стандартам и рекомендациями (в частности, RFC 2821). К тому же проблемные ситуации достаточно редки при нормальной работе, так что снижение большинства тайм-аутов (например, Timeout.quit, определяющий время ожидания команды QUIT) практически не скажется на общей производительности сервера.
Но в ряде случаев изменение тайм-аутов может оказаться полезным. Например, в наши дни протокол IDENT (см. врезку «Протокол IDENT»), предназначенный для идентификации владельца сокета, используется редко из-за его неэффективности и недостоверности. Следовательно, нет никакого смысла ожидать результата идентификации, и можно смело устанавливать соответствующий параметр в ноль: define(`confTO_IDENT’,`0’).
Некоторые из опций, отвечающих за установку различных тайм-аутов, приведены в таблице 1.
Таблица 1. Опции тайм-аутов
Опция в cf-файле
|
Директива mc-файла
|
Описание
|
Timeout.helo
|
define(`confTO_HELO", `знач")
|
Время ожидания команды HELO
|
Timeout.mail
|
define(`confTO_MAIL", `знач")
|
Время ожидания команды MAIL FROM:
|
Timeout.rcpt
|
define(`confTO_RCPT", `знач")
|
Время ожидания команды RCPT TO:
|
Timeout.quit
|
define(`confTO_QUIT", `знач")
|
Время ожидания команды QUIT
|
Есть ещё группа тайм-аутов, отвечающих за работу почтовой очереди, о них мы поговорим в следующем разделе.
Кто последний?
Почтовая очередь оказывает в большинстве случаев наибольшее влияние на общую производительность сервера. Поэтому чуть подробнее рассмотрим вопросы, связанные с ней.
Организация очереди
Очередь сообщений организована в виде каталога в файловой системе. По умолчанию используется /var/spool/mqueue (clientmqueue для процессов, вызванных локальными пользователями). В ней можно найти несколько типов файлов:
- qf* – заголовочный файл сообщения. Содержит информацию, предназначенную для доставки и обработки сообщения (заголовок), а также некоторую служебную информацию, используемую программой обработки очереди (приоритет, время размещения в очереди). Значения некоторых строк представлены в таблице 2.
- df* – в этих файлах хранятся почтовые сообщения. Соответствие с заголовочным файлом устанавливается по оставшейся части имени файла.
Таблица 2. Строки qt-файла очереди
Строка
|
Пример
|
Описание
|
T
|
T1148293041
|
UNIX-время постановки сообщения в очередь
|
K
|
K1148299145
|
UNIX-время последней обработки сообщения
|
N
|
N5
|
Количество выполненных попыток отправки сообщения
|
P
|
P415878
|
Рассчитанный приоритет (см. ниже)
|
S
|
SMAILER-DAEMON
|
Имя отправителя
|
M
|
MDeferred: Connection refused by mail.darbs.lv.
|
Сообщение о причине неудачной доставки в прошлый раз
|
H?
|
H??To: <info@job.lv>
|
Строки заголовка сообщения
|
В процессе обработки создаются и другие временные файлы (например, xf*, содержащие сведения об ошибках, возникающие в процессе передачи сообщения).
Приоритеты
Для сообщений, поставленных в очередь, можно назначать различные приоритеты. Это достигается с помощью следующей конфигурационной директивы (используется по умолчанию):
define(`confQUEUE_SORT_ORDER", `Priority")dnl
Чем большее значение получает сообщение, тем позже оно будет обрабатываться. Рассчитывается значение приоритета таким образом:
Приоритет = Размер_сообщения_в_байтах –
(ClassFactor * Класс_сообщения) +
(RecipientFactor * Кол-во_получателей) +
(RetryFactor * Кол-во_попыток_отправки)
где коэффициенты ClassFactor, RecipientFactor и RetryFactor задаются в файле конфигурации (в формуле указаны их имена в cf-файле) и определяют «вес» класса сообщения, количества получателей и числа предыдущих попыток доставки.
Класс определяется значением поля Precedence, а его числовое значение задаётся строками «P» в конфигурационном (cf) файле, например:
Pbulk=-60
Pfirst-class=0
Pjunk=-100
Pspecial-delivery=100
Таким образом, в первую очередь будут отправляться небольшие сообщения, имеющие минимальное число получателей и наибольший класс, и которые не имеют «тяжёлой кармы» безуспешных попыток доставки в прошлом. Но на практике механизм приоритетов не очень сильно влияет на общую работу сервера. Конечно, более быстрая доставка небольших сообщений способствует «разгрузке» очереди, не позволяя ей чрезмерно вырасти за то время, пока будет выполняться обработка мегабайтного послания. Но, с другой стороны, отправитель письма, имеющего достаточно большой объём, тоже вправе рассчитывать на его своевременную доставку. Тем более что на выстраивание сообщений согласно приоритету требуются дополнительные ресурсы.
Можно сделать вывод, что использование приоритетов может быть полезно разве что на сильно загруженных серверах, имеющих неравномерную загрузку (что даст гарантию отправки больших сообщений в период «затишья») при отсутствии жёстких требований по срокам доставки корреспонденции.
Другие виды сортировок
Помимо рассмотренной выше сортировки по приоритету, опция QueueSortOrder может принимать ещё три значения – Host, Filename и Time. В первом случае очередь будет обрабатываться в алфавитном порядке хостов-получателей, что позволяет несколько сэкономить на установке соединения, поскольку повышается эффективность кэша хостов (см. hoststat).
Во втором случае очередь будет обрабатываться в порядке размещения файлов в каталоге, что снизит нагрузку на файловую систему, поскольку не требуется предварительно считывать файлы для определения приоритетов/хостов.
При установке опции в значение «Time» сортировка осуществляется в зависимости от времени нахождения сообщения в очереди.
Есть ещё вид сортировки – Random. В этом случае перед обработкой очереди список файлов в каталоге будет перемешиваться случайным образом. Благодаря этому достигаются преимущества метода Filename и снижается вероятность того, что несколько одновременно запущенных процессов будут пытаться отправить одно и то же сообщение.
Ветвления
Sendmail позволяет организовать параллельную обработку очереди, когда для каждого сообщения вызывается свой процесс. Определяется это опцией ForkEachJob (директива define(`confSEPARATE_PROC’) в mc-файле). Это снизит общее время обработки сообщений в очереди: пока одни процессы будут ожидать ответа удалённых серверов, другие могут выполнять дисковые операции или использовать ресурсы процессора.
Но, как и у любой медали, здесь есть оборотная сторона: большое число одновременно работающих процессов создаёт дополнительные «непроизводственные» затраты на переключение процессов и обслуживание сетевых соединений. К тому же при параллельной работе процессы sendmail не смогут воспользоваться кэшем состояния хостов (hoststat). В этот кэш при последовательной обработке очереди заносится информация о недоступных хостах, и попытки отправить другие сообщения на эти хосты не предпринимаются.
В случае же параллельной обработки каждый процесс самостоятельно проверяет работоспособность хоста получателя, так что при недоступности одного из удалённых серверов будут предприниматься попытки доставки каждого адресованного ему сообщения.
Режимы обработки очереди
В Sendmail предусмотрено несколько режимов обработки очереди, задаваемых директивой define(`confDELIVERY_MODE’):
- background – используемый по умолчанию режим фоновой отправки. В этом случае Sendmail сначала получает сообщение от клиента, помещает его в очередь и возвращает клиенту ответ «250 ОК». После чего сообщение доставляется в фоновом режиме.
- interactive – интерактивный режим. Sendmail сразу пытается доставить сообщение, не разрывая соединение с отправителем. Если доставка выполняется успешно, отправитель получает ответ «250 OK» и отсоединяется. В очередь письмо помещается только в том случае, если его не удаётся доставить сразу. В данном режиме, особенно если основная масса получаемых сообщений предназначена для локальной доставки, существенно снижается нагрузка на дисковую подсистему. Но при этом отправитель вынужден удерживать соединение всё то время, пока будет предприниматься первая попытка доставить сообщение.
- queue – только в очередь. В этом режиме попытка немедленно отправить сообщение вообще не будет предприниматься. MTA будет только помещать письмо в очередь. Отправка будет осуществляться уже обработчиком очереди. Может быть полезно в случае, если перед отправкой требуется установить интернет-соединение (например, коммутируемое).
- defer – отложить доставку. Аналогичен режиму queue, но при этом подавляются также и любые обращения к сети (например, запросы DNS).
Наборы очередей
Вместо общего каталога для всех файлов очереди в Sendmail можно использовать наборы очередей. Например, директива define(`QUEUE_DIR’, `/var/spool/mqueue/*’) заставляет Sendmail все каталоги в mqueue рассматривать как очереди и соответственно обрабатывать их. При этом для размещения нового письма конкретный каталог будет выбираться случайным образом, что гарантирует определённую «равномерность» заполнения очередей. Есть возможность и более «интеллектуально» размещать различные сообщения – см. врезку «Группы очередей».
Если имена каталогов в mqueue будут начинаться с qf, df, xf, то Sendmail будет использовать их для размещения соответствующих файлов. Если при этом каталоги разнести по разным жёстким дискам, то можно повысить скорость обработки каждого сообщения. Причём некоторые файлы (например, xf) могут быть безболезненно размещены в памяти (используя tmpfs).
Помимо снижения количества сообщений в отдельных каталогах, наборы очередей позволяют осуществлять параллельную обработку нескольких очередей, что положительно сказывается на производительности.
«За выслугу лет»
Ещё одним полезным параметром является MinQueueAge. С его помощью можно указать, сколько сообщение должно «отлежаться» в очереди, прежде чем будет предпринята следующая попытка доставить его. Такая странная на первый взгляд опция позволяет повысить время отклика очереди, установив сравнительно небольшой интервал её обработки (например, 5 минут), но без слишком частых попыток отправить «застрявшее» сообщение. Сделать это можно следующим образом:
define(`confMIN_QUEUE_AGE", `30m")
Если теперь процесс-обработчик очереди запустить с параметром -q5m, то очередь будет обрабатываться каждые 5 минут, но при каждом запуске будут отправляться только те сообщения, попытка отправки которых предпринималась не менее получаса назад.
Ограничения по загрузке
Механизм обработки очереди в Sendmail предусматривает ещё один метод предотвращения перегрузки сервера. Сразу нужно заметить, что это не средство оптимизации работы Sendmail, а своего рода «аварийный клапан», и если он срабатывает достаточно регулярно – значит, нужно что-то делать для повышения производительности.
Речь идёт о двух опциях – QueueLA и RefuseLA (в mc-файле – define(`confQUEUE_LA’, `знач’) и define(`confREFUSE_LA’, `знач’) ) соответственно). Первая из них при превышении средней загрузки сервера (Load Average) сверх указанной переводит Sendmail в режим «только очередь» (queue), когда для входящих сообщений не предпринимаются попытки доставить их немедленно, а выполняется только размещение в очереди.
Вторая опция даёт указание отклонять новые соединения, если средняя загрузка системы превышает указанное значение. О том, что это произошло, можно узнать по записям «Sendmail rejecting connecting, load average too high» в /var/log/maillog.
Оптимизация очереди
Основная проблема, связанная с очередью, – это её чрезмерное разрастание. Когда по тем или иным причинам (проблемы при доставке или поступление новых сообщений с большей скоростью, чем сервер может обработать) в каталоге очереди скапливается большое число файлов, система начинает тратить слишком много времени на их предварительную обработку (поиск, чтение, расчёт порядка обработки согласно приоритету и т. д.).
Если проблема носит регулярный характер, то более эффективным, по-видимому, будет устранение её причины («узкий» интернет-канал, недостаточно быстрый процессор, спам-рассылки со стороны ваших клиентов). Учитывая постоянно возрастающие объёмы пересылаемой корреспонденции, попытки выиграть несколько процентов производительности за счёт оптимизации работы с очередью (возможно, ценой снижения функциональности или надёжности) могут рассматриваться лишь как временная мера.
Тем не менее рассмотрим основные приёмы, позволяющие добиться более быстрой работы с очередью.
Во-первых, рассмотренные выше режимы сортировки очереди позволяют несколько перераспределить нагрузку в зависимости от того, в каких ресурсах испытывается недостаток. Так, порядок Filename несколько снижает нагрузку на дисковую подсистему; Host – оптимизирует использование сетевых ресурсов и т. д.
Во-вторых, подумайте над тем, чтобы вместо одной очереди использовать наборы. Меньшее число файлов в конкретном каталоге позволит более быстро и с меньшими затратами выполнять поиск нужного файла.
В-третьих, на сильно загруженных серверах имеет смысл вынести каталог очереди на отдельный жёсткий диск или даже на RAID-массив, с тем чтобы максимально повысить скорость доступа к файлам. Если использовать набор очередей, разнеся различные каталоги по нескольким дискам, то можно достичь ещё более высоких показателей скорости работы.
Нужно сделать и одно предостережение – как бы ни казалось заманчивым размещение очереди в оперативной памяти (используя tmpfs), этого не следует делать. Ведь сообщения для того и помещаются в очередь, чтобы гарантировать их сохранность при неожиданных проблемах с сервером, вплоть до перезагрузки. Если же в вашем случае надёжностью доставки можно пренебречь (думаю, это верно разве что при рассылке спама), то можно отключить опцию SuperSafe (define(`confSAFE_QUEUE’, `False’)).
А вот размещение в tmpfs конфигурационных файлов (таких как aliases.db, access.db) может быть весьма полезно – ведь в этом случае Sendmail не будет каждый раз обращаться к диску для «разрешения» псевдонима или поиска адреса отправителя в базе access. Впрочем, в грамотно работающей системе эти данные и так должны преимущественно находиться в дисковом кэше (если, конечно, нехватка оперативной памяти не вынуждает систему снижать размер кэша до предела).
Методы «авральной» работы
И всё же порой случается, что очередь заполняется неимоверным количеством сообщений. Например, причиной подобного может явиться прерывание соединения с Интернетом на несколько часов. Пока канал будут «поднимать», нетерпеливые пользователи накидают уйму писем, которые после восстановления соединения могут вызвать резкий всплеск нагрузки на сервер. Если учесть, что в это же время на ваш MTA обрушится масса внешних соединений (удалённые серверы ведь тоже накапливали всё это время письма, адресованные вам, и теперь поспешат от них избавиться), то ситуация может стать близкой к катастрофической.
Наиболее простым и почти что «стандартным» способом решения подобных проблем можно считать перенос накопившихся файлов очереди в отдельный каталог с последующей его обработкой «вручную». Это позволяет максимально быстро вернуть сервер в «штатный» режим.
Серверы на «чёрный» день
К сожалению, время от времени любая техника даёт сбои. Чтобы смягчить последствия временной недоступности вашего сервера или интернет-соединения, сохранив для удалённых пользователей возможность по-прежнему отправлять вам почту, можно предусмотреть резервный почтовый сервер.
Почтовый сервер, выполняющий роль резервного, должен быть настроен на обработку почты, поступающей для другого домена. Ну и естественно, на него должна указывать MX-запись для обслуживаемого домена, имеющая низший приоритет. В этом случае при невозможности доставить почту на основной сервер будет использоваться резервный (см. рис. 3).
Рисунок 3. Схема работы с резервным сервером
Иногда полезно предусмотреть и «обходной манёвр» для обратной проблемы – когда ваш сервер не может отправить почту удалённому. По умолчанию в этом случае вся отправляемая корреспонденция должна оставаться в очереди, и периодически должны предприниматься попытки её доставить. Однако в результате очередь сообщений может оказаться перегруженной, и почтовый сервер будет тратить слишком много времени на её обслуживание. Для решения этой проблемы предусматривается так называемый FallBack-сервер. Так, если основной сервер содержит в своей конфигурации такую строку:
define(`confFALLBACK_MX", `адрес_сервера")
то при возникновении проблем с отправкой сообщения оно будет «сбрасываться» на указанный адрес, который возьмёт на себя дальнейшую заботу о его судьбе (рис. 4). Технически адрес FallBack-сервера добавляется в конец списка хостов-получателей, определённых на основании MX-записей. То есть это работает так, как если бы каждый удалённый сервер имел ещё одну MX-запись с минимальным приоритетом, указывающую на FallBack-сервер.
Рисунок 4. Схема работы с FallBack-сервером
Продолжение следует…
Итак, Sendmail предоставляет достаточно широкие возможности по гибкой настройке работы для повышения эффективности, надёжности и безопасности. В большинстве случаев дополнительная настройка сервера выглядит излишней, но в условиях дефицита ресурсов некоторая оптимизация может оказаться весьма полезной.
Впереди у нас ещё одна, последняя, тема – взаимодействие Sendmail со сторонними программами. Например, эта программа позволяет фильтровать сообщения с помощью так называемых milter. Чтобы не превратить свой сервер в открытый релей и в то же время позволить всем вашим пользователям отправлять почту из любой точки мира, можно настроить smtp-аутентификацию с помощью Cyrus SASL. Об этом и поговорим.
Приложение
Протокол IDENT
Authentication Server Protocol (серверный протокол аутентификации), часто именуемый IDENT, был разработан для идентификации пользователя-владельца конкретного TCP-соединения. С его описанием вы можете ознакомиться в документе RFC 931 (который датирован январём 1985 года). В ответ на запрос в виде разделённых запятой локального (с точки зрения сервера) и удалённого портов сервер возвращает идентификационную информацию о владельце данного соединения.
Служба запускается на 113-м порту (в /etc/services определён как auth).
Так может выглядеть сеанс с сервером, где IDENT поддерживается:
serg$ telnet smtp.nekiyhost.ru 113
Trying 1.2.3.4...
Connected to mail.nekiyhost.ru.
Escape character is "^]".
25, 49973
25, 49973 : USERID : UNIX : mail
|
То есть вы вводите пару «порт сервера – порт клиента» (в примере предварительно было установлено соединение с 25-м портом сервера, «свой» порт можно узнать, например, с помощью sockstat), и сервер возвращает информацию о пользователе-владельце данного сокета.
В настоящее время польза от данного сервиса весьма сомнительная, поскольку возвращаемая информация может быть легко фальсифицирована. В связи с этим его использование не является обязательным для работы служб Интернета, и потому на многих серверах поддержка этого протокола отключается. Например, на системах FreeBSD эта служба по умолчанию закрыта (см. /etc/inetd.conf, строки auth).
Группы очередей
Sendmail позволяет распределять сообщения по различным очередям с группировкой по домену получателя. Например, чтобы выделить в отдельную очередь почту для mail.ru, yandex.ru и rambler.ru, необходимо выполнить следующие действия:
Добавить в mc-файл строки:
FEATURE(`queuegroup')
QUEUE_GROUP(`mails', `P=/var/spool/mqueue/mails, F=f')
Этими строками мы объявляем отдельную очередь для группы mails. Ключ F=f заставляет Sendmail запускать для обработки этой очереди отдельный процесс (выполнять вызов fork).
За «приписку» конкретных сообщений к группе mails отвечает файл access:
QGRP:mail.ru mails
QGRP:yandex.ru mails
QGRP:rambler.ru mails
Теперь почта для указанных доменов будет размещаться в собственной очереди.
«Русский экстрим»
Для иллюстрации предлагаю вам рассмотреть один практический пример. Имеется почтовый сервер, который уже не справляется с навалившейся на него нагрузкой, а денег на новый нет. Зато есть несколько «слабеньких» машин, которые можно использовать.
Один из вариантов решения – организовать «распределённый» почтовый сервер за счёт «разделения труда», когда несколько вспомогательных серверов принимают на себя часть нагрузки основного.
Схема нашего «сводного сервера» представлена на рис. 5.
Рисунок 5. Больше серверов – хороших и разных...
Основной сервер занимается взаимодействием с клиентами – принимает от них сообщения для отправки, размещает входящую корреспонденцию по почтовым ящикам пользователей, и т. д. То есть делает то, что и любой почтовый сервер. Но, чтобы ему было проще, предусмотрено несколько вспомогательных серверов.
Сервер, обозначенный на схеме как Smart-хост, берёт на себя заботу о доставке исходящих сообщений. Поскольку он имеет надёжную связь с основным сервером, то задержки при передаче ему почты будут незначительными. Благодаря этому затраты ресурсов основного сервера на отправку сократятся, поскольку никаких проблем, способных вызвать чрезмерное разрастание очереди, возникнуть не должно (не считая, конечно, выхода из строя самого Smart-хоста).
Ещё один вспомогательный сервер, теперь уже для облегчения участи Smart-хоста, – FallBack-сервер, задача которого – обрабатывать «проблемные» сообщения, которые Smart-хост не смог доставить. Благодаря этому и на Smart-хосте очередь должна оставаться минимальной.
Backup-сервер (на который должна указывать MX-запись с меньшим приоритетом) в рассматриваемой схеме выглядит не совсем уместно, будучи подключенным на тот же интернет-канал. Если организация располагает резервным интернет-соединением, то данный сервер следует подключить именно на него. Но даже в такой схеме его использование позволит разгрузить основной сервер. Для этого нужно на основном сервере установить небольшие значения тайм-аутов, а также «посильное» значение MaxDaemonChildren. В результате медленные, а также «избыточные» внешние соединения будут отклоняться, и их обслуживание возьмёт на себя Backup-сервер.
Есть ещё один приём балансировки нагрузки. Заключается он в том, что если домен имеет несколько MX-записей с одинаковым приоритетом, то для работы должна выбираться случайным образом одна из них, что обеспечивает равномерность распределения нагрузки между несколькими хостами.
Для Backup-сервера можно указать более приоритетную MX-запись, чтобы вся входящая почта поступала в первую очередь на него. При этом основной сервер сможет получать почту от Backup-сервера с меньшими издержками благодаря более быстрому и надёжному соединению. Но имейте в виду, что использование отдельного сервера для входящих соединений имеет один недостаток: этот сервер ничего не будет знать о существовании конкретных пользователей, следовательно, он будет принимать всю почту, адресованную на обслуживаемый домен, вместо того чтобы отклонять сообщения для несуществующих пользователей ещё на стадии команды RCPT TO.
Мы рассмотрели, скажем так, «предельный» случай. На практике можно варьировать его в весьма широких пределах в зависимости от наличия «лишних» компьютеров. Например, можно объединять на одной машине ряд задач (FallBack-сервер и Backup-сервер вполне уживутся на одном компьютере, особенно если он будет подключён на резервный интернет-канал) либо часть задач возлагать не на выделенный сервер, а на уже имеющийся (например, принт-сервер в локальной сети), если его ресурсы и режим безопасности позволяют это сделать, и т. д. И конечно же, обязательным является только основной сервер, все остальные – «опциональны».
- Супрунов С. Как работает Sendmail. Полезные подробности. Часть 1. //Системный администратор, №5, 2006 г. – С. 12-18. – http://www.samag.ru/cgi-bin/go.pl?q=articles;n=05.2006;a=01.
- Супрунов С. Как работает Sendmail. Полезные подробности. Часть 2. //Системный администратор, №6, 2006 г. – С. 18-25. – http://www.samag.ru/cgi-bin/go.pl?q=articles;n=06.2006;a=02.