company_banner

Почтовый офис Яндекса: как мы сделали сервис, анализирующий результаты рассылок в реалтайме

    У Яндекса есть сервис для добросовестных рассыльщиков писем — Почтовый офис. (Для недобросовестных у нас в Почте есть Антиспам и кнопка «Отписаться».) С его помощью они могут понимать, какое количество их писем пользователи Яндекс.Почты удаляют, сколько времени их читают, насколько дочитывают. Меня зовут Антон Холодков, и я занимался разработкой серверной части этой системы. В этом посте я расскажу о том, как именно мы ее разрабатывали и с какими трудностями столкнулись.



    Для рассыльщика интерфейс Почтового офиса полностью прозрачен. Достаточно зарегистрировать в системе свой домен или email. Сервис собирает и анализирует данные по множеству параметров: имени и домену отправителя, времени, признаку спам/не спам, прочитано/не прочитано. Также реализована агрегация по полю list-id — специальному заголовку для идентификации рассылок. Источников данных у нас несколько.

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

    При сохранении и модификации информации нет жестких временных требований. Запись может добавляться или изменяться довольно долго. В этот момент статистика будет отражать предыдущее состояние системы. При больших объёмах данных это незаметно пользователю. Одно-два его действия, еще не положенных в базу, не смогут изменить статистику на сколько-нибудь большое значение.

    В веб-интерфейсе скорость отклика очень важна — торможения выглядят некрасиво. Кроме того, важно не допустить «скачков» значений при обновлении окна браузера. Такая ситуация возникает, когда извлекаются данные то с одной головы, то с другой.

    Пару слов хочется сказать о выборе платформы. Мы сразу поняли, что не каждое решение справится с таким потоком данных, который у нас есть. Изначально было три кандидата: MongoDB, Postgres, наша собственная связка Lucene+Zookeeper. От первых двух мы отказались из-за недостаточной производительности. Особенно большие проблемы были при вставке большого количества данных. В результате мы решили воспользоваться опытом коллег и использовали связку Lucene+Zookeeper — такую же связку использует поиск по Яндекс.Почте.

    Стандартом общения между компонентами внутри системы стал JSON. У Java и Javascript есть удобные средства для работы с ним. На C++ используем yajl и boost::property_tree. Все компоненты реализуют REST API.

    Данные в системе хранятся в Apache Lucene. Как вы знаете, Lucene — это библиотека, разработанная Apache Foundation для полнотекстового поиска. Она позволяет хранить и извлекать любые предварительно проиндексированные данные. Мы превратили ее в сервер: научили хранить данные, добавлять в индекс и сжимать его. С помощью http запроса можно искать, добавлять, модифицировать. Есть и различные виды агрегации.

    Чтобы каждая запись об изменении состояния была обработана во всех «головах» кластера, используется Zookeeper, ещё один продукт Apache Fondation. Мы доработали его и добавили возможность использования в качестве очереди.

    Для извлечения и анализа данных из Lucene написан специальный демон. В нем сосредоточена вся логика работы. Вызовы веб-интерфейса превращаются в http-запросы к Lucene. Тут же реализована логика агрегации данных, сортировки и прочие обработки, которые нужны для показа данных в веб-интерфейсе.



    Когда пользователи совершают действия в веб-интерфейсе, информация об этих действиях сохраняется через Zookeeper в Lucene. Каждое действие — например, нажатие кнопки «Спам» — изменяет состояние системы, и надо аккуратно модифицировать все данные, которые оно затрагивает. Это самая сложная часть системы, мы переписывали и отлаживали её дольше всего.

    Первая попытка решить задачу была, что называется, «в лоб». Мы хотели складывать записи о состоянии письма в Lucene налету. Агрегировать данные предполагалось в реальном времени при извлечении. Это решение прекрасно работало на небольшом количестве записей. Суммирование сотен записей занимало микросекунды. Все выглядело отлично. Проблемы начинались при большом количестве записей. Например, тысячи уже обрабатывались секунды. Десятки тысяч — десятки секунд. Это раздражало пользователей и нас. Нужно было искать пути ускорения выдачи данных.

    При этом агрегация обычных пользователей с десятками, сотнями и тысячами писем в день не была проблемой. Проблемой становились единичные рассыльщики, которые рассылали сотни тысяч писем за очень короткое время. Рассчитать для них данные в реальном времени было невозможно.

    Решение было найдено после анализа запросов c веб-интерфейса. Видов запросов было мало, и все они сводились к суммированию данных или нахождению среднего значения серии данных. Мы добавили в базу записи агрегации и стали их модифицировать при добавлении или изменении записей о состоянии письма. Например, пришло письмо — прибавили к общему счетчику единицу. Пользователь удалил письмо — отняли единицу от общего счетчика и прибавили единицу к счетчику удаленных. Пользователь пометил письмо спамом — прибавили единицу к счетчику «спамовых писем». Число записей, которое надо обработать для выполнения запроса, стало меньше, и это сильно ускорило агрегацию. Zookeeper позволяет легко обеспечить целостность данных. На изменение агрегирующих записей требуется время, но мы можем позволить себе небольшое отставание данных.

    Что получилось в итоге? Сейчас в системе четыре машины на Lucene, три на Zookeeper. Входные данные поступают с 10 машин и выдаются на шесть frontend машинах. В секунду система обрабатывает 4500 модификацирующих запросов и 1100 запросов на чтение. Объем хранения на сегодняшний день составляет 3.2 терабайт.

    Система хранения на Lucene + Zookeeper зарекомендовала себя очень стабильно. Можно на лету отключить узел на Lucene, можно добавить узел. Zookeeper хранит историю и накатит нужное число событий на новую машину. Через некоторое время мы получим голову с актуальной информацией. Одна машина в кластере выделена под хранения бэкапов данных.

    Несмотря на сжатые сроки разработки, система получилась надежная и быстрая. Архитектура позволяет легко масштабировать — как вертикально, так и горизонтально — и добавлять новые возможности анализа данных. Которые мы для вас обязательно скоро добавим.
    Яндекс 556,06
    Как мы делаем Яндекс
    Поделиться публикацией
    Комментарии 51
    • 0
      Сервис удобный, спасибо, давно пользуюсь. Не хватает только возможности удаления информации по ненужным рассылкам (ну или хотя бы их скрытия).

      Немного оффтоп, но все же — хотелось бы для добросовестных рассыльщиков от Яндекса сервис собственно самой рассылки увидеть — а то при рассылке писем через вашу почту для домена, например (с форума, используя его средства) через писем 200-300 все начинает возвращаться якобы как спам. Когда писал в поддержку — сказали что почта для домена не для рассылок. Пускай даже за небольшую плату, но сервис пользователей бы нашел. Для того же самого форума держать у себя на сервере smtp не всегда хорошим вариантом представляется.
      • 0
        Есть же различные сервисы для отправки писем. Знаю, правда, только пару платных. Но одним пользуюсь уже давно (Mailjet) — у них отличная статистика вплоть до 1 письма — показывает, что попало в спам, что открыли а в каком письме ещё и кликнули на ссылку.
        • 0
          Сокрытие это хорошая мысль. Спасибо!
        • 0
          Подскажите, когда ваш сервис почтовый офис выйдет из статуса беты?
          • 0
            Я не знаю. Если есть проблемы пишите в саппорт, мы с ними активно общаемся. А если нет то бетта не бетта какая разница? :)
            • +3
              Ну да, есть небольшая проблемка, пытаюсь добавить домен и вижу:

              Поздравляем, вы входите в топ-15 отправителей писем на Яндекс.Почту!
              К сожалению, из-за этого мы не сможем подключить ваш домен до выхода Почтового офиса из беты, так как он создаёт слишком высокую нагрузку.

              Безусловно я рад, что имею отношение к топ-15 спамеров отправителей, но реальность такова, что хочется как раз пользоваться вашим сервисом, чтобы понимать эффективность рассылок. :)
              • 0
                Мысли в слух: четвертый день жду пока Тимофей (саппорт) консультируется с техническими специалистами, почему не приходит подтверждение на почту.
                • 0
                  На выходных сотрудники Яндекса, как и многие другие люди, предпочитают отдыхать, иначе в будни очень сложно работать.
                  Уточните, пожалуйста, номер тикета, о котором идёт речь.
                  • 0
                    Четыре дня это без выходных.

                    P.S.
                    Тикет отправил лично.
                    • 0
                      Описанной в тикете проблемой уже занимаются разработчики. Как только ситуация будет исправлена, коллеги из службы поддержки обязательно оповестят. Извините, что не сообщили о создании задачи на исправление.
            • 0
              Изначально было три кандидата: MongoDB, Postgres, наша собственная связка Lucene+Zookeeper.

              А можете показать примерные результаты бенчмарков?
              • 0
                Я ждал этого вопроса :). Нет, к сожалению результаты тестов не сохранились.
                • 0
                  А Cassandra не пробовали? Пошустрей монги должна быть, особенно на запись.

                  Для Lucene свою http обвязку писали? Почему не Solr/Elasticsearch?
              • 0
                Будет ли в будущем fbl? Статистика это, конечно, круто, но и отписывать тех, кто 'в спам' жмет тоже как-то надо!
                • +1
                  У вас есть такие варианты:
                  1. yandexfbl.senderscore.net/
                  2. Использовать выгрузку в почтовом офисе. Мы ее скоро улучшим и автоматизируем.
                  • 0
                    1. Что писать в CIDRs/IPs?
                    2. В интерфейсе ссылки не нашёл, в документации к сервису так же не увидел. Подскажите, как получить доступ к выгрузке.

                    Ещё вопрос вдогонку. Что должно содержать письмо, чтобы появилась кнопка Отписаться?
                    • 0
                      Извините я вам не ответил в личке.
                      1. Ваши IP и сети.
                      2. Когда у вас будет больше 100 (точно цифру не помню) отписок то появится кнопка в рассылке а пока можно не беспокоится.
                      3. blog.yandex.ru/post/66296/

                      А вообще уточните у саппорта. Я могу что нибудь напутать.
                      • 0
                        Здравствуйте, может подскажете.
                        В FBL вырезали емейлы, кнопку выгрузки тех кому не интересно убрали из постофиса. И как быть? Что делать? Почему яндекс не дает убрать из рассылки тех кому не интересно читать наши письма?
                        • 0

                          а я так и не смог подключить FBL из-за сложностей в подключении,
                          сравнивая с mail.ru — Яндекс. менее дружелюбен

                          • 0
                            А какие там сложности? указал ip сервера и свой емейл :)
                            Логически это удобнее, у меня на сервере 30 сайтов. Быстрее указать один раз IP чем 30 раз подтверждать на mail.ru
                            • 0

                              Мы используем сторонние сервисы email-рассылок

                    • 0
                      Извините, а можно как-нибудь почеловечнее сделать интерфейс к FBL? Вот как у mail.ru хотя бы.

                      У меня письма рассылаются через гугл, через SES и через MailChimp. Какие CIDR мне писать, если они у них в любой момент могут измениться?
                      • 0
                        Скоро еще не наступило? Очень хочется автоматизированной выгрузки :)
                    • 0
                      Я добросовестный рассыльщик, но посмотрел на статистику моей рассылки и обнаружил, что порядка 75% писем падают в спам. Как это исправить?
                      • +2
                        Рассылать другие письма, которые люди не будут отправлять в спам.
                        • –4
                          Азазаза.
                          Это новости, на которые они сами добровольно подписывались.
                          • +3
                            Можно предположить, что они не понимают, как от них отписаться. Или они ожидали что-то немного другое, когда подписывались.

                            В любом случае, вас никто не обвиняет ни в чём. А вот знание о том, что 75% людей ваша рассылка не полезна — очень важное, используйте его.
                            • +1
                              Иногда форма подписки настолько неочевидна, что пользователи потом очень удивляются.
                              Иногда текст писем составлен так, что иначе как спамом это не назвать (даже если сам подписывался).
                              Иногда технически рассылка производится с серьёзными нарушениями, например, нет обратных зон или spf, нет List-Unsubscribe.
                              Требования Яндекса к честным рассылкам перечислены на странице help.yandex.ru/mail/honest-mailers.xml
                          • +2
                            А как люди подписываются на вашу рассылку? Без «double opt-in» нынче плохо. Отслеживаете ли непосредственно доставку почты и отсекаете ли в дальнейшем те ящики, на которые возвращается «550 user not found»? Пользуетесь mail.ru-шным postmaster'ом?
                            У яндекса и мейла в справке есть статьи на тему как улучшить свою доставку, там полезная информация.
                            Ну и, само собой, spf + dkim, + лично у себя еще и dmarc.
                            • 0
                              Разберитесь для начала почему попадает в спам. Возможно это техническая проблема.
                              • 0
                                Как понять, если это техническая проблема?
                                • +1
                                  spf, dkim, dmarc — очень желетелен. В саппорт написать.
                            • 0
                              Стандартом общения между компонентами внутри системы стал JSON.

                              На C++ используем yajl и boost::property_tree


                              А что за такие 4 буквы yajl?

                              PS.
                              Подумал что это YAndex Json Library, а нет, это Yet Another Json Library
                            • 0
                              Мы превратили ее в сервер: научили хранить данные, добавлять в индекс и сжимать его. С помощью http запроса можно искать, добавлять, модифицировать. Есть и различные виды агрегации.

                              Т.е. вы сделали Elastic Search. Планируете выложить исходники?
                              Вообще интересно, а почему Lucene. По сути вы не используете full text search (странно вообще его использовать имея свой, более продвинутый поиск), вам просто нужно хранилище данных с какими-то job'ами сверху для аггрегации и прочего, а тут overhead на индексацию. По своему опыту знаю, что Lucene ощутимо тормозит на постоянной вставке большого количества данных.
                              • 0
                                Исходники выложить не планируем. Там нет ничего особо интерестного. Поиск там не full text а по конкретным полям. Агрегация на лету я там писал в статье.
                              • 0
                                А где-нибудь доступна статистика по рассыльщикам? В частности, мне интересно я, со своими 5000 письмами на яндекс адреса в сутки, где… в первой тысяче, в первых десяти тысячах?
                                • 0
                                  Нет не доступна. Она плавающая.
                                • 0
                                  Скажите, пожалуйста, как можно объяснить разницу с показателями с postmaster.mail.ru по числу открытых писем. Относительное число писем, открываемых на mail, примерно в два раза больше, чем на yandex. Чем это можно объяснить?

                                  Похожая история с отмечающими письма как спам. Mail.ru каждый день сообщает о нескольких (до десяти) человек, отмечающих рассылку, как спам, тогда как в yandex уже давно не предлагает скачать список таких адресов.

                                  Заранее благодарю за разъяснение.
                                  • 0
                                    1. незнаю. Может у нас firstline лучше :).
                                    2. Если не предлагет скачать то число пользователей кликнувших spam < 100. Это хорошо я так думаю.
                                  • +1
                                    Спасибо за материал. А еще больше — спасибо за комменты. На многие важные вопросы ответили.
                                    • 0
                                      А почему в списке, который скачивается из блока «Удалите эти адреса» отсутствуют адреса с персональным спам-фильтром (а их большинство)?
                                      Дайте их скачать, чтобы тоже отписать, пожалуйста!
                                      • 0
                                        Ребята, а как еще можно подтвердить домен, кроме размещения на нем html-файла? Почему нет подтверждения через DNS, например? Конкретная проблема: мы используем для рассылки писем сервис SendGrid, который для whitelabel требует настройки A-записи домена, с которого рассылается почта, на свой IP. В результате наш общий from-домен имеет вид o1.sendgrid.convead.com и A-запись указывает на SendGrid, так что никакой возможности положить туда файл нет. Привязаться к конкретному емейлу тоже нельзя, т.к. мы — SaaS-сервис, отправляем письма от имени своих клиентов, емейлы всегда разные. Как мне подтвердить домен?

                                        Прошу прощения, что задаю вопрос в комментариях к статье полугодовой давности, но излазил весь хелп по почтовому офису, а формы суппорта так и не нашел.
                                        • 0
                                          Если отправитель всегда разный, то подтверждение домена никак не поможет.
                                          • 0
                                            Что имеется ввиду под «отправителем»? Домен всегда одинаковый (если клиент не заказал себе whitelabel, но этот случай не рассматривается).
                                            • 0
                                              Имеется ввиду заголовок From.
                                          • 0
                                            Вообще ситуация, когда From не соотносится с сервером отправителя, не похожа на честную рассылку. Требования к таким рассылкам со стороны Яндекса описаны, например, на странице help.yandex.ru/mail/spam/honest-mailers.xml
                                            • 0
                                              Мы не нарушаем требования, описанные по приведенной ссылке. Что значит «не похожа на честную рассылку»? Наши письма выглядят вот так: take.ms/9xCr0. Точно так же выглядят любые рассылки через Mailchimp например (обратный адрес — мой, отсылающий домен — другой). Они тоже «не честные»? Простите, но я не понимаю, о чем вы.
                                              • 0
                                                Вы можете попробовать подтвердить владение доменом sendgrid.convead.com. Если средствами Почтового офиса это не получается, подтвердите в Вебмастере — он появится в Офисе. Но чтобы отслеживать такую необычную рассылку, вам необходимо во всех письмах поддержать list-id help.yandex.ru/postoffice/advices.xml#list-id. И всё равно, не уверен, что это сработает для рассылок с разными From. Но попробовать стоит.
                                                • 0
                                                  Вы можете попробовать подтвердить владение доменом sendgrid.convead.com.

                                                  Это мы уже сделали, но по нему все время «Данных пока нет»… Эх, ладно, видимо не судьба.

                                                  Кстати, аналогичный сервис от ваших коллег из Mail.ru все прекрасно показывает по нашему домену.
                                                  • 0
                                                    Если в письмах нет list-id, то и данным неоткуда взяться.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое