Компания
1 155,45
рейтинг
12 сентября 2012 в 15:13

Разное → IMAP: трудности перехода

Какие грабли зарыты в IMAP



Уже некоторое время IMAP работает в Почте Mail.Ru в полную силу, и я готов рассказать о том, с какими проблемами мы столкнулись при его запуске. Часть из них была связана с особенностями самого протокола и с его историей, другие были обусловлены спецификой взаимодействия IMAP с нашим хранилищем. Отдельная категория трудностей вызвана многообразием почтовых клиентов.

За подробностями — добро пожаловать под кат.

Нынешний запуск IMAP — наш второй подход к снаряду. В прошлый раз мы взяли сервер Dovecot и попробовали заточить его под себя. Результат нас не устроил: с нашими нагрузками и нашей инфраструктурой он сочетался плохо. В этот раз мы решили выбрать другой путь, и написали собственное решение.


IMAP мы запустили в мае, но анонсировали только в июне. Фактически, майская аудитория — это наши сотрудники и те пользователи, у которых клиенты автоматически определили наличие IMAP в нашей Почте и подключили к нему новые добавленные аккаунты.


Трудности, специфичные для протокола IMAP


1. Громоздкость самого протокола

Первая версия протокола IMAP появилась в 1986 году. В данный момент актуален стандарт IMAP версии 4rev1, который был обновлен в 2003 году. За такой долгий срок стандарт существенно разросся: его текущая версия насчитывает порядка 200 страниц.

Сейчас многие моменты, описанные в стандарте, устарели — в сегодняшних условиях они уже не являются необходимостью. Например, в протоколе предусмотрен возврат количества строк и MD5-суммы частей письма — функционал, который фактически не используется в современных клиентах.

Кроме того, существует множество опциональных расширений протокола. Некоторые из них, по сути, являются необходимыми для удобной работы с почтовым ящиком.

Чтобы побороть историческое наследие, нам пришлось реализовать несколько расширений. Одно из них — UID+: когда мы копируем или добавляем письмо, мы возвращаем ID нового письма, которое появилось на сервере в результате копирования или добавления. Это позволяет нам сэкономить на ресурсоемкой операции поиска, которую приходилось проводить клиенту, чтобы распознать, какое именно письмо было добавлено.

2. Отсутствие стандартного паттерна работы с сервером

IMAP предоставляет множество способов решить одну и ту же задачу и, как следствие, практически у всех клиентов паттерн работы различен. Также важно, что паттерны работы существенно отличаются от того, как работает веб-почта или POP3.


Более половины приходится на долю клиентов под устройства Apple: причина в том, что у них хорошо работает автоопределение IMAP. Outloook же, напротив, по умолчанию работает по POP3, и настраивать IMAP нужно руками.

Здесь можно выделить 2 основные категории: десктопные клиенты, которые сразу запрашивают информацию обо всех письмах в ящике или папке, и мобильные клиенты, которые изначально запрашивают информацию только о самых новых письмах. Далее нам оставалось изучить запросы, которые они делают, чтобы обновить состояние, как именно они вытягивают информацию о письмах.

Почему для нас это было необходимым шагом? При скромных нагрузках (например, если сервер обслуживает корпоративную почту небольшой компании) вопрос оптимальности стоит не так остро. Однако при наших объемах оптимальность становится критичной: следовательно, нам нужно было изучить паттерны работы всего зоопарка почтовых клиентов, обращающихся к хранилищу.

3. Количество одновременных сессий

По стандарту, минимальный таймаут сервера — 30 минут. Кроме того, один клиент может держать сразу несколько соединений к серверу (в протоколе не указано максимальное количество разрешенных соединений). Фактически, в нашем масштабе, это означает, что один сервер должен оптимально работать с десятками тысяч одновременных соединений. При работе в синхронном режиме такое количество соединений просто поглотило бы все ресурсы.

Для решения этой проблемы я написал библиотеку для асинхронной работы, построенную на базе edge-triggered epoll. Изначально я ставил перед собой задачу сделать библиотеку, при помощи которой можно было бы в будущем за пару дней написать свой асинхронный сервер для решения других задач, помимо IMAP; в результате практически весь код можно использовать для написания других сервисов.

4. Невозможность однозначно идентифицировать клиент

Наш сервер поддерживает расширение ID, которое позволяет нам идентифицировать примерно половину клиентов. К сожалению, другая половина об этом расширении не знает (из популярных можно назвать, например, Outlook).
Понимание того, с каким клиентом мы работаем, позволяет обойти его характерные баги, а также предсказать, каким будет паттерн работы в рамках данной сессии и, соответственно, оптимизировать работу. Для нас это критично, поэтому, если клиент не называет ID, мы стараемся идентифицировать его другими путями (в случае Outlook — по тегам).

5. Отсутствие команды перемещения сообщений

В клиентах перемещение реализовано через копирование+удаление. Нам, разумеется, хочется, чтобы при этом копия письма помещалась в нужную папку, а оригинал удалялся и не захламлял корзину. С другой стороны, иногда сам пользователь копирует письмо в новую папку, а затем удаляет оригинал: в этом случае удаленное письмо должно помещаться в корзину.
Чтобы различать эти два кейса, после копирования мы в этой же сессии помечаем письмо специальным внутренним флажком. Когда сам пользователь копирует письмо и удаляет оригинал, клиент, как правило, обновляет список писем. При обновлении флажок автоматически сбрасывается, а удаленное письмо оказывается в корзине. Если же письмо (в рамках перемещения) удаляет клиент, обновления не происходит, и письмо, помеченное флажком, удаляется окончательно.

Трудности, связанные с адаптацией текущего хранилища писем и индексов


1. Идентификация сообщений

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

Наиболее рациональным оказывается держать в оперативной памяти весь набор порядковых номеров, их соответствие внутренним идентификаторам, а также IMAP ID. При открытии папки мы вытягиваем из хранилища список всех писем, наши внутренние идентификаторы, IMAP ID, флажки и размер сообщения — все то, что хочется отдавать без лишних запросов.

Обо всех изменениях порядкового номера в рамках одной сессии мы должны оповещать клиент. Согласно стандарту, последовательность IMAP ID должна соответствовать последовательности порядковых номеров. Порядковые номера мы получим, отсортировав список писем по уникальным номерам. Когда клиент выдает новую команду, мы заново открываем соединение с хранилищем, запрашиваем время последних изменений, которые были сделаны в ящике. Если изменений со времени последнего такого запроса не было, то мы просто возвращаем ответ на команду. В ином случае мы заново запрашиваем список сообщений в папке и сравниваем с аналогичным списком клиента. Далее мы либо возвращаем информацию об изменениях, либо, если протокол не позволяет этого сделать сразу, делаем у себя пометку о том, что письмо удалено, и ждем подходящего момента, чтобы сообщить об этом клиенту.

Из-за такой специфики — письма уже нет в ящике, но клиент об этом еще не узнал — клиент может запросить данные об уже удаленном письме. Более того, некоторые из них испытывали серьезные проблемы, если ответа на их запрос не поступало. Чтобы клиент не ломался, мы в ответ на подобные запросы возвращаем заглушки. Клиент получает нужную ему для нормальной работы информацию, а уже при следующем обновлении списка писем (оно, как правило, происходит сразу же) удаляет из него сообщение.

2. Необходимость оптимально возвращать информацию о MIME-структуре письма

Практически все клиенты запрашивают информацию о структуре письма. Часто в рамках первой сессии они запрашивают такую информацию сразу обо всех письмах в папке. Парсить письмо на каждый такой запрос было бы крайне неоптимально.
Вместо этого мы сделали кэш MIME-структур. Наличие кэша помогло нам побороть сразу несколько трудностей, связанных с особенностями IMAP — в частности, отсутствие стандартного паттерна работы с сервером: поскольку часть информации хранится в кэше, это помогает нивелировать нагрузку, связанную с разными паттернами работы клиентов.

Сейчас мы кэшируем до 50 сообщений. Почему не 2-3? Дело в том, что некоторые клиенты сначала запрашивают структуру письма, а потом тело, причем сразу для нескольких сообщений; максимальное число писем в такой «пачке» обычно составляет 50 штук.

3. Оптимальная отдача частей письма

Часто клиенты просят лишь текстовые части письма, которые могут находиться в конце самого сообщения. Для отображения сниппетов клиенты могут просить текстовые части сразу у 50-200 писем. Читать весь файл сообщения целиком (и обрабатывать 10 МБ письма для того, чтобы отдать 10 КБ текста) при этом не хочется; использовать индекс для определения позиции части внутри файла при каждом запросе также было бы накладно. В этой ситуации также спасает кэш структуры письма.
Преимущества такого подхода особенно наглядны тогда, когда клиент подгружает сниппеты для нескольких десятков писем: если бы мы не использовали кэш структуры, то для этого приходилось бы просмотреть много мегабайт и пожертвовать скоростью.

Для экономии места в наших хранилищах base64-части хранятся в декодированном виде внутри письма: при работе с веб-почтой это позволяет отдавать аттачи без лишнего перекодирования. Нужно было сделать схему отдачи частей с учетом этого перекодирования. Мы написали потоковое перекодирование на IMAP-сервере. Здесь также помог кэш — благодаря ему мы без перечитывания структуры можем понять, в каком виде (бинарном или нет) хранится тот или иной фрагмент.

4. Особенности работы некоторых клиентов

Некоторые клиенты не полностью соответствуют стандарту RFC: например, стандартные клиенты Android версий 2.2 — 2.3 не могут корректно отображать письма без возврата некоторых необязательных полей. Основная трудность заключалась в том, чтобы определить, какие именно поля каждый из таких клиентов считает для себя обязательными: приходилось решать это методом перебора.

Выше уже упоминалось о том, что у клиентов могут быть различные подходы к удалению писем: одни перемещают их в корзину, другие — удаляют сразу и безвозвратно. При этом некоторые клиенты не понимают стандартное расширение XLIST, которое мы поддерживаем, позволяющее определить, какая именно папка является корзиной. Вместо этого они используют в качестве корзины свою папку (так себя ведет, например, Sparrow).

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

В условиях такого разнообразия нам также было необходимо эмпирически понять, как ведет себя каждый из клиентов, и подстроиться под эти варианты — причем таким образом, чтобы пользователь мог быть уверен: независимо от того, в каком клиенте он работает, почта отреагирует на его действия привычно и предсказуемо (в данном случае — удаленное письмо окажется к корзине). Решали мы это, пробуя различные ответы через тестовый прокси-сервер и отслеживая реакцию клиента на каждый из вариантов.



То, что мы вынесли для себя: IMAP — достаточно «развесистая» штука, с множеством исторических особенностей, нажитых за 26 лет, которые умножаются на разнообразие почтовых клиентов. При наших нагрузках это выливается в то, что брать готовое решение и пытаться заточить его под себя нерационально: в лучшем случае объем работы будет таким же, как при самостоятельной разработке решения. Этим путем мы и пошли :)

Виктор Стародуб,
команда Почты Mail.ru
Автор: @vstarodub

Комментарии (56)

  • +3
    Вопрос, а какой клиент с Вашей точки зрения вы рекомендуете?
    я сейчас пользуюсь rhu8nderbird и многим недоволен, хочу чего-то «быстрее», что бы вы порекомендовали?
    • +3
      А какая платформа: windows/linux/mac os x, что именно не устраивает в скорости? Я лично imap-ом на android-е в основном пользуюсь, использую aquamail.
      • 0
        windows, thunderbird
        на ящиках свыше 10к писем очень медленно работает :)
        • +2
          Хоть я сам лично и не фанат, но очень многие хвалят outlook :) Он вроде бы нормально работает с большой базой писем. Еще как вариант есть the bat и opera. Друзья использовали the bat + imap на довольно больших аккаунтах.

          Для меня идеален был бы десктопный клиент с моделью работы мобильных клиентов: не качать ничего лишнего, всякие аттачи и картинки fetch-ить по запросу. Особенно это было бы актуально в случае слабого internet-канала. К сожалению, я таких клиентов не встречал, поэтому для десктопа использую веб-интерфейс. Он примерно соответствует моим требованиям не качать ничего лишнего.
          • 0
            Можно настроить, качать только заголовки писем, почти в любом клиенте.
            Я тоже письмо не полностью качаю. У меня стоит SSD HDD и я просто экономию место.
            • 0
              Ну заголовки — это тоже может быть достаточно много, особенно, в случае, если это автогенеренные текстовые письма. А заголовки 100-200 тыс писем — это уже прилично данных само по себе. Их надо уметь прилично индексировать, с чем не всегда клиенты справляются.

              Мобильные клиенты такой кучи информации стараются не хранить, а получают только последние сообщения, что мне и нравится.
  • +4
    Хорошая статья, систематизировали все проблемы imap.
  • +7
    Витя, супер, респект за IMAP. Хорошая работа!
  • +1
    Спасибо, очень интересно! Лишний раз подтверждает, что на практике все «немного не так», как написано в RFC.
    • +1
      Не всегда, а только для неудачных протоколов.
  • 0
    Вопрос не совсем по теме, но весьма меня волнующий.
    mime вложений, разсширение, magic проверяются у вас уже или пока нет?
    Помню, полгода назад с этим были проблемы. У gmail не было.
    • +1
      К сожалению, не совсем понял, о чем речь. Плюс, полгода назад у нас имап, насколько помню, еще был только на внутреннем тестовом сервере и проблем там было море :)

      Если речь об ответах BODY/BODYSTRUCTURE, то, согласно RFC, мы там возвращаем все поля из письма, которые клиенты могут использовать для работы с вложениями: content-id, content-type с полями charset и name, content-disposition с полем filename.
      • 0
        Писали мы клиент, который отправляет пользователю счет (с инн \ кпп, пасьянсом и барышнями) формате pdf. Использовали для сего действия gen_smtp.

        Тестовые письма

        Все три письма идентичны и все с вложениями. Только для последнего (первого в списке) был указан параметр application=pdf. Content-Type во всех случаях был application/pdf.
        Что конкретно, мы отправлялось, не проверяли.
        Если, любопытно, могу и покопаться.
        Такая проблема была (и есть?) только у mail.ru.

        Извиняюсь за офтоп (хотя вся ветка — оффтоп),
        но на всякий пожарный приведу код:
        mail(         {FromName, FromEmail}, 
                        {ToName, ToEmail}, 
                        Subject, 
                        Body, 
                        {AttachName, AttachBinary}
        ) -> 
            Email = {<<"multipart">>, <<"mixed">>, [
                        {<<"From">>, mmh_person(FromName, FromEmail)},
                        {<<"To">>, mmh_person(ToName, ToEmail)},
                        {<<"Subject">>, list_to_binary(Subject)}],
                    [],
                    [
                     %% Тело письма
                     {<<"text">>,<<"plain">>, [], [], list_to_binary(Body)},
                     %% Аттачменты(PDF) 
                     {<<"application">>,<<"pdf">>,
                        [{<<"Content-Type">>,<<"application/pdf">>},
                         {<<"Content-Transfer-Encoding">>,<<"base64">>}],
                        [
                         {<<"content-type-params">>,
                        [{<<"name">>, list_to_binary(AttachName)}],
                        [{<<"x-unix-mode">>,<<"0644">>}]},
                        {<<"disposition">>,<<"attachment">>},
                        {<<"disposition-params">>,[{<<"filename">>, 
                                        list_to_binary(AttachName)}]}],
                        AttachBinary}
                    ]},
            gen_smtp_client:send(
                {
                    FromEmail,
                    [ToEmail],
                    mimemail:encode(Email)
                },  ?SYS_MAIL_OPTIONS
            ).
        

        • +1
          Ага, т.е. речь все-таки об SMTP сервере. Я слишком плохо знаком с erlang-ом, чтобы суметь легко попробовать этот пример. Не могли бы вы сгенерить тела этих двух писем (с глюком и без), положить их в zip-архив и прислать мне на v.starodub {собака} corp.mail.ru? Мы разберемся, где именно глюк — в телах писем, или же в SMTP/веб-интерефейсе, если у нас — то с радостью починим.

          Как я понимаю, генерацию производит вызов mimemail:encode(), а gen_smtp занимается уже отправкой?
          • 0
            SMTP сервере.
            — Клиенте.
            Gen_smtp занимается отправкой, но только в качестве клиента. Отправкой занимается sendmail (как я понимаю), который находится удаленно.
            Остальное, вы поняли правильно.

            Возможно, как верно подметил ниже Макс, это как раз пример такого «чу́дного клиента».
            Попробую сделать что вы сказали.
            • +1
              Думаю, что тут вряд ли дело в клиенте, т.к. SMTP — очень агностичный протокол по отношению к телу письма, smtp-клиенту редко нужно уметь парсить mime письма дальше нескольких хэдеров и вообще разбираться, что там внутри. Исключение составляет только разве что binary extension.

              Нужно смотреть в тело письма.
              • 0
                Если я воспроизвел именно ту ошибку о которой говорил, то я немного соврал. Уж слишком давно это было. Да и во общем, вроде уже проблему решили, не актуально.

                Проболема была в multipart/alternative. Т.о., с вашей стороны все было сделано, формально правильно. Однако, поведение, интерфейса почты
                — странно, и несколько не предсказуемо.

                Пока пытался воспроизвести, эту проблему я нашел, еще несколько интересных особенностей. Сервисы на которых, я тестировал почту были выбраны от балды (никаких предрассудков и предрасположенностей не имею), просто нужно было с чем-то сравнивать.

                1. Если указать, multipart не mixed, a alternative, в mail.ru вложение приходит то в гриде просмотра почты не отображается, что есть вложение. У mail.yandex.ru показывает, что вложение есть, но в письма вложения вообще нет (скачивать нечего). То, что вложение есть показывается не сразу после получения письма, а если немного подождать. У gmail.сom все ок.
                  Если я действительно, воспроизвел ту самую проблему, понятно, почему у mail.yandex.ru она не была замечена. Не факт, что внутрь письма заглядывали, когда тестировали полгода назад.

                2. Была замечена ошибка у mail.yandex.ru. Если отправлять письмо без, Content-Transfer-Encoding: base64 то в гриде просмотра почты не отображается, что есть вложение. Всего скорее проблемы в интерфейсе. Потому что поcле просмотра письма значок аттача появляется. У mail.ru все ок. У gmail.сom все ок.
                3. Если не указать disposition-params у mail.ru, то нет аттача в гриде просмотра почты. Если открыть само письмо, то аттач есть (Untitled.pdf вместо имени). Проблема всего скорее только в интерфейсе, ибо thunderbird этот аттач видит и до открытия письма. У mail.yandex.ru в этом случае вообще не показывает аттача. У gmail.сom все ок, но вложение соответсвенно называется noname (без расширения).
                4. Была замечена ошибка у mail.yandex.ru Если отправлять письмо без, content-type-params, то в гриде просмотра почты не отображается, что есть вложение. У mail.ru все ок. У gmail.сom все ок.


                Несколько урезанные версии писем на которых тестировалось:
                gist.github.com/b5bb40d982604b40b5b7
                Полные версии продублировал на почту.
  • +2
    Молодцы!

    Полагаю, что вам ещё год-два знакомиться с разными диалектами чудных клиентов, которые шлют команды именно в таком порядке, в котором вы уж точно никак не рассчитывали, но вы и это разберете =)

    Насколько вам пришлось менять само базовое хранилище писем? К нему централизованный доступ или вы запускаете на каждом сервере со стораджами свой IMAP сервер?
    • +2
      Спасибо :)

      К хранилищу пришлось прикрутить imap-ные uid-ы и uidvalidity, а также их обновление в случае модификаций писем. Это теоретически несложно, но нужно было быть аккуратным и поправить достаточное кол-во кода. Также там была прикручена пара оптимизаций для ускорения частичной отдачи письма в RFC-формате, это не было нужно pop3 и веб-интерфейсу.

      Вообще, одна из целей написания собственного сервера — не менять сильно хранилище, т.к. переиндексировать все письма — очень «дорого», в наших объемах это может занять до полугода. Мы обошлись только довольно «дешевой» раздачей uid-ов, которую мы делаем при первом доступе по imap к ящику.

      Хранилище у нас на отдельных серверах, имап является таким же клиентом хранилища, как и pop3, smtp и веб-интерфес. Они все дергают один API по одному протоколу.

  • –5
    детский сад :)
  • 0
    В Outlook 2013 добавили RFC6154 XLIST
  • –7
    >Уже некоторое время IMAP работает в Почте Mail.Ru в полную силу
    Гмайл IMAP с 2008 г.
    Яндекс IMAP с 2009 г.
    Про IMAP на Mail.Ru в 2012 смешно читать, как и о почте на Mail.Ru, уж извините, хотя за статью спасибо.
    • +3
      Я рад, что наша статья вызывает у вас положительные эмоции. Сейчас обхохочетесь еще больше:

      Newmail.ru IMAP с 2001 г.
      Hotbox.ru IMAP с 2002 г.
      Gmail IMAP с 2008 г.

      Обе почте несколько лет назад объединились в составе mail.qip.ru и здравствуют и поныне.
      • +1
        Вы Hotbox.ru и Newmail.ru ставите в один ряд с Gmail, Яндекс, Mail.Ru, тогда давайте начнем с 86?
        • 0
          Обе эти почты — это сейчас mail.qip.ru, которая по российской дневной аудитории где-то на уровне Rambler-почты, т.е. четвертая почта после Mail.Ru, Yandex и GMail. mail.qip.ru, конечно, по российской суточной аудитории отличается в разы от ближайшего к ней GMail, но и GMail в разы меньше Mail.Ru по тому же параметру.
          • 0
            ключевое слово «сейчас». И какое в данном контексте имеет значение российская аудитория или нет?
            • +1
              Как раз в те годы, когда там внедряли имап, эти сервисы были достаточно популярны, не только сейчас. Навскидку: у меня именно в 2001-м основной ящик был на newmail.ru, как и у многих моих друзей.

              Актуальность имапа тогда была достаточно высока: веб-интерфейсы были убогие по современным меркам, почтовые программы были бесспорно удобнее. Интернет был дорогой и слабый, возможность не качать весь свой ящик, работать с папками на сервере выглядела достаточно привлекательно. Поддержка имапа этими сервисами в своем роде даже большее достижение, чем имап на гмейле в 2008-м.

              Но если говорить именно про «сейчас», так в современном своем виде имап более актуален для мобильных клиентов, которые в силу своих ограничений по объему persistent-хранилища просто не могут адекватно работать с pop3. Если посмотреть на графики, то мобильных клиентов больше половины.

              Но нормальная поддержка имапа, более-менее соответствующая RFC и работающая не только с gmail-ом и еще парой серверов, например, в андроиде появилась чуть позже появления версии 2.2, а это был уже 2010 год. В 2008-м не было такого рынка устройств, корректно поддерживающих imap, соответственно актуальность самого протокола была не так высока.

              С 2008 года поменялось многое: команда почты mail.ru поменялась практически целиком, как поменялись и приоритеты. К сожалению, я не мог написать имап в 2008 году, как бы ни хотел, т.к. я еще тогда не работал в команде почты и в mail.ru вообще, а Денис тогда как раз делал поддержку имапа в яндексе :)

              В своем посте я систематизировал технические нюансы реализации imap-а. Возможно, кому-то это будет просто любопытно, кому-то подкинет мыслей, скажем, при написании imap-клиента. Если бы я что-то в этом роде прочитал перед написанием сервера — мне это бы сэкономило некоторое количество времени. Если вам это неинтересно и вызывает лишь скептицизм — простите меня за то, что вы решили прочесть эту статью.
            • 0
              Как справедливо заметил Витя эти почты тогда занимали существенную долю рынка. Т.е. сейчас — это не ключевое слово. Российская аудитория имеет то значение, что вы упомянули gmail, у которого суточная аудитория world wide выше mail.ru в 4 раза. Если вы считаете их нашими конкурентами, то неявно подразумеваете, что речь только о России и возможно бывших советских республиках.
    • +2
      В Mail.Ru первый раз IMAP был запущен в 2005 году. И вполне успешно работал с популярными почтовыми клиентами того времени. Но популярность среди пользователей протокол не обрел, да и те кто им пользовался не охотно репортили баги, поэтому из-за отсутствия обратной связи с пользователями, и развитие поддержки имапа на стороне клиента ушло дальше возможностей имапа Mail.Ru. Повторный интерес к IMAP на мой взгляд — появился одновременно с ажиотажем на устройства с iOS и android. Появился интерес вот вам и обновленный IMAP 2012 Mail.Ru :)
  • +1
    Спасибо за статью! А можно вкратце про dovecot — помимо сложностей с прикручиванием к хранилищу, какие ещё с ним были проблемы? От него пришлось отказаться в основном из-за хранилища, или это была только половина проблемы?
    • 0
      В основном из-за хранилища. Но dovecot еще и очень прожорлив по процессору
      • +2
        мне кажется, что IMAP-сервер это как раз то, что надо садиться и писать на эрланге без всяких там глупостей с С =)

        Логики много, она вся с таймаутами и запутанная.
        • +1
          Если говорить про написание просто абстрактно хорошего имап сервера, оно, наверное, так и есть: проще взять очень высокоуровневый, возможно функциональный, язык программирования, написать на нем лаконичный, красивый и аккуратный код без хаков.

          Но у нас сервер, к сожалению, писался не совсем абстрактно: есть уже хранилище с достаточно громоздким C-шным API, кроме того, внутри проекта почты сервер-сайд сейчас пишут на С/C++, perl-е и python-е. Программистов на эрланге у нас в команде просто нет. Т.е. даже если сервер на нем и написать, то читать его код будет потом некому. Плюс, надо изобретать какие-то обертки для C-шного кода в эрланг, либо поддерживать 2 версии клиентской библиотеки к стороджу.

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

          Да и на самом деле, на C++ при правильном подходе, код оказался довольно лаконичным: со всеми хаками для всех клиентов, там имапной специфики около 5000 строк. :)
          • 0
            Плюс, надо изобретать какие-то обертки для C-шного кода в эрланг

            Для таких вещей все и придумывалось. Наш стримящий сервер был написан тоже в лохматые времена на C. Не мешает его испрльзовать через erlang. Тем более, не надо ничего изобретать!
            www.erlang.org/doc/tutorial/c_port.html
            Реальный пример использования:
            github.com/zavr/erlxslt (многопоточная обертка над libxslt)

            Программистов на эрланге у нас в команде просто нет.

            Вопрос двух недель. У нас тоже не было.

            Если Вы любите, TeX, пример — есть такие хорошие понятия в TeX как «блоки» и «клей». В переложении на мир технологий, erlang — и есть этот «клей». Это не просто еще один язык разработки, в том-то и его преимущество (мы же Вам не ocaml или haskell предлагаем).
            Можно писать, на самом erlang все, но если уже что-то есть сделанное, не обязательно переписывать. Составные части, как мне кажется, логично продолжить писать на сях, а вот склеивать их эрлангом. Но это мое скромное мнение.
            Вам, в вашей ситуации виднее.
            • +1
              Ну, т.е. с_port подразумевает еще один процесс-проксю? Не думаю, что наших админов бы это обрадовало :)

              А на самом деле, я думаю, что описанный вами способ написания сервера — просто другой подход, который вполне хорош и имеет право на жизнь. Он имеет, как плюсы, так и минусы.

              Вообще же, как показала практика, написать код сервера — это не так уж и сложно, независимо от языка. Повторюсь, но специфики имап там всего лишь 5к строчек. Правильно подружить все это дело с нашей инфраструктурой, с множеством разных клиентов — это было куда более сложной задачей, а тут уже язык не важен, важен подход.
              • 0
                c_port как вариант, а так, как настроите-сделаете. Обычно, да — но, это вроде как логично, но все настраиваемо. Может и erl_driver замутить.

                Я во общем вас не агитирую, просто ответил, на не очень правильные аргументы с вашей стороны. А у программы все один критерий правильности: работает — значит не все плохо.

                Ближе к теме:
                5k хорошо комментированного, понятного кода, или как голые функции, c короткими именами и однобуквенные переменные?
                • +1
                  Насчет качества кода — тут уж не мне судить, извините. Мне он, естественно, большей частью нравится :) Там в основном именно работа с протоколом, парс-форматирование, код достаточно простой и без rocket-science-а. C++ — довольно лаконичный язык, но, к сожалению, только если уметь его готовить.
          • +1
            Как это нет? Вот у вас есть люди, которые пишут сервер-сайд на С++? Они уже готовы писать на эрланге, пока компилится С-шный код.

            • +1
              Хм, ну уж нет. Я, например, лично не готов :) Толстовато, в общем)

              Вообще, это странная тема… я могу более-менее читаемо, быстро и лаконично писать на C++(надеюсь, что так). Вы — на erlang. Если мы поменяемся местами, то, скорее всего, наша продуктивность резко снизится (во всяком случае, моя уж точно). Хуже от этого будет только пользователям mail.ru, которые получат имап позже :) При этом, при всех прелестях erlang-а, вряд ли я сразу напишу maintainable код.

              А кроме erlang-а еще много интересных технологий. Говорят, в последнем .NET-е интересные фишки в плане асинхронности добавили, а еще он тоже быстро компилируется. Scala тоже интересный и красивый язык с функциональными плюшками.

              Но если все пробовать, то кто и когда код писать-то будет? Да и по мне, так добавление еще одного языка, даже самого передового, в любой корпоративный зоопарк технологий только усложняет интеграцию.
              • 0
                А как же синергетический эффект? )

                в плане асинхронности добавили

                К сожалению, особенности .NET и java-машины, не позволяют, на мой взгляд, сделать полноценную асинхронность. Во общем, есть на то математические основания.

                получат имап позже

                Возможно, а возможно и раньше. + есть одна важная деталь — сопровождение. Не только сегодняшним днем живем. И не в любых своих (и чужих) исходниках двухлетней давности приятно разбираться.

                Как раз для изучения плюсов и минусов той или иной технологии, применительно к текущим задачам и нужны в компании консультанты.
                • +1
                  В плане .NET — я на нем писал давно и не очень много. Но об этих улучшениях написано в release notes, друзья говорили, что стало удобнее. Это был просто пример того, что есть и другие интересные технологии, которые в принципе можно попробовать :)

                  Получат позже — потому что непосредственно написание кода заняло реально малый процент времени. Я знаю, что на новом для себя языке я бы писал не так быстро и код был бы хуже, как минимум, первые полгода. На нормальное овладение технологией, имхо, уходит не один месяц и не один проект.

                  Я лично, как инженер, считаю, что язык программирования — не главное. На практически любом языке можно сделать удобную для проекта и задач платформу. Главное — хорошо владеть выбранным инструментом.

                  Консультанты — это хорошо, но я помню, что в Parallels, например, по совету консультантов начали пытаться переписывать всю автоматизацию на java. Имхо, это был очень странный шаг, который стоил компании нескольких толковых специалистов и отнял порядочно времени. С любым подходом главное — не перестараться :)
                  • 0
                    Это ветка, конечно, похожа на холивар, но Вы приводите интересные и очень разумные аргументы, потому предлагаю продолжить.
                    Получат позже
                    Я с Вами согласен, что применять что-то пилотное в активном и критически важном проекте — не правильно. Но, как мне кажется, нужно смотреть дальше чем один проект. Живем не сегодняшним днем, и Ваши 5k строк через некоторое время могут превратиться в 50k, 500k строк (и это нормально) и их надо будет как-то поддерживать. Если есть немного свободного времени, посмотрите Cesarini F. Erlang programming, и сравните с тем что уже имеете.
                    язык программирования
                    Согласен, но как лингвист, я скажу что любые языки принципиально не эквивалентны. Сам язык, что — просто набор правил над некоторым множеством символов. Но за каждым естественным языком стоит его культура. За искусственным — парадигма, или архитектура абстрактной машины этого языка.
                    Знание внешней оболочки языка, без понимания основания делает человека «языковым чудищем». Вы просто спросили как пройти, а вам морду набили.
                    Парадигмы-то они эквивалентны, но некоторые вещи в лямда выражениях выглядят проще, удобнее, эффективнее, чем в рамках стековой машины (java, .net, python) или машины фон Неймана (C\C++, Fortran).
                    сделать удобную для проекта и задач платформу
                    По сути, тоже реализация некоторого языка, на основе существующего. А такое лучше делать на функционального подхода. + Делать платформу — это тоже время. А если она станет одноразовой, и даже частично не применимой, к чему-то другому — слишком дорого.
                    Локальные решения это хорошо, но только они не позволяют находить других локальных решений, которые, может быть, лучше. Траншею можно копать саперной лопаткой, а можно экскаватором. Если траншея одна в принципе, то лопатой, конечно быстрее. Она получится даже аккуратнее. А на экскаваторщика придется еще учиться. Но если траншей сотни, то лопата уже не применима.
            • 0
              пока компилится С-шный код.

              Вот тут мне кажется, ты не прав. Что такое у тебя долго компилировалось? И как долго?
              Имхо, такие 5k как раз, скомпилятся вполне себе быстро.
              • +1
                это какие 5К строк. Если с бустом и локи, то поспать успеешь. Если попроще код, то шустро разгребется.
  • +1
    Посмотрел на dovecot — там вроде бы вполне прозрачная система плагинов для хранилищ. Неужели настолько плохо совместимыми оказались его API и API хранилища — настолько, что написать с нуля сервер оказалось дешевле? Или, как ответили выше, процессорное время тоже стало узким местом (или ещё что-то)?
    • 0
      В общем случае, dovecote надо допиливать напильником, если у вашего хранилища ни один из поддерживаемых им форматов. Вот тут подробности: wiki2.dovecot.org/MailboxFormat
      Ну и процессорное время тоже жалко. В свое время, когда я работал техдиром в Почте.ру, у нас была IMAP-прокси в лице dovecote. Переделав ее на свою собственную, мы уменьшили количество серверов для IMAP-прокси в 10 раз.
  • +1
    Там основная проблема в том, что у нас другие требования к индексам. Как пример: imap-сервер может позволить себе сохранить в индексе уже готовый ответ на fetch bodystructure, для нас это было бы слишком дорого как в смысле избыточности, так и в смысле переиндексации. У нас структура письма в индексах хранится в виде дерева, и используется imap-ом, веб-интерфейсом, и даже pop3.

    Кроме того, письма у нас хранятся не по RFC, а в другом, чуть более компактном виде.

    Фактически нам надо было бы научиться формировать на лету ответы bodystructure/envelope из данных в нашем формате, прикрутить какие-нибудь хаки для того, чтобы без лишних оверхедов на I/O отдавать части письма, попутно преобразуя их к RFC-виду. Потом надо было бы прикрутить общение с нашей базой юзеров.

    На самом деле, примерно этим и занимается 80-90%% кода нашего имап-сервера.Т.е. какую часть dovecot-а мы реально смогли бы переиспользовать? По сути, только работу с сокетами и парсинг протокола. И то, ее, скорее всего пришлось бы патчить, чтобы не есть лишнего CPU.

    Кроме того, dovecot — сторонний для нас проект, он живет своей жизнью и любые плагины и правки нам надо будет мерджить с новыми изменениями самого сервера, либо взять на себя поддержку проекта из 300 тыс строк.

    В результате плюсы от написания своего сервера перевесили минусы.

    • 0
      блин, но у вас бы хоть IDLE был. ладно NOTIFY (редкая вещь), но хоть IDLE… и QRESYNC… а щас в итоге ни фига нет до сих пор) вы кстати там ещё работаете? есть какие-нибудь планы по развитию IMAP сервера?
  • +1
    Рапортую: IMAP работает просто великолепно. Подключил с первого раза без проблем. Огромное спасибо!
  • 0
    Почему-то сейчас не могу установить для ящика возможность использовать IMAP, как на iOS 6 так и в Mail.App OS X 10.8.2. Всё время видится только POP3
    • 0
      У Apple что то сломалось. Мы сейчас в активной переписке с ними. Просим вернуть автонастройку imap.
      • 0
        Спасибо за быстрый ответ :)
        • 0
          Пока рекомендуем воспользоваться следующим хаком. Вводите при настройке неверный пароль, и вам предложат выбрать поп или имап с ручной настройкой параметров сервера.
          • 0
            Сработало! :) Спасибо!
  • 0
    Спасибо за статью. Хоть я и не программист, но было очень интересно почитать.
    Кто что может посоветовать (из почтовых серверов) для компании (200 пользователей). Средний размер ящика 10 ГБайт (максимум — 30 ГБайт). Средне кол-во писем в ящике — 30000.
    Сейчас используем dovecot. Клиенты — Thunderbird. У всех IMAP без кеширования почты на диск.
    Спасибо!

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

Самое читаемое Разное