Автосервис в Одинцово, 14 рабочих мест, март 2023 года. Клиенты жаловались, что счета приходят через полчаса после звонка, а часть писем не доходила вовсе. В очереди висело 1 248 сообщений. Я сначала пошёл по ложному следу — про чёрные списки, — а потом набрал одну команду, которая за минуту отрезала половину гипотез.
Очередь Postfix в Zimbra растёт: amavis, ClamAV и resolv.conf
«Мы отправили полчаса назад» — а письмо ещё не пришло
Эту жалобу почти никогда не формулируют как техническую. Её формулируют так: «клиент говорит, что не получил», «отправь ещё раз, вдруг дойдёт», «а можно я лучше в мессенджер скину». Почтовый сервер при этом работает, никто не ругается на ошибки, письма в итоге доходят — просто не тогда, когда надо.
Потом появляется вторая часть жалобы. Часть писем не доходит вообще, а через 5 суток отправителю падает уведомление о недоставке — по адресам, которые точно рабочие.
Если это про вас — почти наверняка у вас растёт очередь. Не пропадают письма, не блокируют домен, не ломается сервер. Письма стоят внутри вашего же сервера и ждут. Причин, дающих ровно такую картину, четыре, и снаружи они неразличимы.
Есть команда, которая за минуту отсекает две из четырёх. Называется qshape. Расскажу про неё на конкретном случае — и заодно про то, как я в этом же случае удалил 60 писем, которые ещё могли доехать.
Одинцово, март 2023: 1 248 писем в очереди
Автосервис на Красногорском шоссе, 14 рабочих мест: приёмка, два мастера-консультанта, склад запчастей, бухгалтерия. Zimbra 9.0.0 Open Source на Ubuntu 20.04, поставлена в 2021 году, около сорока гигабайт почты. Обслуживает их приходящий человек, который сам честно сказал: «я в почте не разбираюсь, я по компьютерам».
Жалоба на входе была ровно такая, как выше. Счета уходят к клиентам с задержкой, заявки от корпоративных заказчиков теряются, часть писем через несколько суток возвращается с ошибкой доставки.
Первое, что я сделал, — посмотрел размер очереди:
[zimbra@mail ~]$ zmqstat
deferred=1248
incoming=0
active=43
hold=0
corrupt=0
1 248 отложенных писем на контору из 14 человек. Это очередь, которая копится не первый день: задержки тут замечали и раньше, но массовыми жалобы стали с конца февраля, недели за три до звонка. И 43 штуки в активной: они прямо сейчас в обработке и не могут её закончить.
Сорок три в active — самая говорящая цифра из трёх. Активная очередь на маленьком сервере должна быть пустой почти всегда: письмо туда попадает на секунды. Если там постоянно висит несколько десятков — значит, обработка каждого письма занимает минуты, а не секунды. И искать надо не снаружи, а внутри цепочки обработки.
Ложная версия: «нас внесли в чёрные списки»
Я всё равно пошёл сначала не туда, и вот почему. Владелец сказал фразу, которая сбивает почти всех: «у нас проблемы в основном с крупными клиентами, у них там почта на больших сервисах». Из этого складывается стройная версия: наш IP попал в чёрный список или его придерживают серым списком, а мелкие получатели принимают сразу.
Версия проверяемая, и я потратил на неё 40 минут. Проверил адрес по десятку RBL — чисто. Посмотрел PTR — на месте, совпадает с именем сервера. Записи SPF и DKIM валидные, подпись проходит. Ни одного повода для блокировки.
А потом набрал команду, с которой надо было начать:
[zimbra@mail ~]$ qshape deferred | head -12
T 5 10 20 40 80 160 320 640 1280 1280+
TOTAL 1248 18 34 61 122 178 246 297 212 80
mail.ru 216 3 6 11 22 31 42 52 37 12
yandex.ru 186 2 5 9 18 27 38 43 32 12
gmail.com 97 1 3 5 10 14 19 23 17 5
autoservice.local 94 2 4 7 11 13 18 21 14 4
partner-detali.ru 71 1 2 4 7 10 14 17 12 4
...
Вот здесь версия про чёрные списки умерла. Очередь размазана ровным слоем по всем доменам пропорционально их доле в переписке — включая autoservice.local, то есть письма между своими же сотрудниками, которые вообще не покидают сервер. Девяносто четыре внутренних письма не могут висеть из-за чужого чёрного списка (autoservice.local — их внутренняя зона, наружу контора пишет с autoservice.ru). Значит, узкое место у нас.
Команда qshape — самый недооценённый инструмент в этой истории. Она рисует форму очереди: строки — домены получателей, столбцы — возраст писем в минутах. Читается она так:
- Один домен резко выделяется на фоне остальных — проблема на стороне получателя: серые списки, недоступный узел, переполненный ящик.
- Очередь размазана по всем доменам — проблема у вас.
- В очереди есть ваши собственные домены — проблема точно у вас, и точно не в сети.
- Много писем в правых столбцах — они лежат давно, и через пять суток начнут возвращаться отправителям.
Четыре причины, дающие один и тот же симптом
Когда стало ясно, что дело внутри, круг сузился до четырёх вариантов. Все четыре выглядят снаружи одинаково. Письма стоят, потом медленно уходят.
Подвисший антивирусный фильтр
Письмо в Zimbra не летит от отправителя к получателю напрямую. Маршрут такой: клиент сдаёт письмо на 25 или 587, дальше внутренняя обработка и планировщик, затем письмо уходит на 127.0.0.1:10024 службе amavisd, та зовёт ClamAV и SpamAssassin, и возвращает письмо обратно на порт 10025 — для окончательной раскладки в ящик по LMTP на 7025.
Точка отказа тут одна. Порт 10024.
В настройках транспорта smtp-amavis заложен таймаут 20 минут и параметр max_use=20: после двадцати писем экземпляр перезапускается. Если amavisd отвечает медленно, письмо застревает ровно посередине маршрута и висит эти самые двадцать минут. Отсюда и берутся жалобы «пришло через полчаса». Смотреть надо в /opt/zimbra/log/amavis.log и на вывод zmamavisdctl status.
Просроченный ClamAV
Частный и самый противный случай предыдущего пункта. Движок с устаревшими базами или устаревшей версией начинает отдавать ошибку вместо вердикта, и amavisd честно откладывает письмо, вместо того чтобы пропустить его непроверенным. Встаёт всё сразу: входящая, исходящая, внутренняя. Проверяется одним листингом /opt/zimbra/data/clamav/db/ — по датам файлов main.cvd и daily.cvd.
Битый /etc/resolv.conf
Служба доставки для каждого письма выясняет, куда его нести, и делает это через DNS. Если в /etc/resolv.conf указан адрес, который молчит, каждое письмо оплачивает свою порцию таймаута — обычно 5 секунд на попытку, и попыток две. Симптом описывают одинаково: письма зависают в активной очереди на 15–20 минут. Сервер при этом абсолютно исправен. Ни одной ошибки в логах.
Разъехавшийся DNS изнутри и снаружи
Когда внутренние клиенты и внешний мир видят разные адреса одного имени, почта уходит наружу через периметр и пытается вернуться обратно тем же путём. Получается петля. Письма копятся сотнями по таймауту, и в qshape deferred видно много записей на собственные домены компании. Лечится настройкой раздельного DNS для внутренней зоны, а не правкой почтового сервера.
Проверьте у себя за две минуты
Четыре команды. Все безопасные, ничего не меняют, выполняются под пользователем zimbra.
# размер и форма очереди
zmqstat
qshape deferred | head -12
qshape active | head -8
# жив ли антивирусно-антиспамовый фильтр
zmamavisdctl status
tail -30 /opt/zimbra/log/amavis.log
# насколько свежие вирусные базы
ls -l --time-style=long-iso /opt/zimbra/data/clamav/db/
# кому сервер задаёт вопросы про имена
cat /etc/resolv.conf
| Что увидели | Что это значит | Насколько срочно |
|---|---|---|
В active висит больше десятка писем постоянно | Обработка одного письма занимает минуты. Узкое место внутри сервера | Сегодня |
В qshape deferred резко выделяется один домен | Проблема на стороне получателя, ваш сервер здоров | На неделе |
| Очередь размазана ровно, есть свои домены | Проблема у вас: фильтр, антивирус или разрешение имён | Сегодня |
| Файлам вирусных баз больше месяца | Обновления не приходят. Скоро встанет вся почта | Сегодня |
В resolv.conf адрес, который не отвечает на запросы | Каждое письмо оплачивает таймаут ожидания | Прямо сейчас, это правка на минуту |
| Много писем в столбцах справа | Они лежат больше суток. Через пять суток вернутся отправителям | Сегодня, потом будет поздно |
Про последнюю строку: срок жизни письма в очереди по умолчанию — пять суток. Всё это время сервер повторяет попытки с нарастающими паузами, а по истечении срока возвращает письмо отправителю с уведомлением о недоставке. Пять суток — это ваш запас времени. Не больше.
Что нашлось: антивирус с базами позапрошлого года
Проверка заняла три минуты и дала сразу два попадания.
[zimbra@mail ~]$ ls -l --time-style=long-iso /opt/zimbra/data/clamav/db/
-rw-r--r-- 1 zimbra zimbra 170868224 2021-11-08 04:12 main.cvd
-rw-r--r-- 1 zimbra zimbra 132096512 2021-11-09 04:15 daily.cvd
-rw-r--r-- 1 zimbra zimbra 294912 2021-11-08 04:12 bytecode.cvd
[zimbra@mail ~]$ tail -6 /opt/zimbra/log/freshclam.log
ERROR: Can't download daily.cvd from database.clamav.net
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.103.2 Recommended version: 0.103.8
[zimbra@mail ~]$ tail -4 /opt/zimbra/log/amavis.log
(!)ClamAV-clamd av-scanner FAILED: run_av error: timed out
(!)WARN: all primary virus scanners failed, considering backups
TIMING [total 1204 ms] ... SMTP pre-DATA-flush 0, DATA 1180
Базы от ноября 2021 года. Обновление перестало приходить полтора года назад — сервер сидел за роутером, где кто-то закрыл исходящие соединения «для безопасности», и служба обновления с тех пор молча падала в лог, который никто не читал.
Второе попадание — файл настроек разрешения имён:
[zimbra@mail ~]$ cat /etc/resolv.conf
nameserver 192.168.88.1
nameserver 213.xxx.xxx.4
search local
Первый адрес — роутер, живой. Второй — сервер имён прежнего провайдера, которого автосервис сменил осенью 2022 года. Он не отвечал ничем: ни отказом, ни ошибкой. Просто тишина до истечения таймаута. И на каждое письмо, где первый адрес не успевал ответить, накидывалось ожидание.
Обе причины работали одновременно. И усиливали друг друга: ClamAV отдавал вердикт с задержкой, amavisd держал соединение на 10024, qmgr ждал своё, а мёртвый resolver добавлял сверху собственные секунды на каждом письме.
Моя ошибка: шестьдесят писем, которые ещё могли доехать
Я починил обе причины за 1 час 20 минут. Открыл на роутере исходящие 443 и 53 для freshclam, дождался свежих daily.cvd, перезапустил amavisd через zmamavisdctl restart, вычистил мёртвый адрес из /etc/resolv.conf.
А потом сделал глупость. Очередь на 1 248 писем меня раздражала: она мешала смотреть, начали ли новые письма проходить нормально. И я по инерции набрал команду очистки отложенного. Секундное движение.
# то, что делать не следовало
postsuper -d ALL deferred
# postsuper: Deleted: 1248 messages
Правильный порядок был другой: сначала форсировать доставку всего, что накопилось, и только потом — при необходимости — чистить остаток.
# как надо было
postqueue -f # немедленная попытка доставить всё отложенное
sleep 300
zmqstat # смотрим, что осталось
qshape deferred | head # и почему именно оно осталось
Из тех 1 248 писем большая часть была мусором — повторы, автоматические уведомления, рассылки. Но около шестидесяти были живыми письмами возрастом меньше пяти суток: они бы доехали за первые же минуты после починки. Мы восстановили из них сорок одно — из папки «Отправленные» у самих сотрудников и из ящиков контрагентов. Остальные девятнадцать я просто потерял.
Вывод, который я с тех пор держу в голове как правило: очередь — это не мусор, это письма ваших клиентов. Удалять её можно только после того, как принудительная доставка прошла и вы посмотрели, что именно осталось лежать и почему. Команда postsuper -d ALL deferred сносит именно отложенные, аккуратнее общего варианта — но живые письма она сносит точно так же.
Тюнинг очереди: только через локальную конфигурацию
После починки я поправил параметры повторных попыток, потому что дефолтные для маленькой конторы великоваты: паузы между попытками растут по нарастающей и доходят до нескольких часов, а сотруднику надо, чтобы письмо ушло сейчас.
Здесь важен способ, а не значения. Основные файлы настроек службы доставки в Zimbra генерируются автоматически из шаблонов. Правки, внесённые в них руками, живут до ближайшего перезапуска конфигуратора, а потом бесследно исчезают — вместе с вашей уверенностью, что вы всё настроили.
# так правки переживут перезапуск и обновление
zmlocalconfig -e postfix_queue_run_delay=180s
zmlocalconfig -e postfix_minimal_backoff_time=180s
zmlocalconfig -e postfix_maximal_backoff_time=1800s
# применить
zmmtaconfig
# или, если хочется наверняка
zmcontrol restart
# проверить, что значение реально встало
zmlocalconfig -s postfix_queue_run_delay
Что здесь что. Первый параметр — как часто планировщик берёт письмо из deferred на новую попытку. Два следующих — нижняя и верхняя границы паузы для конкретного письма. Слишком маленькими их ставить не надо: агрессивные повторы к крупным сервисам выглядят подозрительно и дают обратный результат.
Отдельно про срок жизни письма в очереди. По умолчанию он пять суток, и я почти всегда оставляю как есть. Единственная ситуация, когда его укорачивают, — когда отправителю важнее быстро узнать о недоставке, чем дождаться. Для автосервиса это оказалось не так: клиент лучше получит счёт с задержкой, чем не получит вовсе.
Итог и где это перестаёт быть часовой работой
Цифры по Одинцово.
- Диагностика: 40 минут по ложному следу плюс 6 минут на четыре правильные команды.
- Починка: 1 час 20 минут, из них час — ожидание, пока скачаются свежие вирусные базы объёмом около 300 мегабайт.
- Задержка доставки после починки: с 15–20 минут до 4–9 секунд.
- Активная очередь: с 43 писем до нуля.
- Потеряно по моей вине: 19 писем из 1 248.
- Счёт клиенту: 12 000 рублей.
- Сколько это тянулось до звонка мне: полтора года в мягкой форме и три недели в острой.
Цена бездействия здесь считается не через простой. Через недополученные заказы. Владелец посчитал по своей учётной системе: за три острые недели сорвалось 11 согласований на запчасти, где ответ клиента ждали в тот же день. Средний чек по таким заявкам — около 22 000 рублей. Даже если сорвалась половина, это шестизначная сумма против счёта в 12 000.
Где ломается самостоятельная попытка
Последовательность я расписал целиком, и она несложная. Ломается обычно не она.
Первое. Соблазн начать с очистки очереди слишком велик — я сам ему поддался, будучи человеком с опытом. Очередь мешает смотреть, и рука тянется. После неудачной чистки вы теряете и письма, и информацию о причине.
Второе. Причины любят ходить парами. Починив ClamAV, вы увидите улучшение: задержка упадёт с 20 минут до 3. И решите, что справились. А 3 минуты вместо 4 секунд — это по-прежнему мёртвый адрес в /etc/resolv.conf, просто теперь он не так заметен.
Третье. Правки в файлах настроек службы доставки исчезают при следующем перезапуске конфигуратора. Человек настраивает, проверяет, радуется, а через две недели после планового обновления всё возвращается — и он уже не помнит, что именно правил.
Четвёртое. Просроченный антивирус в цепочке почты — это не только задержки. Полтора года почта автосервиса проверялась базами позапрошлого года, то есть фактически не проверялась. Это отдельный разговор, и он про безопасность, а не про очередь.
Если хотите понять, что происходит у вас: пришлите мне вывод zmqstat, первые двенадцать строк qshape deferred и листинг каталога с вирусными базами. По этим трём вещам я за день скажу, где именно затык и сколько времени займёт его убрать. В большинстве случаев это работа на пару часов — важно только не удалить очередь до того, как в неё посмотрели.
Частые вопросы
Можно ли просто отключить антивирусную проверку, чтобы почта пошла?
Технически да, и в аварийной ситуации на час это допустимо — например, когда надо выпустить накопившиеся счета до конца рабочего дня. Но как решение это ужасно: вы получаете почтовый сервер, который принимает вложения без единой проверки, и вспоминаете об этом ровно тогда, когда бухгалтерия открывает архив с шифровальщиком. Если антивирусный движок не обновляется, чинить надо обновление, а не выключать проверку. У автосервиса первопричиной было закрытое исходящее соединение на роутере — правка на пять минут, которую полтора года никто не сделал, потому что никто не читал лог обновлений.
Почему письма между своими же сотрудниками тоже висят в очереди?
Потому что внутреннее письмо проходит ровно тот же путь, что и внешнее: приём, обработка, отправка на антивирусно-антиспамовый фильтр, возврат и только потом раскладка в ящик. Оно не покидает сервер, но проходит все стадии внутри него. Поэтому внутренние письма в отложенной очереди — самый надёжный признак того, что проблема ваша, а не получателя. Мне эта строка в выводе qshape в Одинцово сэкономила часа полтора: она мгновенно убила версию про чёрные списки, которую иначе я бы проверял долго и с удовольствием.
Что будет с письмами, которые уже несколько дней лежат в очереди?
Пять суток сервер будет повторять попытки доставки с нарастающими паузами. Если причина устранена в пределах этого срока, письма уйдут — либо сами при очередной попытке, либо сразу, если дать команду принудительной доставки. По истечении пяти суток письмо возвращается отправителю с уведомлением о недоставке и из очереди исчезает. Отсюда практический вывод: обнаружив растущую очередь, у вас есть примерно пять дней на починку, прежде чем начнутся возвраты. Обычно этого хватает с запасом, если не тянуть.
Мы правили main.cf руками, и всё работало. Почему нельзя?
Работало до первого перезапуска конфигуратора. Основные файлы настроек службы доставки в Zimbra собираются автоматически из шаблонов при каждом старте, и ваши правки при этом просто затираются. Особенно неприятно то, что происходит это не сразу: правка живёт неделями, потом сервер перезагружают после обновления, и настройка тихо возвращается к исходной. Человек в этот момент ищет проблему где угодно, кроме собственной старой правки. Все изменения делаются через локальную конфигурацию — они переживают и перезапуск, и обновление версии.
Как понять, что причина в разрешении имён, а не в фильтре?
Есть простая проверка: замерить время ответа каждого сервера имён из списка. Возьмите любую утилиту опроса и обратитесь к каждому адресу по очереди, засекая время. Живой сервер отвечает за десятки миллисекунд, мёртвый — не отвечает вовсе и утилита сама сообщит о таймауте. Второй признак: если задержка составляет ровно круглые величины — пять секунд, десять, — это почти всегда таймаут, а не медленная работа. Настоящая перегрузка даёт разброс, а таймаут срабатывает по расписанию, всегда одинаково.
Оставить комментарий