FastComments.com Blog

Sun Mar 29 2026
...

FastComments готов к космосу!

! Эта статья содержит технический жаргон

Что нового

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

"Готов к космосу" звучит несколько оптимистично, но идея заключается в том, что мы могли бы развернуть FastComments на разных планетах, и в конечном итоге система синхронизируется. Однако пользователям на Плутоне придется ждать около суток, чтобы изменения отразились на странице их предстоящего счета, так как в настоящее время только один мастер на регион может агрегировать информацию о счетах.

Немного истории, почему изменения

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

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

Чтобы справиться с этим, мы реорганизовали многие области приложения, чтобы использовать readPreference в аргументах функции, позволяя вызывающим решать, насколько устаревшими они могут быть со своими чтениями, и сверху этого сделали больше записей (например, запись статистики модератора по действиям модератора) "fire-and-forget". Не идеально, но это значительно ускорило процессы.

Одной из проблем, с которой мы столкнулись, работая с Mongo во всем мире, являются сетевые разделения. Если достаточно узлов отключаются, чтения останавливаются, поскольку каждый узел становится неопределенным, допустимо ли обслуживать чтения. Есть некоторые способы обойти это, но крайние случаи запутаны. Это не теоретическая проблема - это происходило достаточно часто, вызывая страницы в 3 часа утра, и мы устали от этого, даже пытаясь настроить Mongo так, чтобы он был готов к неопределенности выборов реплик на минуту. К сожалению, сети от Сан-Паулу до Фалькенштейна, например, просто не очень хорошо работали через некоторых наших провайдеров хостинга. Настройка контроля перегрузки и тому подобное помогла, но не решила проблему.

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

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

Как это работает

Некоторые из этого уже описаны в предыдущем разделе, но краткое содержание таково: это CRDT-lite. Мы создали прокси (на Rust, потому что, конечно же), который находится между приложением и Mongo и делает его многомастером. Прокси осведомлен о пирах, управляет контрольными точками, репликацией, мониторингом и первоначальной синхронизацией. Это замена многомастера для системы репликации Mongo, включая некоторые команды DDL.

Разница с другими инструментами состоит в том, что этот не отслеживает oplog. Отслеживание oplog или использование потоков изменений не сработает, потому что они показывают только окончательное состояние объекта после записи, что делает невозможным обработку конфликтов. Вам нужно захватить каждую операцию $set, $inc и реплицировать саму эту операцию.

Это решение, специфичное для домена. Оно не сработает для всех продуктов. Можно сказать, что это основанное на домене проектирование :). Это работает для нас, потому что с самого начала мы очень внимательно только $set поля, которые изменяем в документах - например, мы никогда не используем replaceOne в Mongo. То же самое и с счетчиками. Вы никогда не делаете SET VOTES = 5. Вместо этого вы бы написали INCREMENT VOTES BY 5, так как это позволяет обеспечить конечную согласованность. Распределенные блокировки обрабатываются абсолютным избеганием их. Только один узел на кластер имеет установленный флаг для запуска cron. Хотя это может показаться ограниченным, мы можем покупать серверы с терабайтами RAM, так что мы можем пойти на этот компромисс, чтобы снизить риски и сложность.

Чтение своих собственных записей

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

Тестирование и миграция

Около половины кода в системе - это тестовый каркас, фреймворк и тесты. Тем не менее, выпуск был немного неровным, заняв больше времени простоя (1 час для ЕС и 20 минут для глобального) чем планировалось, но мы рады, что преодолели этот этап и благодарим вас за ваше терпение!

В заключение и что это значит для вас

FastComments теперь должен быть быстрее и устойчивее, чем когда-либо, и теперь мы можем вернуться к работе над функциями :)

Ура!