FastComments.com Blog

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, для развлечения, так что хотя я не эксперт, я знаю пару вещей о написании быстрых серверных Java-сервисов, и достичь этого с Rust было намного проще. Кроме того, всплески сообщений для большого числа подписчиков с трудом отражали загрузку процессора, в то время как Java-сервисы тратили 40% своего времени на сборку мусора, несмотря на то, что мы писали наш код больше как игровой движок и меньше как типичный сервер. Я не могу сказать, что я большой фанат Rust, но для сервисов, которые выполняют много работы и не меняются после начальной разработки, это идеально. Наша основная бизнес-логика остается на TypeScript.

Новая архитектура

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

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

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

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

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

Мы также можем выбирать оборудование, что интересно и приятно. Новые серверы представляют собой смесь i5-13500 и Ryzen 5 5600X, а в ЕС используются старые многоядерные Xeon. В наших бенчмарках все это оказались намного быстрее, чем более дорогие серверы, которые мы изучали у других провайдеров. Недостаток - это больше работ по настройке, но мы автоматизировали это, а также мониторинг SMART дисков на наличие сбоев и прочее.

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

Развертывание

Развертывание за последние пару месяцев, пока мы переписываем сервисы и переходим к новым хостинговым провайдерам, было не без проблем, мы благодарим вас за ваше терпение.

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

Постепенный прогресс
Медленные запросы

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

Соображения при использовании API

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

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

Почему не использовать обычную CDN

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

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

Кто владеет моими данными сейчас

Ваши данные больше не хранятся на Linode. Они реплицируются в реальном времени между Hetzner и OVH с полным шифрованием диска, и все коммуникации между серверами бэкенда производятся с помощью TLS. Мы поддерживаем несколько устаревших экземпляров Linode для прокси-вебхуков, но никаких данных или медиа-файлов больше не хранится на Linode.

В заключение

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