Ваш пьяный друг когда-либо вдохновлял Вас на создание первого в своем роде интернет-сервиса, который пришелся бы по вкусу миллионам пользователей и при этом неприхотливо обрабатывал миллиарды электронных писем ежегодно? Именно так Paul Tyma и создал Mailinator.
Mailinator представляет собой бесплатный, не требующий инсталляции, сервис для разрушения планов злобных спаммеров путем предоставления регистрации "одноразовых" почтовых адресов. Если Вы не не будете публиковать в Сети свой настоящий интернет-адрес - спаммеру не будут слать вам письма, вместо этого они будут спамить Mailinator :-)
Как же Mailinator справляется со своей ролью анти-спам супергероя?
Источники информация
Да-да, это снова перевод статьи от Todd'а (цифры правда не первой свежести, но все же). На что-то более глобальное я в ближайшее время способен не буду, в основном благодаря незаметно подкравшейся сессии и, отчасти, работе.
Платформа
Статистика
- Сервис обработал: 1.29 миллиардов электронных писем за 2007 год. 450.74 миллионов за 2006. 280.68 миллионов за 2005.
- В период пиковых нагрузок обрабатывается 6.5 миллионов электронных писем в сутки или 4513 сообщений в минуту или 75 в секунду.
- Mailinator работает на всего одном весьма средненьком компьютере с AMD Athlon 2GHz процессором, 1 GB оперативной памяти (которая используется не целиком) и низкопроизводительным IDE жестким диском объемом 80 GB. И она в общем-то загружена далеко не полностью.
- Mailinator работает месяцами без присмотра и теряется очень небольшое количество сообщений, даже при постоянных спам-атаках и высоких пиковых нагрузках.
Архитектура
- Так как система бесплатна, она не должна быть идеальной. Таким образом основные цели:
- Создание системы, которая ценит выживание превыше всего, даже пользователей. Основным ключом является именно выживание, так как Mailinator вынужден ежедневно отражать спам-атаки.
- Предоставить пользователям 99,99% доступность и точность данных. Более высокие гарантии будут существенно менее практичными и приведут к большим затратам. И так как сервис бесплатен, этот небольшой риск для пользователей становится просто частью правил игры.
- Поддержка следующей модели сервиса: пользователь регистрируется где-то, заходит в Mailinator, жмет на пришедшую ссылку и забывает об этом. Это означает, что письма не должны храниться постоянно. Они могут размещаться в оперативной памяти, так как являются временными (живут три-четыре часа). Если Вам нужен обычный настоящий почтовый ящик - воспользуйтесь любым другим соответствующим сервисом.
- Изначально письма обрабатывались следующим образом:
- Sendmail получал письмо в общий ящик на диске.
- Java-приложение доставало сообщение используя IMAP и/или POP (с течением времени это менялось) и удаляло их.
- Система загружала все письма в память и оставляла их там.
- Наиболее старые сообщения вытеснялись как только накапливался лимит в 20000 сообщений.
- Данный принцип работал вполне неплохо:
- Он стабилен и работал месяцами без каких-либо проблем.
- Использовался практически весь гигабайт оперативной памяти.
- Проблемы начались, когда количество сообщений в сутки начало превышать 800000. Система начала давать сбои из-за использования жесткого диска между Mailinator и email подсистемой.
- Наиболее старые сообщения вытеснялись как только накапливался лимит в 20000 сообщений.
- Новая архитектура:
- Идея заключалась в отказе от временного хранения данных на жестком диске путем полного переписывания всей системы с нуля.
- Веб-приложение, почтовый сервер и все хранилище писем функционируют в рамках одной JVM.
- Sendmail был заменен на специально написанный для этого проекта SMTP сервер. Так как природа Mailinator не требовала полноценного SMTP сервера. Mailinator не отправляет писем, основная цель - принимать или отвергать входящие письма. Это является недостатком многоуровневой архитектуры. Она часто является залогом успеха в процессе масштабирования веб-приложения, но порой она может и наоборот полностью убить всю производительность благодаря неверному принятию ответственных решений. Решение о создании собственного SMTP сервера было достаточно интересным и смелым, многие другие руководители проектов вместо этого просто добавили бы дополнительное оборудование в систему. Это не было бы ошибкой, но, согласитесь, создание своего собственного решения задачи - намного более интересный подход.
- Сейчас Mailinator получает почту напрямую, обрабатывает ее и хранит в оперативной памяти. Жесткие диски полностью обходятся и практически не используются.
- Основное их применение - хранение сообщений в случае остановки сервиса для того, чтобы они могли быть восстановлены при запуске.
- Ведение логов было отключено.
- Система использует менее 300 потоков. Это оказалось вполне достаточно.
- При принятии сообщения, система пропускает его через набор фильтров и хранит его в памяти только в том случае, если все фильтры были успешно пройдены.
- Каждый почтовый адрес ограничен только 10 письмами, так что популярные адреса вроде [email protected] не могут "взорвать" систему.
- Письма не могут превышать 100 kb, а все приложения автоматически уничтожаются. Это позволяет существенно сэкономить в плане используемой оперативной памяти..
- Электронные письма сжимаются в оперативной памяти:
- 99% писем никто даже не открывает, компрессия позволяет сэкономить место в оперативной памяти. Письмо разжимается в исходное состояние только если кто-то решает его открыть.
- Mailinator может хранить около 80000 писем в оперативной памяти, используя лишь 300 MB памяти, по сравнению с 20000 писем, занимающих 1 GB без использования компрессии.
- С таким подходом к хранению писем, они живут в среднем 3-4 часа.
- В память поместится и 200000 писем, но на практике это и не требуется.
- Оперативная память ценна, а процессорное время - вовсе нет. Именно из-за этого используется компрессия для экономии памяти и использования излишков вычислительных мощностей.
- Mailinator не гарантирует анонимность или приватность:
- Любой пользователь может получить доступ к любому почтовому ящику.
- Отказ от ограничений доступа делает схему работы системы намного более простой.
- Со стороны пользователя такой подход очень прост, так как не требуется абсолютно никакой регистрации. Когда сайт требует ввести почтовый адрес достаточно лишь просто ввести любой адрес Mailinator. Вам не нужно создавать отдельный аккаунт. Банальный ввод адреса создает почтовый ящик. Все просто.
- На практике же, не смотря на вышесказанное, пользователи все же получают изрядную степень приватности.
- Стремление к выживанию требует агрессивной борьбы со спамом:
- Mailinator не имеет ничего против спама, но так как спама приходит нереально много, когда он подвергает риску работоспособность сервиса приходится его фильтровать.
- Этот факт привел к правилу: если Вы делаете что-то (получаете спам или что-то еще), что мешает работе системы - Ваши письма не будут приниматься и Вы можете быть временно заблокированы.
- Для успешного приема письмо должно пройти следующую цепочку фильтров:
- Все письма, которые не смогли быть доставлены, отклоняются.
- При слишком большом количестве писем с одного IP они перестают приниматься.
- Слишком много писем с одинаковой темой не принимаются.
- Письма, содержащие в заголовках запрещенные сервисом слова, также не попадают в почтовые ящики.
- Выживание в условиях наплыва писем с одного IP адреса:
- Для этого типа фильтрации используется AgingHashMap. Когда сервис получает очередное письмо, IP помещается в массив и счетчик, соответствующий этому ключу, увеличивается на единицу в момент получения каждого последующего письма с этого IP.
- Спустя определенное время без получения писем с IP, соответствующие ему счетчик обнуляется.
- Когда счетчик достигает определенного порога, IP блокируется, предотвращая поток сообщений.
- Этим простым методом пользуются многие интернет-ресурсы для защиты различных своих компонентов, например комментариев. В роли хранилища для такого массива при распределенном функционировании системы часто используют memcached.
- Защита от "зомби" атак:
- Спам может приходить и с больших координированных сетей с разными IP адресами, как раз участников таких сетей и называют "зомби". Одинаковые письма приходят со множества разных адресов, так что защита по IP адресам становится бессильна.
- Этот фильтр несколько более сложный, чем блокировка по IP, так как требуется достать из письма строку с заголовком, да и их сравнение - несколько ресурсоемкая задача.
- Когда около 20 писем с одинаковыми темами приходят в течении 2 минут, этот заголовок блокируется на час.
- Что интересно, Mailinator не хранит заблокированные темы вечно, так как это значило бы, что этот список неуклонно рос и приходилось бы вечно отслеживать соответствия с ним. Это никак не приемлемо для мимолетной природы Mailinator. Более комплексные алгоритмы защиты от спама нужны лишь только если ставятся цели с более жесткой борьбой со спама, для Mailinator же данный вариант - наиболее эффективный.
- Этим фильтром блокируется около 9% писем.
- Mailinator фильтрует сообщения только по теме и IP, так что системе не приходится прочитывать и анализировать все письмо целиком. Это позволяет неплохо сэкономить на вычислительных ресурсах при достаточно эффективной итоговой фильтрации.
- Для уменьшения угрозы DDoS атак:
- Все соединения, неактивные какое-то время обрываются.
- Mailinator отвечает отправителям писем очень медленно, 10, 20 или даже 30 секунд, даже для небольших объемов данных. Это замедляет работу спаммеров, пытающихся отправлять спам как можно быстрее, и заставляет их лишний раз задуматься о целесообразности отправки снова спама на этот адрес. Период ожидания уменьшается во время повышенных нагрузок на сервис, так что письма не теряются из-за этого.
Подводим итоги
- Идеальность - всего лишь ловушка. Как много систем были кардинально усложнены лишь для того, чтобы достичь 100%-го результата во всех аспектах. Если Вы участвовали в подобных совещаниях, Вы понимаете о чем идет речь. О нет, мы не можем сделать этого, так как есть 0,01% шанс, что что-то пойдет не так. Лучше спросите себя: насколько неидеальными можно позволить себе быть, чтобы все равно оставаться достаточно неплохим сервисом?
- То, что Вы отвергаете, ничуть не менее важно, чем то, что Вы оставляете в системе. Существует масса концепций по построению архитектуры системы. Нужно не только выбрать подходящие, но и отказаться от тех, которые излишни.
- Знайте предназначение своей системы и разрабатывайте ее в соответствии с этим. Быть всем для всех значит быть ничем для никого. Временное хранение электронных писем, позволяя небольшой части спама пробиться через фильтры, в совокупности с не 100% временем работы системы производят достаточно хорошее впечатление на пользователей. Построение собственного SMTP-сервера необходимо лишь в случае, если у Вас есть весомые аргументы в пользу того, что он Вам необходим. Далеко не факт, что такая идея придет в голову, возможно выбор пал бы и на более тривиальное решение, связанное просто с добавлением дополнительного оборудования.
- Постарайтесь как можно быстрее свести механизм работы системы к наиболее общему случаю. Очень большой процент писем отвергается, так что это оправданно сделать это как можно раньше, чтобы минимизировать ресурсы, требуемые для их обработки. Найдите способ сделать это как можно быстрее в отношении наиболее частых случаев. то очень часто становится важным компонентом стратегии масштабирования.
- Эффективность часто означает "постройте это самостоятельно". Готовые решения обычно решают большой спектр задач, но на практике часто нужна лишь небольшая часть функционала, в таких случаях можно написать небольшой компонент с нуля самостоятельно, чтобы он мог выполнять только нужные функции, но более эффективно.
- Небольшое количество сбоев - вполне допустимо. Все заблокированные адреса не должны быть запомнены навечно. Позвольте этим спискам генерироваться на основе локальных данных, а не глобального состояния. Это очень простая и эффективная архитектура.
- Java совсем не обязательно должна быть медленной. На эту тему сказано уже достаточно.
- Избегайте работы с жесткими дисками. Многие приложения требуют работы с дисковой системой, но очень часто именно она оказывается узким местом в системе. Можете ли Вы обойтись без него, используя более креативные подходы к архитектуре системы?
- Ограничте использование ресурсов. Задайте рамки для размеров почтовых ящиков и других подобных элементов системы, это позволит избежать неконтролируемых скачков нагрузок. Неограниченное использование ресурсов недопустимо при ограниченности ресурсов.
- Сжимайте данные. Компрессия данных может стать неплохим достижением в попытках сэкономить оперативную память. Можно сократить использование памяти вдвое с лишь небольшой дополнительной нагрузкой, связанной с компрессией и декомпрессией информации. Если обмен данными происходит локально, достаточно лишь закодировать данные и предоставить API для доступа к данным без полной декомпрессии.
- Используйте фиксированные объемы ресурсов для обработки запросов. Многие приложения не могут контролировать используемые ресурсы, в частности - оперативную память, таким образом они могут порой давать сбой при использовании излишне больших ее объемов. Для более стабильной работы стоит ограничить используемые ресурсы и откладывать выполнение новых задач пока они используются полностью. Для управление доступом к ресурсам можно использовать определенную логику в зависимости от ситуации: по времени, по приоритету, "честный" доступ, но так как ресурсы ограничены, система несколько ослабнет под серьезной нагрузкой.
- Если данные не хранятся длительное время, они не могут стать причиной возбуждения судебного дела о нарушении чьих-либо прав.
- Пользуйтесь тем, что знаете лучше всего. Этот урок не раз оправдывал себя. Paul знал Java лучше, чем что-либо еще, именно по-этому он заставил приложение на этом языке работать и выполнить все поставленные задачи.
- Найдите свои собственные Mailinator'ы. Конечно, Mailinator является очень небольшой системой. В более крупной системе этот проект был бы лишь небольшой дополнительной возможностью, но такие системы обычно состоят просто из нескольких подпроектов размером с Mailinator. А что если подойти к разработке некоторых из них так же как и к Mailinator?
- KISS работает, правда довольно редко. Простота систем часто обсуждается, но практические примеры появляются достаточно редко. Чаще всего разговор остается на уровне: твоя система сложная, а моя - простая, просто так как она моя. Mailinator является хорошим примером простой архитектуры системы.
- Надежность является функцией архитектуры системы. Для построения системы, эффективно использующей память и выживающей серьезные атаки спаммеров, потребовалось серьезно подойти к каждому уровню ее архитектуры.