Мультиинстанс Postfix на сервере рассылок

Нет, это не Рио-де-Жанейро. Это гораздо хуже
(О. Бендер)

Прелюдия

Имеется несколько тематических списков рассылки одного крупного портала. В течении дня может пройти несколько рассылок по разным спискам. В самом большом списке более 200К подписчиков. И со всем этим успешно справлялся не самый мощный сервер (далее мейлер) с единственным белым адресом. Так что в течении 1,5-2 часов все 200К успешно уходили

Однако есть у нас один национальный мейл-провайдер (далее mailhub.tld), который вдруг, неожиданно, со своей стороны установил ограничения и в логах зачастила запись

421 Too many concurrent SMTP connections from this IP address; please try again later

Как выснилось из переписки с саппортом, они дают не более 8 одновременных подключений, не более 100 писем в одном подключении и не более 200 писем в секунду. И никак не собираются менять лимиты даже для конторы с громким именем в своей стране

Необходимо что б Вы исправили ситуацию с количеством подключений и вопрос будет решён автоматически

Таким образом они защищаются от спама. И это хорошо для них, но плохо для нас. Мы ввели рекомендуемые ограничения для домена mailhub.tld. Почта для остальных доменов шла на общих основаниях — 90 одновременных подключений. И теперь не только мы — люди, но и наш мейлер был удивлен таким раскладом и рекомендовал поднять лимиты

warning: mail for mailhub.tld is using up 6284 of 6284 active queue entries
warning: you may need to increase the main.cf mailhubtld_destination_concurrency_limit from 8

Так как подписчиков, у которых ящики на mailhub.tld более чем 60% списка рассылки (ок. 120К) то при таких ограничениях очередь стала быстро расти. И подписчики, у которых ящики отличные от mailhub.tld не могли своевременно получить почту. Человек выписавший с сайта счет мог получить его через 4-8 часов. Ясно, что с этим нужно было что-то делать

мультиинстанс Postfix

Слева два широких высоких пика это две рассылки по 200К подписчиков. Такие рассылки прошли быстро. Из-за введеных ограничений рассылка на mailhub.tld длилась 11 часов (ок. 120К подписчиков)

Варианты выхода

Их было всего два: переговоры с большими начальниками mailhub.tld и расширение парка мейлеров. Последний вариант был с вопросами, а именно:

  1. Нужно время для инсталяции, настройки, проверки новых мейлеров (На тот момент речь шла о дополнительных виртуальных серверах)
  2. Усложняется администрирование
  3. mailhub.tld должен будет еще «научится» понимать, что новые мейлеры не спамеры
  4. Чтоб выйти на цифру 90, нам нужно 11 таких мейлеров, исключительно ради mailhub.tld (Важно решить проблему доставки почты именно для пользователей этого домена)
  5. Нужны дополнительные ip-адреса. Аренда одного адреса — 1 евро/мес (Ерунда конечно, но все же)
  6. Через пол-года к примеру они введут ограничения с 8 до 3, и что, нам опять расширять парк мейлеров?

Мы занимаемся рассылками с 2011 года. И никаких проблем с mailhub.tld никогда не было. Более того, мы сами нашим подписчикам рекомендовали этот сервис как беспроблемный

Переговоры с ними ни к чему не привели. Позже пришел еще один ответ от их саппорта

Это ограничение на всех одинаковое, селективного вайтлиста нет, т.к. ограничения общесистемные

Такие дела 🙁

Задача

Разделить исходящую почту к mailhub.tld и другим мейл-провайдерам посредством настройки мультиинстанс postfix. Вся входящая почта должна приходить как и раньше через основной инстанс

Текущее состояние

Есть виртуальный мейлер с внешним и внутренным интерфейсом строго для рассылки и приема почты. В качестве MTA выступает posftix. В качестве dns-сервера unbound, который используется как форвардер. Имена хостов внутренней сети прописаны в /etc/hosts. Вся исходящая почта подписывается opendkim. x.x.x.92 — белый адрес внешнего интерфейса, 192.168.55.92 — серый адрес внутреннего интерфейса мейлера

Поехали!

Все действия выполняются на продакшене. ОС Gentoo

Берем у провайдера белые адреса x.x.x.15/24 x.x.x.16/24 и прописываем их дополнительными на внешний интерфейс. Аналогично с серыми адресами 192.168.55.15/24 192.168.55.16/24. Сразу все оформиляем в конфиге. /etc/conf.d/net должен выглядеть примерно так:

config_eth0="x.x.x.92/24 x.x.x.15/24 x.x.x.16/24"
routes_eth0="default via x.x.x.1"
config_eth1="192.168.55.92/24 192.168.55.15/24 192.168.55.16/24"

И перезагружаем интерфейсы

rc-service net.eth0 restart
rc-service net.eth1 restart

Важно! При перезагрузке внешнего интерфейса запускать команду в фоне, либо в сессии, которая была на мейлер по внутреннему интерфейсу. Соответственно в случае перезагрузки внутреннего интерфейса, запускать команду в сессии, которая была на внешнем интерфейсе. Если страшно используем ip addr для назначения адресов

Команда ip addr должна показать следующую картину (лишнее убрал):

eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP
inet x.x.x.92/24 brd x.x.x.255 scope global eth0
inet x.x.x.15/24 brd x.x.x.255 scope global secondary eth0
inet x.x.x.16/24 brd x.x.x.255 scope global secondary eth0

eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP
inet 192.168.55.92/24 brd 192.168.55.255 scope global eth1
inet 192.168.55.15/24 brd 192.168.55.255 scope global secondary eth1
inet 192.168.55.16/24 brd 192.168.55.255 scope global secondary eth1

Порядок. Теперь переводим postfix в режим мультиинстанса. В этом режиме postfix будет работать с папками, конфигами, очередью и pid-файлами каждого дополнительного инстанса отдельно

postmulti -e init
postmulti -I postfix-15 -G mailout -e create
postmulti -I postfix-16 -G mailout -e create

Все созданные конфиги безопасны и закрыты от запуска параметром master_service_disable = inet из main.cf. Когда все будет настроено и готово к запуску, данный параметр приводим к виду master_service_disable =

Важно! С этого момента ранее привычные команды postfix { stop | start | reload } выполняются над всеми инстансами сразу

Конфигурирование

Конфиги дополнительного инстанса postfix-15

main.cf

compatibility_level = 2
queue_directory = /var/spool/postfix-15
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix-15
mail_owner = postfix

myhostname = i15.mydomain.tld
smtp_bind_address = x.x.x.15
smtp_helo_name = i15.mydomain.tld
inet_interfaces = 192.168.55.15, x.x.x.15
inet_protocols = ipv4

smtp_use_tls = no

mydestination =
alias_maps =
alias_database =
local_recipient_maps =
local_transport = error:5.1.1 Mailbox unavailable
mynetworks = x.x.x.92, 192.168.55.0/24, 127.0.0.1

transport_maps = hash:/etc/postfix-15/transport

slow15_destination_concurrency_limit = 8
slow15_destination_rate_delay = 0
slow15_destination_recipient_limit = 5

smtpd_banner = $myhostname ESMTP service ready

multi_instance_enable = yes
master_service_disable = 
authorized_submit_users = 
multi_instance_group = mailout
multi_instance_name = postfix-15

unknown_local_recipient_reject_code = 550
debug_peer_level = 2
debugger_command =
PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
ddd $daemon_directory/$process_name $process_id & sleep 5

master.cf

Сюда добавляем строку с именем сервиса slow15 (из main.cf)

slow15 unix - - n - - smtp
  -o syslog_name=postfix15/slow15

transport

Тут указываем домен mailhub.tld проблемного мейл-провайдера и имя сервиса из master.cf через который должна уходить почта

# MAILHUB.TLD
mailhub.tld slow15:

После редактирования обязательно

postmap transport

Все. Дополнительный инстанс postfix-15 готов к запуску

postmulti -i postfix-15 -x postfix start

Аналогичным образом поднимается следующий дополнительный инстанс для пары адресов 192.168.55.16, x.x.x.16. Посмотреть статус запущеных инстансов можно командой:

postfix status

postfix/postfix-script: the Postfix mail system is running: PID: 4266
postfix-15/postfix-script: the Postfix mail system is running: PID: 19508
postfix-16/postfix-script: the Postfix mail system is running: PID: 20702

Видно, что запущены основной инстанс и два дополнительных

DNS

Нужно, чтоб dns-сервер умел работать в режиме round-robin. Такие как unbound и bind это умеют. У меня уже есть настроеный unbound в качестве форвардера, поэтому я раскомментирую строку rrset-roundrobin: yes в файле конфигурации unbound.conf

Еще нужно внести записи в прямую зону. До введения мультиинстанса для корректной работы достадочно было содержимого /etc/hosts. Однако postfix хочет наличия A-записей в прямой зоне, что более корректно, чем работа с /etc/hosts

Инфо! Можно заставить postfix смотреть в /etc/hosts указав в main.cf параметр smtp_host_lookup = native, а в /etc/nsswitch.conf указать порядок опроса dns-записей: hosts: files dns. Однако вариант добавления в /etc/hosts другого адреса с тем же именем не годится. При резолвинге отрабатывает только первая запись для этого имени

В unbound.conf конфигурация для прямой зоны .local выглядит так:

local-zone: "local." static
local-data: "mail.local. IN A 192.168.55.15"
local-data: "mail.local. IN A 192.168.55.16"

Важно! Серый адрес внутреннего интерфейса основного инстанса с именем mail.local в unbound.conf вносить нельзя, иначе основной инстанс будет резолвить mail.local только в 192.168.55.92, что сделает невозможной передачу почты дополнительным инстансам. Как следствие — зацикливание почты. Логично

Стоп-старт unbound

unbound-control stop
unbound-control start

Теперь попеременный запуск команды ping mail.local должен вернуть ответы с 192.168.55.15 и 192.168.55.16. Если это так, то двигаемся дальше

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

Добрый день
Просьба для следующих адресов внести изменения в обратной зоне
x.x.x.15 IN PTR i15.mydomain.tld.
x.x.x.16 IN PTR i16.mydomain.tld.

Изменения в прямой зоне делаем сами. Все это можно делать сразу после получения дополнительных адресов, до начала работ

Основной инстанс

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

  • Дополнительные белые адреса от провайдера и записи для них в прямой и обратной зоне. Работает обратный резолвинг
  • Дополнительные адреса (белые и серые) висят на своих интерфейсах
  • Сконфигурирован и запущен мультиинстанс postfix. Команда netstat -anl показывает интерфейсы 192.168.55.15:25 и 192.168.55.16:25 в состоянии LISTEN. Дополнительные инстансы готовы принимать почту от основного инстанса по серым адресам внутреннего интерфейса
  • Сконфигурирован и корректно работает в режиме round-robin dns-сервер для внутренней зоны .local

Если по всем пунктам ответ утвердительный, то можно вносить изменения в конфигурацию основного инстанса. Переходим в папку /etc/postfix

master.cf

Сюда добавляем строку с именем сервиса slow

slow unix - - n - - smtp
  -o syslog_name=postfix/slow

transport

Тут указываем домен mailhub.tld, имя сервиса из master.cf и dns-имя мейлера из внутренней зоны через который должна уходить почта. Благодаря механизму round-robin это dns-имя всякий раз будет разное, почта пойдет через другой дополнительный инстанс и соединение с mailhub.tld состоится с другого белого адреса, что и нужно

# MAILHUB.TLD
mailhub.tld slow:mail.local

После редактирования обязательно

postmap transport

Все. Самый ответственный момент

postfix reload

Перечитаны конфиги основного и дополнительных инстансов. В логах для mailhub.tld должны появиться похожие по смыслу записи:

Nov 22 13:43:54 i postfix/slow/smtp[12015]: 86E5862624: to=<nata@mailhub.tld>, relay=mail.local[192.168.55.15]:25, delay=0.28, delays=0.12/0.03/0.03/0.1, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as BCB0362648)
Nov 22 13:43:58 i postfix15/slow15/smtp[12019]: BCB0362648: to=<nata@mailhub.tld>, relay=mxs.mailhub.tld[z.z.z.z]:25, delay=3.6, delays=0.07/0.02/0.53/3, dsn=2.0.0, status=sent (250 OK id=1iY7Lw-000LVa-IO)
Nov 22 13:46:50 i postfix/slow/smtp[12015]: E658162749: to=<sfg@mailhub.tld>, relay=mail.local[192.168.55.16]:25, delay=0.23, delays=0.09/0/0.03/0.11, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 1A2CD6276A)
Nov 22 13:46:53 i postfix16/slow16/smtp[12334]: 1A2CD6276A: to=<sfg@mailhub.tld>, relay=mxs.mailhub.tld[z.z.z.z]:25, delay=3.3, delays=0.09/0.03/0.58/2.6, dsn=2.0.0, status=sent (250 OK id=1iY7Ol-000BN0-Oe)

Остальная почта должна уходить как и раньше с основного инстанса

Управление инстансами

На примере инстанса postfix-15

postmulti -i postfix-15 -p postfix reload {start | stop}
postmulti -i postfix-15 -x mailq
postmulti -i postfix-15 -x postsuper -d ALL
postmulti -i postfix-15 -x postsuper -d ALL deferred

Отключение и включение

postmulti -i postfix-15 -e disable
postmulti -i postfix-15 -e enable

Отключение и удаление

postmulti -i postfix-15 -p stop
postmulti -i postfix-15 -e disable
postmulti -i postfix-15 -e destroy

Результаты

  • Получена гибкая, масштабируемая система доставки писем разным мейл-провайдерам с smtp-ограничениями на входе
  • Каждый инстанс конфигурируется отдельно под конкретные нужды
  • Потребляемые ресурсы CPU/RAM выросли незначительно
  • Усложнилось администрирование системы мультиинстанс postfix за счет наличия дополнительных очередей и конфигов
  • Сложность администрирования мейлера осталась на прежнем уровне

Для сравнения графики «до» и «после»

мультиинстанс Postfix

Рассылка для 100К подписчиков. Слева почта уходит только через один инстанс, он же основной. Рассылка длится 4,5 часа. Справа — введено в эксплуатацию добавочно два дополнительных инстанса. Уже значительно легче. Рассылка ушла за 2 часа

мультиинстанс Postfix

В эксплуатации 13 дополнительных инстансов. Рассылки 100К слева и 200К+120К справа. Максимальная длительность рассылки до 2 часов каждая

Александр Черных
системный администратор

208
0