Wed Sep 10 2025
...
FastComments Тепер Глобально Розподілений
Що нового
Раніше FastComments мав дуже традиційну архітектуру для веб-застосунку. У нас були сервери додатків, бази даних та деякі інші послуги. Це було дубльовано в двох регіонах (us-west та eu). Якщо ви були у Франції і хотіли переглянути потік коментарів для клієнта, який розміщений у нашому глобальному дата-центрі, ваші запити повинні були йти до us-west для отримання коментарних даних.
Тепер це не так! Тепер коментарні дані та всі медіа активи розмножуються глобально для клієнтів у нашій глобальній розгортці, а для клієнтів у нашій розгортці в ЄС ми маємо три пункти присутності в ЄС, де дані реплікуються. Ваші запити йдуть до найближчого вузла в ЄС.
Як це працювало раніше
Якщо не враховувати бази даних, які мали кілька живих реплік у різних регіонах і хмарних провайдерів, всі послуги були розгорнуті на одному екземплярі для кожного типу послуги. Це означало, що для кожного регіону у нас був один сервер додатків, один сервер pubsub і один медіа-сервер. План полягав у вертикальному масштабуванні, поки ми могли оскільки це спростило задачі. Писати код було легко — ви завжди знали, що можете "читати свої власні записи", звертаючись до бази даних. Інфраструктура була простою, за винятком оновлень безпеки, які займали одну хвилину простою.
Проблема
Проблема виникла, очевидно, коли ми досягли максимальної потужності. Тоді ми оптимізували, а потім зрештою доводилося збільшувати розмір екземпляра для цієї служби.
Це почало ставати дорогим на Linode, де екземпляр в $144 приблизно еквівалентний, згідно з нашими термічними тестами, $20 вузлу OVH, і навіть якщо ми змінили провайдерів хостингу, ми мали б одиничні точки відмови по всьому місцю — а провайдери, такі як OVH, зазвичай мають довший час реагування на прибуткові проблеми.
RiR :)
Перші кілька років служби PubSub та Media в FastComments були написані на Java. Java була обрана за відносно високу продуктивність с урахуванням зусиль, які ми вкладали, і після років налаштування GC, спроб 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% свого часу на GC, незважаючи на те, що ми писали наш код більше як енджин гри і менше як типовий сервер. Не можу сказати, що я великий фанат 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 повинні масшта бути краще і мати більшу безвідмовність протягом тривалого часу завдяки цій роботі. Повідомте нас нижче, якщо ви виявите якісь проблеми.
