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

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

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

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

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

«Толпа» в краудсорсинге мгновенно сработала в моем инженерном мозгу: будет много людей, работающих одновременно, ожидающих хорошего производительность из любой точки мира. Мне понравился вызов.

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

  • Скомпрометированный экземпляр Wordpress, на котором запущены сотни устаревших ошибочных плагинов, запущенный на виртуальной машине на общем сервере.
  • Взломанные почтовые ящики
  • Множество документов и таблиц Google.

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

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

От Wordpress к веб-приложению

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

Вам необходимо разобраться в своих данных, а восстановление данных из разных источников в разных форматах будет огромной тратой времени. Wordpress может быть очень хорошим выбором во многих случаях, сэкономив довольно много времени на разработку, но для своих нужд команде Visage пришлось установить причудливые плагины, которые больше не поддерживаются. В результате у нас не было контроля над созданной моделью данных, и данные, которые не могли соответствовать модели, были разбросаны по десяткам документов и таблиц.

Поэтому, если нет продукта, который уже соответствует 90% вашим потребностям, подумайте об идеальной модели данных и дизайне и внедрить минимально жизнеспособный продукт (MVP), который сможет хранить все ваши данные.

Тогда подумайте о API. У вашего приложения должен быть API, он будет иметь решающее значение, когда вы в конечном итоге его продадите. Не масштабируйте сразу, но кодируйте с учетом масштабируемости. Сделайте свой API без состояния и как можно более RESTful, поскольку каждый будет рассчитывать на возможность запрашивать его с помощью стандартных методов HTTP.

В нашем случае мы выбрали NodeJS, потому что большая часть нашего кода будет просто обрабатывать входные и выходные данные. NodeJS не блокирует и поставляется с библиотекой, удобной для разработки API: ExpressJS.

Если вам нужен веб-сайт, ориентированный на клиентов, у вас есть несколько вариантов. Сначала вы можете создать слой на своем сервере приложений, который будет генерировать ваши страницы, или вы можете создать приложение Одностраничный Javascript, которое будет обслуживаться статическим сервером веб-хостинга.

В Visage мы выбрали второй вариант и решили создать одно приложение для пользователей и одно для администраторов. Это было просто потому, что у нас были бы гораздо большие ожидания от пользователей, чем мы необходимо с администраторами, и хотел, чтобы обе кодовые базы были простыми (а также для рассмотрения CORS в дальнейшем). Вот как выглядела наша система:

Делегируйте хранение конфиденциальных данных на ранней стадии

Если это не критично для вашего бизнеса, нет веских причин для хранения конфиденциальных личных данных в ваших системах. Безопасность - это сложный вопрос, и если вы изменяете свой код каждый день, пока не найдете, что ваш продукт подходит для рынка, он сломается. Предположим, что кто-нибудь злонамеренный может взломать ваше приложение, если действительно захочет.

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

Например, Auth0 - это наиболее известная третья сторона, выполняющая аутентификацию. Stripe - тоже хороший вариант для онлайн-платежей. Они посвятят все свои ресурсы и лучшие команды специалистов по безопасности на планете, чтобы обеспечить безопасность ваших данных - в противном случае у них нет бизнеса .

Облачные сервисы - ваши лучшие друзья

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

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

К счастью, мы живем в то время, когда всего один разносторонний инженер может легко создать такую ​​систему за пару дней, используя облачные сервисы, такие как Amazon Web Services, Google Cloud Services или Лазурный. Мы решили перенести наши системы на AWS, потому что на тот момент это было наиболее полное решение, и у нас были 2 года бесплатных кредитов.

Вот почему в этом посте я в основном буду говорить о решениях AWS, но есть аналогичные сервисы на других платформах. Это также время, когда мы решили запустить наши модули в контейнерах Docker по множеству других причин, которые не будут описаны в этом сообщении (вы можете проверить это статья для получения дополнительной информации: https://medium.freecodecamp.org/amazon-fargate-goodbye-infrastructure-3b66c7e3e413).

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

Нет хорошего или плохого ответа.

Вы можете поместить все свои модули в контейнеры и использовать систему управления контейнеров, например ECS / EKS в AWS или движок Kubernetes в GCP. Если нет и вы не хотите самостоятельно заниматься такими вещами, как автоматическое масштабирование и балансировка нагрузки, вы можете использовать Elastic Beanstalk или App Engine.

Если вы хотите полностью перейти на бессерверную версию, вы также можете объединить использование лямбда-функций и API-шлюза. Мы решили перейти на ECS. Мы развернули 3 экземпляра в 3 зонах доступности, балансировщик нагрузки, настроили автоматическое масштабирование в зависимости от использования ЦП, интегрировали журналы всех наших контейнеров с Cloudwatch и настройте показатели для отслеживания ошибок, внешних вызовов и времени ответа API.

Для нашей базы данных мы использовали MongoDB, потому что наша модель хорошо подходит для базы данных NoSQL и из-за ее высокой согласованности. Мы решили воспользоваться MongoDB Atlas и развернули 3 реплики, чтобы обеспечить высокую доступность. Помимо других услуг, Atlas предоставляет автоматическое масштабирование, автоматическое резервное копирование и позволяет вам легко вернуться назад во времени в случае аварии.

Мы также решили разместить все наши статические веб-файлы в S3 и использовали Cloudfront в качестве CDN, чтобы наши JS-приложения могли загружаться очень быстро в любом месте world и обслуживаться столько раз, сколько требуется. Cloudflare также является хорошим вариантом и предлагает защиту от DDOS из коробки.

Для простоты мы решили использовать Route 53 в качестве нашего DNS, используя их серверы имен для всех наших доменов. Это один из моих любимых сервисов на AWS. Это делает вашу жизнь намного проще. Каждый раз, когда вы хотите обслуживать что-то через доменное имя, будь то экземпляр EC2, эластичный IP, балансировщик нагрузки, Cloudfront распространение или что-то действительно, частное или публичное, это займет у вас несколько минут, потому что оно так хорошо интегрировано со всеми другими сервисами.

Совместите это с диспетчером сертификатов, который позволяет вам бесплатно получить сертификаты SSL (включая подстановочные знаки) за считанные минуты и развернуть их на всех ваших серверах, установив флажок, и вы у вас есть самый быстрый и надежный способ включить HTTPS во всех ваших модулях. До свидания SSL-сертификаты «Let's Encrypt», которые мне приходилось обновлять и устанавливать на моих серверах примерно каждые 3 месяца 😅.

Определитесь со стратегией кеширования

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

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

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

Мы начали рассматривать использование memcached, потому что часто запрашивали одни и те же профили кандидатов и предложения о работе снова и снова. Внедрение его на компьютере с оптимизацией памяти повысило производительность нашего API более чем на 30%, если мы усредним время ответа на все запросы в день. Memcached также распространяется, поэтому он может работать на разных серверах, но при этом действовать так, как будто это всего лишь одна большая область памяти для хранения ваших объектов.

Местоположение, местоположение, местоположение

Теперь у нас есть распределенная система, в которой нет единой точки отказа (если вы рассматриваете AWS ELB и распределенный memcached), и можно автоматически масштабировать вверх и вниз. Мы также используем кеширование, чтобы свести к минимуму передачу данных по сети. Выглядит неплохо. На этом этапе вы, вероятно, захотите проверить своих третьих лиц, чтобы увидеть, будут ли они воспринимать нагрузку так же, как вы.

Но все же некоторые из наших пользователей жаловались, что приложение работает для них немного медленнее, особенно когда они загружали файлы. Действительно, даже если наши статические веб-файлы кэшировались по всему миру (любезно предоставлено CDN), все наши серверы приложений были развернуты только на западе США. Пользователи из Восточной Азии столкнулись с гораздо большей задержкой, особенно при передаче больших данных.

Решение оказалось простым: разверните точно такой же кластер ECS в новом регионе в Азии вместе с новым балансировщиком нагрузки и используйте Route 53 Geoproximity Routing для маршрутизации пользователей к «ближайшему» подсистеме балансировки нагрузки. MongoDB Atlas также позволяет развертывать ваши реплики в регионах, поэтому никаких дополнительных действий не требуется.

Заключение

Хотя распределенная система, которую вы видите здесь, была упрощена для этого поста, мы изучили те части, которые вы, скорее всего, встретите во многих современных веб-приложениях. Другие темы, связанные, но не затронутые, - это архитектура микросервисов, хранение и шифрование файлов, сегментирование базы данных, запланированные задачи, асинхронные параллельные вычисления… возможно, в следующем посте!

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

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

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

Если вам понравилась эта статья и вы нашли ее полезной, нажмите эту кнопку и подписывайтесь на меня, чтобы увидеть больше статей по архитектуре и разработке! 🤓