Sun Mar 29 2026
...
FastComments е готов за космоса!
! Тази статия съдържа технически терминология
Какво ново
Всеки point-of-presence на FastComments сега записва локално и асинхронно ги репликира към всички останали възли. Това ще осигури увеличена издръжливост в сравнение с предишната система, както и ще направи инструментите за модериране по-бързи за потребителите в някои региони, с някои компромиси.
"Готов за космоса" звучи малко оптимистично, но идеята е, че можем да внедрим FastComments на различни планети и в крайна сметка системата ще бъде синхронизирана. Потребителите на Плутон, обаче, ще трябва да изчакат около ден, за да видят промените отразени на страницата си с предстоящи фактури, тъй като в момента само един основен възел на регион може да агрегира информация за фактури.
Някои истории, защо промяната
Когато FastComments първоначално стартира, имаме много типична архитектура. Имахме прокси слой, приложение слой, база данни, няколко реплики, след това по-късно реплики в различни региони и облачни доставчици за допълнителна издръжливост.
В крайна сметка преместихме репликите на базата данни във всички зони, където се намират повечето от нашите потребители и също така разположихме приложението там, и създадохме наша собствена DNS и прокси система (описана в по-късна статия в блога), за да насочим заявките към най-близкия възел на приложението. Това прави четенето бързо, но записите по-бавни, тъй като сега вместо да чакаме за един HTTP рунд, вие чакате за HTTP рунд до близкия възел, а този възел може да прави множество записвания обратно към основния. Не е добре!
Така че, за да се справим с това, реорганизирахме много области на приложението, за да приемем параметъра readPreference в аргументите на функциите, така че повикващите да могат да решат колко
остарели могат да бъдат четенето им, а освен това направихме повече записвания (като записване на статистики за модераторите по действия на модератора) да се изпълняват в стил fire-and-forget. Не е идеално, но значително ускори процесите.
Една от проблемите, с които се сблъскахме при глобалното използване на Mongo, са мрежовите разделяния. Ако достатъчно възли бъдат прекъснати, четенето спира, тъй като всеки възел става несигурен дали е приемливо да предоставя четене. Има няколко начина да се заобиколи това, но краен случай става хаотичен. Това не е теоретичен проблем - случи се достатъчно пъти, причинявайки викове в 3 сутринта, така че се изморихме от него, дори опитвайки се да настроим Mongo да бъде ОК с несигурността на изборите на репликационен набор за до една минута разлика. За съжаление, мрежите от Санта Паол до Фалкенщайн, например, просто не бяха много добри през някои от нашите хостинг доставчици. Настройването на контрола на задръстванията и подобно помогна, но не реши проблема.
Светият граал на решението, при условие че сте ОК с определени компромиси, е способността да приемате записите локално на този възел (който има приличен хардуер, RAID и т.н., който вероятно няма да се повреди) и да уведомите потребителя, че данните му са запазени. Можете също така в тази точка на присъствие да имате втори възел като гореща реплика за издръжливост.
Така че това е до което стигнахме. Орегон, Вирджиния, Фалкенщайн, Санта Паол, Сингапур, са всички свои собствени репликационни набори и приемат записи. Разполагането в ЕС (въпреки че има само три PoPs) има същото поведение.
Как работи
Някои от това са отразени в предишната секция, но TL;DR е, че е CRDT-lite. Създадохме прокси (на Rust, защото, разбира се), който седи между приложението и Mongo и го прави много-основен. Прокси е ориентиран към връзки, управлява контрольни точки, репликация, мониторинг и инициална синхронизация. Това е много-основно заместване на репликационната система на Mongo, включително за някои DDL команди.
Разликата от другите инструменти е, че този не следи oplog. Следенето на oplog, или използването на потоци от промените, няма да работи, тъй като те показват само крайното състояние на обекта след записа, което прави невъзможно справянето с конфликти. Трябва да уловите
всяка операция $set, $inc и да репликирате самата операция.
Това е решение, специфично за домейн. Няма да работи за всички продукти. Можете да кажете, че е проектиране, ориентирано към домейн :). Работи за нас, защото от самото начало много внимателно само $set полетата, които променяме в документите - никога не използваме replaceOne на Mongo, например. Същото важи и за броячите. Вие никога не правите SET VOTES = 5. Вместо това, вие напишете INCREMENT VOTES BY 5, тъй като това позволява евентуална консистентност. Разпределените заключвания се управляват, като се избягват напълно. Само един възел
на кластер има флаг, зададен за работа с cron задачи. Въпреки че това може да изглежда ограничено, можем да закупим сървъри с терабайти RAM, така че можем да приемем този компромис, за да понижим риска и сложността.
Четене на вашите собствени записи
За разработчиците, използващи API, трябва да можете да четете своите собствени записи точно както преди (направете API повикване за създаване на коментар, след това изброете коментарите и вижте новия запис в този списък). Условието е, че не можете да направите това между регионите. Ако вашето приложение работи само в един регион, като нас-запад, тогава трябва да можете да четете своите собствени записи, с изключение на случая, когато между вашия запис и вашето четене, този възел спре да функционира и вашият DNS кеш се обновява, за да сочи към следващия най-близък възел. При условие, че това не се случи, четенето на вашите собствени записи е надеждно.
Тестове и миграция
Около половината от кода в системата е тестовия пътека, рамка и тестове. Въпреки това, пускането беше малко неспокойно, отнемайки повече време за спиране (1 час за ЕС и 20 минути за нас-глобално), отколкото желаехме, но сме щастливи, че преминахме този етап и ви благодарим за търпението!
В заключение и какво означава това за вас
FastComments сега трябва да бъде по-бърз и по-издържлив от всякога и сега можем да се върнем към работа по нови функции :)
Наздраве!
