У клиента-торговой компании на Дмитровском шоссе во вторник утром веб-почта начала отдавать 502 всем сразу. При этом mailboxd был жив, службы показывали Running, а у половины сотрудников почта на телефонах продолжала работать. Разбираю, как Zimbra маршрутизирует подключение через route lookup и memcached и почему эта связка рвётся тихо.
«no memcache server available»: 502 на всей веб-почте Zimbra
Когда 502 приходит на пустом месте
Есть аварии, которые выглядят страшнее, чем они есть. И есть такие, которые выглядят проще. Эта — вторая.
Картина: пользователи открывают веб-почту и получают короткую страницу с числом 502. Все, одновременно, без исключений. Админ идёт на сервер, смотрит службы — всё Running. Смотрит место — есть. Смотрит нагрузку — нормальная. Пробует почту на своём телефоне — а она работает. И вот здесь начинается самое интересное, потому что дальше человек обычно перезапускает всё подряд, что-то случайно чинит на двадцать минут, потом оно ломается снова, и к обеду сервер уже перезагружен трижды.
Если вы узнали себя — дело почти наверняка не в почте. Дело в том, что стоит перед почтой. У Zimbra между пользователем и его ящиком работают два посредника, о которых вспоминают в последнюю очередь: обработчик маршрутов на отдельном порту и маленький кэш, который хранит ответы этого обработчика. Когда рвётся связь между ними, ящики целы, письма на месте, а зайти нельзя.
Вторник, 20 февраля 2024-го: хронология
Торговая компания, склад и офис на Дмитровском шоссе, 48 рабочих мест, оптовые поставки инструмента. Заявки от клиентов приходят почтой — это важно для понимания цены вопроса. Zimbra 9 Open Source на своей виртуалке, обслуживает их подрядчик, меня позвали как второе мнение.
В ночь с понедельника на вторник у них было плановое окно: обновили ядро гостевой ОС и перезагрузили машину. Утром — 502.
Первое, что я открыл, — лог прокси, а не лог почты:
$ tail -n 5 /opt/zimbra/log/nginx.log
2024/02/20 09:04:11 [error] 3184#0: *217 no memcache server available,
cannot post request, client: 10.20.4.61, server: mail.example.ru,
request: "POST /service/soap/AuthRequest HTTP/1.1"
2024/02/20 09:04:12 [error] 3184#0: *219 no memcache server available,
cannot post request, client: 10.20.4.88, server: mail.example.ru
Строка исчерпывающая. Прокси не может достучаться до кэша и поэтому отказывается обрабатывать запрос. Клиенту это приезжает как 502.
Почему при этом работали телефоны: у тех, кто уже был подключён по IMAP, сессии держались, маршрут для них был получен раньше и лежал в кэше. Новый вход падал у всех. К десяти утра, когда часть телефонов перезашла, перестало работать и там.
Ложная версия: «просто mailboxd не поднялся»
Первая версия была не моя, но я её честно проверил, потому что она правильная в большинстве случаев. По статистике самая частая причина ошибок проксирования — это упавший mailboxd на целевом сервере: обработчик маршрутов не отвечает, прокси нечего сказать клиенту, тот получает отказ.
Версия ломается о два факта. Первый: службы были подняты. Второй, важнее, — обработчик маршрутов отвечал:
$ curl -k -s -o /dev/null -w "%{http_code}\n" https://$(zmhostname):7072/service/extension/nginx-lookup
401
Код 401 здесь не ошибка, а хороший знак: сервлет живой и требует данных авторизации, которых я ему не дал. Если бы mailboxd лежал, я бы получил отказ в соединении или пустоту.
Значит, обработчик работает, прокси работает, а между ними ничего не ходит. Осталось звено, которое я до этого момента вообще не рассматривал.
И вот здесь я сделал то, за что до сих пор себя ругаю. Нашёл на форуме обходной приём, применил его, не разобравшись:
zmprov mcf zimbraMailProxyMaxFails 0
zmproxyctl restart
Почта поднялась в 10:40 и проработала ровно сорок минут. В 11:20 502 вернулся. Я замаскировал симптом и потерял почти час, потому что перестал искать причину, решив, что уже нашёл. Приём рабочий — но он про допустимое число неудачных попыток, а не про адрес, по которому эти попытки идут.
Как Zimbra на самом деле пускает вас в ящик
Разложу цепочку по шагам, потому что без неё дальше ничего не читается.
- Пользователь приходит на публичный порт — 443 для веба, 993 или 995 для почтовых клиентов. Его встречает не почта, а прокси на nginx.
- Прокси не знает, где лежит ящик этого человека. Он делает внутренний HTTP-запрос к обработчику маршрутов — сервлету на почтовом сервере, порт 7072.
- Обработчик смотрит в каталог и отвечает: ящик такой-то обслуживается таким-то сервером.
- Ответ кладётся в memcached на порт 11211, время жизни записи по умолчанию — один час. Пока запись жива, прокси не дёргает обработчик повторно.
Смысл кэша прост: на тысяче подключений в минуту дёргать сервлет каждый раз дорого. Смысл аварии тоже прост: если кэш недоступен, прокси считает, что не может выполнить свою работу, и не пытается ходить к обработчику напрямую. Он отказывает.
Конфигурация прокси не пишется руками — она генерируется. Утилита zmproxyconfgen собирает /opt/zimbra/conf/nginx.conf из шаблонов и значений в каталоге при каждом старте прокси. Отсюда следует неприятное: правку, внесённую в атрибут месяц назад, вы увидите в работе не месяц назад, а при ближайшем перезапуске. Ровно это у нас и произошло.
Проверьте у себя за две минуты
Три строки. Первая — что видит прокси в логе, вторая — куда он собирается ходить, третья — что реально слушает порт кэша.
su - zimbra
grep -c "no memcache server available" /opt/zimbra/log/nginx.log
grep -A3 "memcache" /opt/zimbra/conf/nginx.conf | grep servers
ss -lntp | grep 11211
zmprov gs $(zmhostname) zimbraMemcachedBindAddress
Сопоставляем вторую строку с третьей, а четвёртую держим рядом как «эталон»: именно её значение генератор конфига подставит в nginx.conf при следующем перезапуске.
| Что увидели | Что это значит | Когда действовать |
|---|---|---|
| В логе ноль совпадений, адреса во второй и третьей строке совпадают | Связка целая | Ничего не трогать |
| Адрес в nginx.conf — IP хоста, а слушает 127.0.0.1 | Мина: сработает при первом же перезапуске прокси | До ближайшего планового окна |
| Слушает ::1 вместо 127.0.0.1 | Кэш поднят только на IPv6, сервлет с ним не свяжется | Сегодня |
| Третья строка пустая | memcached не запущен вовсе | Немедленно |
| Файла /opt/zimbra/conf/nginx.conf нет | Генератор конфига упал, прокси не стартовал | Немедленно |
| 502 был на прошлой неделе и «прошёл сам» примерно через час | Подпись залипшего маршрута в кэше после переноса или переименования ящика | На этой неделе |
Отдельно посмотрите список обработчиков маршрутов, которые прокси вообще видит:
$ zmprov garpu
https://mail.example.ru:7072/service/extension/nginx-lookup
Пустой вывод здесь — тоже диагноз: почтовый сервер не помечен как цель для поиска маршрута, и прокси не знает, у кого спрашивать.
Три способа порвать эту связку
Первый и самый частый — разъехавшиеся адреса. Кэш переводят слушать только на локальную петлю: это разумная мера, наружу его торчать нечему. А сгенерированный конфиг прокси продолжает ссылаться на прежний адрес хоста в локальной сети. Именно это было у нас: подрядчик закрывал замечания аудита в январе, а выстрелило 20 февраля, при первом после этого перезапуске.
$ zmprov gs $(zmhostname) zimbraMemcachedBindAddress
zimbraMemcachedBindAddress: 127.0.0.1
$ grep servers /opt/zimbra/conf/nginx.conf
servers 10.20.0.11:11211;
Лечится приведением к одному значению и перегенерацией конфига. Аварийный вариант, если разбираться некогда, — прописать адрес в шаблоне явно, закомментировав подстановку, и перезапустить прокси. Я так делать не люблю: правка в шаблоне переживает не каждое обновление, и через год кто-то будет искать её так же, как я искал причину.
Второй — кэш только на IPv6. Когда memcached поднят на ::1, сервлет не может к нему привязаться и падает с сообщением про то, что ему нужен хотя бы один сервер для подключения. Симптом в браузере тот же самый, а причина в одном символе конфигурации.
Третий — конфиг прокси не сгенерировался. Генератор бросает исключение, файл nginx.conf не создаётся, nginx не стартует. Тут 502 вы даже не увидите — будет отказ в соединении. Проверять руками:
$ /opt/zimbra/libexec/zmproxyconfgen
$ ls -l /opt/zimbra/conf/nginx.conf
-rw-r----- 1 zimbra zimbra 18244 Feb 20 11:52 /opt/zimbra/conf/nginx.conf
$ zmproxyctl restart
Залипший маршрут: отдельная история
Тот же кэш даёт вторую, гораздо более редкую и куда более обидную аварию. Она случается после переноса ящика между серверами в многосерверной установке.
Механика: маршрут для этого человека уже лежит в кэше и указывает на прежний сервер. Ящика там больше нет. Час — время жизни записи — пользователь будет получать ошибки или, что хуже, видеть пустую почту, а вы будете проверять сам ящик, который в полном порядке.
Ждать час не обязательно, кэш сбрасывается рестартом:
zmmemcachedctl restart
zmproxyctl restart
Издержка — все активные сессии переустановятся. На сорока восьми пользователях это незаметно, на шестистах уже ощутимо, поэтому переносы ящиков лучше планировать так, чтобы сброс кэша попадал в то же окно.
Практическое правило, которое я вывел для себя: любая работа, меняющая расположение ящика, заканчивается рестартом кэша. Не «если пожалуются», а всегда. Стоит десять секунд, экономит полдня разбирательств через неделю, когда связь между переносом и жалобой уже никто не проведёт.
Чем закончилось и во что обошлось
Настоящую причину я нашёл в 11:40, починил к 12:10. Непрерывного простоя в три часа не было: почта лежала с 09:00 до 10:40, потом сорок минут работала на моём обходном приёме, а с 11:20 до 12:10 лежала снова. Суммарно 2 часа 30 минут двумя кусками — и это та цифра, которую я считаю честной.
Заявки от клиентов у них приходят почтой, поэтому простой считается не в абстрактных человеко-часах. Реально работать не могли 30 человек: продажи, снабжение и бухгалтерия. 30 × 2,5 часа = 75 человеко-часов; час работы сотрудника вместе с налогами и рабочим местом компания считает по 520 рублей — это 39 000 рублей оплаченного и потерянного времени. Дороже вышло другое: из 34 писем с заявками одно было запросом на срочную отгрузку от постоянного клиента, он не дождался ответа и в тот же день купил у конкурента. Отгрузка на 173 000 рублей просто не состоялась.
| Статья | Цифра |
|---|---|
| Простой веб-почты | 2 ч 30 мин двумя кусками, рабочий вторник |
| Затронуто сотрудников | 48, из них 19 в отделе продаж |
| Заявок, увиденных с задержкой | 34 письма, три отгрузки сдвинулись на сутки |
| Оплаченное время сотрудников впустую | 75 человеко-часов × 520 ₽ = 39 000 ₽ |
| Несостоявшаяся отгрузка | 173 000 ₽ — клиент не дождался и ушёл к конкуренту |
| Мой счёт за второе мнение | 3 часа × 4 300 ₽ = 12 900 ₽ |
| Стоимость профилактики | 20 минут сверки адресов раз в месяц |
| Потеряно на ложной версии и обходном приёме | около 1 часа моего времени |
| Перезагрузок сервера за утро до моего приезда | 3, все бесполезные |
Занятно, что сама правка заняла восемь минут: привести адрес к одному значению, перегенерировать конфиг, перезапустить прокси. Ещё двадцать я стоял и смотрел, как люди заходят, — под нагрузкой, а не «у меня открылось». Всё остальное время ушло на то, чтобы понять, куда смотреть. Это типично для этого класса аварий и это же делает их дорогими — они не требуют квалификации, они требуют знания, что такая связка вообще существует.
Что мы поменяли после: вернули значение допустимых неудач к дефолтному (мой обходной приём я снял, он там был лишним), завели проверку соответствия адресов в ежемесячный чек-лист и добавили в мониторинг простой счётчик строк с этой ошибкой в логе прокси. Порог — единица. За два года сработал один раз, в декабре 2025-го, когда обновляли гипервизор и машина поднялась с другим набором интерфейсов.
Если у вас сейчас 502 или он был на прошлой неделе и «прошёл сам» — прогоните три команды из раздела про двухминутную проверку и пришлите мне вывод. Скажу, что у вас: разъехались адреса, не поднялся кэш или это вообще не про прокси. Разбор занимает у меня минут двадцать.
Частые вопросы
У нас 502 прошёл сам через час. Это точно был memcached?
Скорее нет. Самопроизвольное восстановление ровно через час — это подпись залипшего маршрута: запись в кэше жила час, истекла, прокси заново спросил обработчик и получил правильный ответ. Такое бывает после переноса ящика или после смены адреса почтового сервера. Если же кэш недоступен физически, само оно не пройдёт — 502 будет держаться до тех пор, пока вы не поднимете кэш или не почините адрес. Различить эти два сценария помогает счётчик строк в логе прокси: при залипшем маршруте ошибок про недоступный кэш там не будет вовсе.
Можно ли просто отключить прокси и пустить всех напрямую в mailboxd?
Технически на односерверной установке это иногда делают, и почта заработает. Но вы потеряете больше, чем приобретёте: обрыв соединений на публичных портах, ограничение числа неудачных входов, единую точку для сертификата, а на многосерверной схеме — вообще возможность распределять пользователей. Я такое видел у двух клиентов, оба пришли к этому в аварию и оба потом не помнили, почему у них веб-почта смотрит наружу мимо прокси. Правильнее потратить полчаса и починить связку.
Что делает zimbraMailProxyMaxFails и почему это советуют на форумах?
Это допустимое число неудачных попыток, после которого прокси помечает цель как нерабочую. Значение ноль означает, что цель не будет исключаться из обслуживания. У части людей после такой правки ошибка переставала воспроизводиться, отсюда и совет. Но это работа с последствием, а не с причиной: если кэш недоступен по адресу, прокси всё равно не сможет положить туда ответ. У меня этот приём дал сорок минут работающей почты и час потерянного времени — я решил, что нашёл причину, и перестал искать.
Как понять, что дело не в прокси, а в самой почте?
Спросить обработчик маршрутов напрямую по порту 7072. Если он отвечает кодом 401 — сервлет жив, mailboxd работает, ищите проблему между прокси и кэшем. Если соединение не устанавливается или висит — почтовая часть лежит, и вся история про кэш к вам не относится, идите смотреть журнал mailboxd и память. Это самая быстрая развилка в диагностике: одна команда, два принципиально разных пути дальше.
Стоит ли выносить memcached на отдельный хост?
Для установки на 48 или даже на 300 пользователей — нет, смысла ноль, вы только добавите себе точку отказа и сетевую задержку в каждый вход. Отдельный кэш имеет смысл в многосерверных конфигурациях, где несколько прокси должны видеть одни и те же маршруты. И если вы туда идёте, закладывайте сразу мониторинг доступности порта 11211 с каждого прокси: в такой схеме сетевые проблемы между узлами выглядят точно так же, как эта авария, и ищутся вдвое дольше.
Оставить комментарий