Sun Mar 29 2026
...
FastComments готовий до космосу!
! У цій статті міститься технічна термінологія
Що нового
Кожен point-of-presence FastComments тепер приймає записи локально та асинхронно реплікує їх на всі інші вузли. Це забезпечить підвищену надійність у порівнянні з попередньою системою, а також зробить модераційні інструменти швидшими для користувачів у деяких регіонах, з певними компромісами.
"Готовий до космосу" - це трохи оптимістично, але ідея полягає в тому, що ми можемо розгорнути FastComments на різних планетах, і врешті-решт система буде синхронізована. Користувачі на Плутоні, проте, повинні будуть чекати близько доби, щоб побачити зміни на своїй сторінці майбутнього рахунку, оскільки лише один головний вузол на регіон зараз може збирати інформацію про виставлення рахунків.
Трохи історії, чому зміна
Коли FastComments спочатку запустився, у нас була дуже типова архітектура. У нас був проксі-шар, шар додатку, база даних, деякі репліки, а потім пізніше репліки по регіонах і постачальниках хмар для додаткової надмірності.
Згодом ми перемістили репліки бази даних до всіх зон, де знаходиться більшість наших користувачів, і теж розгорнули додаток там, і створили свою власну систему DNS і проксі (описану в наступному блозі), щоб направляти запити до найближчого вузла програми. Це робить читання швидким, але записи повільнішими, оскільки тепер замість того, щоб чекати на один раунд HTTP до бекенду, ви чекаєте на раунд HTTP до ближнього вузла, а цей вузол може виконати кілька записів до бази даних назад до основного. Неприємно!
Отже, щоб боротися з цим, ми переробили багато областей програми, щоб приймати readPreference в аргументах функцій, так що викликачі можуть вирішити, наскільки старими можуть бути їхні читання, і на додаток до цього зробили більше записів (як запис статистики модератора на дії модератора) "вогонь і забути". Не ідеально, але це значно прискорило процес.
Однією з проблем, з якою ми стикнулися, запускаючи Mongo по всьому світу, є мережеві розділення. Якщо достатню кількість вузлів відключити, читання зупиняється, оскільки кожен вузол стає невпевненим, чи прийнятно обслуговувати читання. Існують деякі способи уникнути цього, але крайні випадки стають заплутаними. Це не теоретична проблема - це сталося достатню кількість разів, викликавши дзвінки о 3 годині ночі, що ми втомилися від цього, навіть намагаючись налаштувати Mongo, щоб він міг впоратися з невизначеністю виборів реплікаторів до однієї хвилини. На жаль, мережі між Сан-Паулу та Фалькенштайном, наприклад, просто не були дуже добрими у деяких наших постачальників хостингу. Налаштування контролю за заторами та подібні речі допомогли, але не вирішили проблему.
Святим граалем рішення, якщо ви готові приймати певні компроміси, є можливість приймати записи локально на цьому вузлі (який має пристойне обладнання, RAID тощо, що навряд чи вийде з ладу) і повідомити користувачу, що його дані збережені. Ви також можете в цьому пункті присутності мати другий вузол як гарячу репліку для надійності.
Отже, до цього ми і дійшли. Ореґон, Вірджинія, Фалькенштайн, Сан-Паулу, Сінгапур - всі вони є власними реплікаційними наборами та приймають записи. Розгортання в ЄС (хоча лише три PoP) має таку ж поведінку.
Як це працює
Частина цього охоплена в попередньому розділі, але коротко кажучи, це CRDT-lite. Ми створили проксі (на Rust, звичайно), який знаходиться між додатком і Mongo та робить його багатоголовим. Проксі обізнаний про сусідів, управляє контрольними точками, реплікацією, моніторингом та початковою синхронізацією. Це багатоголове заміщення для системи реплікації Mongo, включаючи деякі команди DDL.
Різниця з іншими інструментами полягає в тому, що це не відслідковує oplog. Відстеження oplog або використання потоку змін не спрацює, оскільки вони лише показують вам кінковий стан об'єкта після запису, ускладнюючи обробку конфліктів. Вам потрібно захоплювати кожну операцію $set, $inc і реплікувати саму цю операцію.
Це специфічне для домену рішення. Воно б не спрацювало для всіх продуктів. Можна сказати, що це дражливий дизайн :) . Це працює для нас, оскільки ми з самого початку дуже обережно лише $set поля, які змінюємо в документах - ми ніколи не використовуємо replaceOne Mongo, наприклад. Те ж саме з лічильниками. Ви ніколи не робите SET VOTES = 5. Замість цього ви пишете INCREMENT VOTES BY 5, оскільки це дозволяє досягти зрештою узгодженості. Розподілені блокування обробляються за допомогою не робіть. Лише один вузол
на кластер має прапорець, щоб виконувати cron-роботи. Хоча це може здаватися обмеженим, ми можемо купувати сервери з терабайтами оперативної пам'яті, тому ми можемо зробити цей компроміс, щоб знизити ризики та складність.
Читання власних записів
Для розробників, які використовують API, ви повинні мати можливість читати свої власні записи так, як це було раніше (зробіть API-запит, щоб створити коментар, потім перелікуйте коментарі та побачте новий запис у цьому списку). Зауваження полягає в тому, що ви не можете це зробити між регіонами. Якщо ваш бекенд працює лише в одному регіоні, як us-west, тоді ви повинні мати можливість читати свої власні записі, за винятком випадку, якщо між вашим записом і вашим читанням, цей вузол виходить з ладу і ваш DNS-кеш оновлюється і вказує на найближчий вузол. За умови, що цього не станеться, читання ваших власних записів є надійним.
Ви також можете закріпити, до якого пункту присутності ви звертаєтеся. Більше інформації тут.
Тестування та міграція
Приблизно половина коду в системі - це тестовий каркас, фреймворк та тести. Проте реліз стався з деякими труднощами, зайнявши більше часу для простою (1 година для ЄС і 20 хвилин для us-global), ніж бажано, але ми раді, що ми подолали цей рубіж і дякуємо вам за ваше терпіння!
На завершення та що це означає для вас
FastComments тепер має бути швидшим та надійнішим, ніж будь-коли, і тепер ми можемо повернутися до роботи над функціями :)
На здоров'я!
