Wed Sep 10 2025
...
FastComments теперь имеет глобальное распределение
Что нового
Ранее FastComments имел очень традиционную архитектуру для веб-приложения. У нас были серверы приложений, базы данных и несколько других сервисов. Это было дублировано в двух регионах (us-west и eu). Если бы вы находились во Франции и хотели просмотреть обсуждение комментариев для клиента, размещенного в нашем глобальном дата-центре, ваши запросы должны были бы пройти весь путь до us-west для получения данных о комментариях.
Больше этого не происходит! Теперь данные о комментариях и все медиа-ресурсы реплицируются глобально для клиентов в нашем глобальном развертывании, а для клиентов в нашем развертывании в ЕС у нас есть три точки присутствия в ЕС, где данные реплицируются. Ваши запросы поступают на ближайший узел в ЕС.
Как это работало раньше
За исключением баз данных, которые имели несколько активных реплик в различных регионах и облачных провайдерах, все сервисы разворачивались на одной инстанции для каждого типа сервиса. Это означало, что для каждого региона у нас был один сервер приложений, один сервер pubsub и один медиа-сервер. План заключался в вертикальном масштабировании в то время, когда это было возможно, так как это упрощало процессы. Написание кода было простым - вы всегда знали, что можете "читать свои собственные записи", обращаясь к базе данных. Инфраструктура была простой, за исключением обновлений безопасности, которые занимали минуту простоя.
Проблема
Проблема, очевидно, начиналась, когда мы достигали предела емкости. Мы оптимизировали, а затем в конечном итоге приходилось увеличивать размер инстанции для этого сервиса.
Это начало становиться затратным на Linode, где инстанция за $144 примерно эквивалентна, по нашим тестам passmark, узлу за $20 от OVH, и даже если мы сменим хостинг-провайдеров, у нас будут единые точки отказа повсюду - и провайдеры, такие как OVH, имеют тенденцию к более длительным временам решения проблем с техническим обслуживанием по сравнению с Linode.
RiR :)
В первые несколько лет сервисы PubSub и Media в FastComments были написаны на Java. Java была выбрана за относительную высокую производительность за затрату сил и после многих лет настройки сборщика мусора, испытания G1GC, Shenandoah и Z1, мы решили отказаться от Java. Переполнение памяти было просто слишком большим, и так как эти сервисы были довольно статичны по завершении, преимущества Java истощились. Также эти сервисы, как правило, сталкивались с проблемой "громадного потока", что означало, что JVM пыталась справиться с пиковыми нагрузками, когда JIT даже не начал работать. Эти сервисы были первыми кандидатами для перехода на C++ или Rust.
Rust был выбран, так как мы не являемся экспертами в C++, и ошибка в сетевом коде могла бы раскрыть данные одного клиента другому. Rust помогает предотвратить такие проблемы.
Мы хотели консолидировать эти сервисы в любом случае, поэтому, хотя мы могли бы сделать еще одну попытку оптимизации их возможно с GraalVM, мы решили перейти на Rust и завершить это.
Миграция не прошла без проблем. Эти сервисы должны завершать SSL, поддерживать HTTP 1.1, HTTP/2 и так далее. Они выполняют такие задачи как управление многими потоками данных одновременно, чтение медиа из кэша lru на диске с учетом расстояния, S3, баз данных и общение в сетевой структуре. Экосистема Java, Vertx и Netty, была очень хороша для таких задач. Мы толкаем библиотечную экосистему на пределе возможностей, и так как у нас не так много опыта с библиотеками Rust, это означало, что нам пришлось пройти через некоторые испытания и ошибки. Это вызвало некоторый простой, и мы приносим извинения за это.
Мы также экспериментировали с различными менеджерами памяти, остановившись на mimalloc для наших кастомных DNS-серверов и libc для транспортного уровня. Мы не запускаем Nginx или Apache, вместо этого используем нашу собственную комбинацию кастомного DNS-сервера, который маршрутизирует клиентов глобально на основе индекса в памяти, пересобираемого еженедельно из Maxmind, и нашего транспортного уровня на Rust, который поддерживает сетевой узел с другими транспортными инстанциями. Транспорт завершает SSL, обрабатывает работу pubsub и является нашим CDN. Преимущество этого состоит в снижении накладных расходов при перемещении вещей между сервисами и меньшей накладной/абстракцией инфраструктуры. Недостаток заключается в видимости, поэтому хорошие метрики важны.
Что касается полученной производительности, сервисы на Rust использовали около 10-30% памяти от Java-версий, несмотря на все наши усилия. Я читаю книги, такие как «Java Concurrency in Practice», для удовольствия, так что хотя я не эксперт, я знаю пару вещей о написании быстрых сервисов JVM, и сделать это с Rust было намного проще. Кроме того, всплески сообщений к большому количеству подписчиков едва регистрируются в использовании ЦП, когда сервисы JVM тратят 40% своего времени на сборку мусора, несмотря на то, что мы пишем наш код больше как игровой движок и меньше как обычный сервер. Я не могу сказать, что я большой фанат Rust, но для услуг, которые выполняют много работы и не изменяются после первоначальной разработки, он идеален. Наша основная бизнес-логика остается на TypeScript.
Новая архитектура
В новой архитектуре больше нет узлов "питомцев". Вместо этого каждый сервер является полным клоном со всеми теми же сервисами и почти идентичной конфигурацией. Каждый из них выполняет транспорт, DNS, сервер приложений и копию базы данных. Все узлы поддерживают полное шифрование диска с автоматической разблокировкой с помощью Dropbear.
Каждый сервер запускает транспортный маршрут, который завершает запросы и обрабатывает их как либо вебсокет, http поток или cdn запрос. Эти сервера соединяются друг с другом, и любой из них предоставляет отображение глобальной сети к своему локальному DNS-серверу, чтобы в реальном времени сообщать DNS, где находятся все живые узлы глобально.
Одним из преимуществ новой архитектуры является избыточность. Если на нас сильно нагружает клиент в одном регионе, другие регионы остаются онлайн.
Код приложения теперь должен быть очень внимательным к тому, какие запросы могут попасть на ближайший узел или какие должны идти к первичной базе данных, которая может находиться далеко. Ошибка может резко снизить производительность. Это также означает, что записи из некоторых регионов могут быть медленными, и это требует аккуратной настройки и оптимизации. Теперь мы следуем внутреннему паттерну в коде, где все методы, которые обращаются к базе данных, принимают аргумент readPreference, таким образом, вызывающие методы до самого верха должны явно решать, как выполнить запрос.
Преимущество - это очень хорошее горизонтальное масштабирование для чтений. FastComments очень активно используется для чтения, но мы не должны забывать о наших модераторах! Модераторы работают день за днем по всему миру и мы хотим, чтобы их опыт оставался хорошим. В рамках этого развертывания мы работали с несколькими из них, чтобы убедиться, что инструменты модерации остаются быстрыми.
Мы также можем самостоятельно выбирать оборудование, что приятно и вознаграждающе. Новые серверы представляют собой смесь i5-13500 и Ryzen 5 5600X, а в ЕС используются более старые Xeon. В наших бенчмарках все они оказались значительно быстрее, чем более дорогие серверы, которые мы рассматривали у других провайдеров. Недостаток заключается в большем объеме начальной настройки, но мы автоматизировали это, наряду с мониторингом SMART дисков на предмет сбоев и так далее.
Выполнение таких действий позволяет нам продолжать предлагать конкурентоспособные цены.
Развертывание
Развертывание за последние несколько месяцев, пока мы переписываем услуги и переходим к новым хостинг-провайдерам, было непростым, мы благодарим вас за терпение.
На начальном этапе развертывания наши метрики показали увеличение запросов, занимающих > 100ms. Мы стараемся избегать многих запросов, занимающих столько времени.
Мы все еще постепенно улучшаем производительность для некоторых регионов. Спасибо всем, кто предоставил отзывы на сегодняшний день.
Важные моменты при использовании API
API остается строго консистентным - вы можете читать свои собственные записи - чтобы поддерживать обратную совместимость и держать все просто для разработчиков. Чтобы позволить разработчикам выбирать производительность вместо согласованности, мы планируем открыть параметр readPreference. Преимущество заключается в том, что мы также можем предложить скидку на кредиты для этих API-вызовов.
Все публичные конечные точки, такие как для предоставления публичного виджета комментариев, всегда считывают данные из ближайшей (локальной) базы данных на этом узле.
Почему не просто использовать обычный CDN
Обсуждения комментариев не статичны, они живые, и применение живого потока к устаревшим статическим данным также не работает, так как когда вы просматриваете обсуждение как анонимный пользователь, вы получаете "анонимную сессию". В этой анонимной сессии вы можете делать такие вещи, как блокировка и сигнализация других пользователей, и вам нужно показать, нравится ли анонимному пользователю данный комментарий и так далее. Обсуждения комментариев также могут быть закрыты за SSO, аутентификацией или группами пользователей.
Наконец, тип "прогрессивного улучшения", при котором динамические данные сопоставляются со статическими данными из CDN, приводит к плохому опыту, когда контент перемещается или изменяется через несколько секунд. Нам бы не хотелось этого делать.
Кто сейчас имеет мои данные
Ваши данные больше не хранятся на Linode. Они реплицируются в реальном времени между Hetzner и OVH с полным шифрованием диска, и все коммуникации между бекенд-серверами осуществляются с помощью TLS. Мы сохраняем несколько устаревших инстанций Linode для исходящих прокси вебхуков, но никаких данных или медиафайлов больше не остается на Linode.
В заключение
Как и все основные релизы, мы рады, что смогли выделить время для оптимизации, тестирования и правильного выпуска этого изменения. FastComments должен лучше масштабироваться и иметь большую доступность в долгосрочной перспективе благодаря этой работе. Дайте нам знать ниже, если вы обнаружите какие-либо проблемы.
