MongoDB до Postgres
ПРИМІТКА: Цей допис у блозі є об’єднанням моїх MongoDB до Postgres (2024-03-06) та Sequelize vs. Prisma (2023-05-25). Оригінальні блоги були видалені, а цей блог зайняв їхнє місце, оскільки обидва містили по суті той самий вміст/інформацію. Міграція почалася на початку березня 2023 року, перемикання відбулося в середині листопада 2023 року, а всі екземпляри старої системи MongoDB були повністю вимкнені на початку січня 2024 року.
Вступ
Під час моєї роботи в eBay я зіткнувся з тим, що стало найскладнішою з технічного погляду проблемою у моїй кар’єрі: міграцією Storage Management System (STMS) з MongoDB до Postgres. Це була не просто заміна бази даних; це була повна архітектурна трансформація критично важливої системи, яка обробляє понад 1,5 мільйона метрик за хвилину в центрах обробки даних eBay, із вимогою нульового простою та збереження майже всієї наявної функціональності.
Що таке STMS?
Storage Management System (STMS) є критично важливим внутрішнім інструментом для команди Service & Storage Infrastructure (SSI) компанії eBay. Вона відстежує та керує пристроями в центрах обробки даних eBay, дозволяючи інженерам:
- Відстежувати метрики з десятків масивів, комутаторів, хостів, груп дисків і кластерів
- Обробляти сповіщення для комутаторів і масивів
- Виконувати розширені завдання, такі як призначення хостів
- Отримувати доступ до даних у реальному часі для інших внутрішніх сервісів eBay
STMS охоплює понад 70 масивів, 60 комутаторів, 1100 хостів, 900 груп дисків і 200 кластерів у 3 центрах обробки даних eBay. З огляду на її життєво важливу роль в інфраструктурі eBay, будь-який простій або втрата функціональності безпосередньо вплинули б на основні сервіси та бізнес-операції компанії.
Виклик
Чому міграція була необхідною
Рішення мігрувати з MongoDB до Postgres не приймалося легковажно. Хоча MongoDB спочатку добре служила STMS, зростаюча складність наших зв’язків між даними та потреба в більш досконалих можливостях запитів зробили Postgres кращим довгостроковим рішенням для нашого випадку використання.
Що робило цю проблему складною
Складність цієї міграції зумовлювалася кількома фундаментальними викликами:
1. Фундаментальні відмінності баз даних MongoDB і Postgres — це принципово різні бази даних. MongoDB є базою даних на основі документів (NoSQL), тобто дані зберігаються як JSON у колекціях, як документи у картотеці. Postgres є реляційною базою даних (SQL), тобто дані зберігаються як рядки в таблицях, як у електронній таблиці.
2. Архітектура кодової бази Увесь бекенд STMS був побудований для обробки та керування даними як JSON, використовуючи пакети, які були виключно сумісні з MongoDB для операцій з базою даних. Це означало не просто зміну бази даних, а перебудову того, як уся наша програма обробляла дані.
3. Вимога нульового простою Через те, наскільки важливою STMS є як внутрішній інструмент, під час міграції не могло бути жодного простою. Система мала продовжувати обслуговувати 1,5+ мільйона метрик за хвилину протягом усього процесу.
4. Стислі терміни та обмежений досвід Міграцію потрібно було завершити протягом кількох місяців, спочатку без чіткого плану виконання. Ні я, ні мої колеги не мали досвіду міграції великої застарілої кодової бази з баз NoSQL на SQL, а в мене був обмежений попередній досвід із Postgres.
5. Масштаб і складність Міграція передбачала перетворення 36 колекцій MongoDB на 74 таблиці Postgres, що вимагало ретельного врахування зв’язків, індексації та оптимізації запитів.
Вибір правильного ORM: Sequelize vs Prisma
Одним із перших важливих рішень був вибір інструмента ORM (Object-Relational Mapping). Оскільки наша кодова база вже була спроєктована для використання Mongoose для MongoDB, використання ORM забезпечило б найплавніший шлях переходу.
Аналіз вимог
Після ретельного аналізу потреб проєкту я визначив основні критерії для будь-якого ORM-рішення:
- Має бути пакетом JavaScript (більшість нашого коду було написано на JavaScript)
- Має підтримувати Postgres і більшість його функцій
- Продуктивність має бути щонайменше не гіршою за Mongoose або кращою
- Має бути відкритим програмним забезпеченням і підтримуватися
Кандидати
Після масштабного дослідження я звузив вибір до двох основних претендентів: Sequelize і Prisma. Я створив комплексні середовища для тестування з використанням Docker для Postgres і перетворив наш найбільший, найскладніший набір даних із структури документів у структуру таблиць.
Методологія тестування
Для кожного ORM я вимірював продуктивність у критичних операціях:
- Час створення запису
- Час оновлення запису
- Час оновлення вкладених записів (зв’язків і JSON-ключів-значень)
- Час видалення запису
- Час запиту/отримання запису
Рішення: Sequelize
Приблизно 15 травня 2023 року я вирішив, що Sequelize є кращим ORM для нашого випадку використання. Ось чому:
Переваги Sequelize:
- Справді відкрите програмне забезпечення, яке не підтримується фінансованим стартапом
- Підтримує більшість функцій Postgres
- Краща продуктивність, особливо порівняно з Prisma
- Зрілий екосистемний стек із понад 10 роками розробки
- Гнучке представлення моделі/схеми з використанням класів JavaScript
- Підтримка складних об’єднань і варіантів фільтрації, включно з Regex
Результати продуктивності:
У моїх тестах Sequelize значно випереджав Prisma. Для записів нашого великого набору даних:
- Sequelize: ~2,26 секунди на запис
- Prisma: ~11,21 секунди на запис
Prisma був приблизно у 5 разів повільнішим за Sequelize для нашого випадку використання. Крім того, видалення одного запису з нашого найбільшого набору даних у Prisma займало майже 4 хвилини, що було неприйнятним для наших вимог.
Виклики Sequelize:
- Більш складні та громіздкі представлення моделі (564 рядки проти 262 рядків у Mongoose)
- Заплутаний синтаксис у певних випадках
- Складність міграції бази даних
- Менш вичерпна документація порівняно з Prisma
Порівняння переваг і недоліків Sequelize та Prisma
Щоб дати повнішу картину того, чому я обрав Sequelize, я хочу поділитися детальними перевагами та недоліками, які я зібрав для обох ORM під час оцінювання. Я також подивився, як вони виглядали з точки зору представлення схеми та підтримки спільноти станом на 15 травня 2023 року. Це глибше занурення допомогло остаточно закріпити мій вибір, і я сподіваюся, що це може бути корисним для будь-кого, хто опиниться перед подібним рішенням.
Переваги Sequelize:
- Має функцію sync(), яка автоматично створює та обробляє таблиці за вас, заощаджуючи багато ручної роботи.
- Може обробляти складні об’єднання для вкладених даних, що було критично важливим для структури STMS.
- Підтримує широкий спектр параметрів фільтрації, включно з Regex, що дає гнучкість у запитах.
- Представлення моделі/схеми виконується у чистому JavaScript за допомогою класів, які є дуже налаштовуваними під конкретні потреби.
- Безперешкодно обробляє підключення до бази даних, включно з підтримкою кількох підключень для читання.
- Підтримує сирі SQL-запити, коли потрібно зазирнути «під капот».
- Статистика спільноти станом на 15 травня 2023 року: на NPM востаннє оновлено 14 днів тому, 1 505 835 щотижневих завантажень; на GitHub востаннє оновлено вчора, 4,2 тис. форків і 27,9 тис. зірок. Це відкрите програмне забезпечення з ліцензією MIT уже понад 10 років, тож я впевнений, що так буде й надалі.
Недоліки Sequelize:
- Представлення моделі/схеми може ставати дуже складним і громіздким. Наприклад, тоді як представлення нашого великого набору даних у Mongoose займало близько 262 рядків (включно з пробілами), той самий набір даних у Sequelize розрісся до 564 рядків.
- Синтаксис у певних сценаріях може бути заплутаним і складним, що інколи сповільнювало мене.
- Міграція або редагування бази даних є незручною. Навіть із тим, що sequelize-cli генерує скрипти міграції, це все одно громіздко, хоча я помітив, що це поширена болюча точка для більшості ORM.
- Документація не надто хороша, хоча й покращується. На щастя, такі інструменти, як ChatGPT, добре розуміють Sequelize завдяки його довгій історії, що допомагало заповнювати прогалини.
- Не настільки чутливий до типів, як Prisma, що в деяких проєктах може призвести до проблем.
- Обмежена підтримка TypeScript, хоча для STMS це не було проблемою, для інших це може бути вирішальним недоліком.
Переваги Prisma:
- Використовує власну мову схеми, що робить створення моделі чистішим і лаконічнішим. Для порівняння, тоді як Mongoose займав 262 рядки для нашого великого набору даних, Prisma впорався з цим лише за 221 рядок.
- Має CLI-інструмент, який спрощує створення та міграцію бази даних, і це найкраще, що я бачив від ORM на сьогодні, навіть якщо це не ідеально.
- Підтримує сирі SQL-запити, пропонуючи гнучкість, коли це потрібно.
- Синтаксис коду чистий і простіший для розуміння порівняно з Sequelize, що робить його легшим для вивчення.
- Автоматично генерує конструктори запитів для Node.js і TypeScript через свій клієнт, що є приємним доповненням.
- Має чудову, чисту документацію. ChatGPT не настільки актуальний щодо Prisma, але офіційна документація часто це компенсувала.
- Статистика спільноти станом на 15 травня 2023 року: на NPM востаннє оновлено 6 днів тому, 1 344 705 щотижневих завантажень; на GitHub востаннє оновлено 3 години тому, 1,1 тис. форків і 31,3 тис. зірок.
Недоліки Prisma:
- Не підтримує фільтрацію Regex для Postgres, хоча пропонує альтернативи на кшталт “contains”, “includes” і “startsWith.”
- Продуктивність була серйозною проблемою в моїх тестах. Створення записів для нашого великого набору даних займало в Prisma близько 11,21 секунди на запис порівняно з 2,26 секунди у Sequelize, тобто приблизно у 5 разів повільніше.
- Видалення одного запису з великого набору даних займало майже 4 хвилини, що для наших потреб було вирішальним недоліком.
- Навіть за справедливого порівняння на складному наборі даних зі зв’язками на три рівні вглиб Sequelize був значно швидшим під час видалення.
- Prisma підтримується стартапом із фінансуванням у 56,5 мільйона доларів. Хоча його основний ORM-код є відкритим програмним забезпеченням під Apache-2.0, я остерігаюся можливих змін ліцензування в майбутньому, подібно до того, що сталося з MongoDB.
Ці детальні порівняння чітко показали, що Sequelize краще відповідав потребам STMS, особливо щодо продуктивності та довгострокової надійності. Але я подумав, що розкласти це саме так може бути корисно й іншим, хто бореться з таким самим вибором для своїх проєктів.
Процес міграції
Трансформація структури даних
Перехід від документної структури MongoDB до реляційної структури Postgres вимагав ретельного планування. Мені потрібно було:
- Проаналізувати взаємозв’язки: Визначити, як документи MongoDB пов’язані між собою, і спроєктувати відповідні зв’язки зовнішніх ключів
- Нормалізувати дані: Розбити вкладені документи на окремі таблиці там, де це доречно
- Зберегти можливості JSON: Використовувати стовпці JSONB для справді неструктурованих даних, яким потрібно було залишатися гнучкими
- Спроєктувати індекси: Створити відповідні індекси для продуктивності запитів
Індивідуальні рішення
Міграція вимагала розробки кількох індивідуальних рішень:
1. Сценарії міграції даних Я створив комплексні сценарії, щоб:
- Витягувати дані з колекцій MongoDB
- Трансформувати структури документів у реляційний формат
- Імпортувати дані в таблиці Postgres із належними зв’язками
2. Шар сумісності API Щоб забезпечити нульовий простій, я побудував шар сумісності, який міг:
- Маршрутизувати запити або до MongoDB, або до Postgres залежно від стану міграції
- Забезпечувати узгодженість даних під час перехідного періоду
- Надавати механізми резервного переходу
3. Користувацьке проміжне програмне забезпечення Розробив проміжне програмне забезпечення для обробки відмінностей у тому, як MongoDB і Postgres виконують певні операції, забезпечуючи, що наявні кінцеві точки API продовжували працювати без модифікацій.
Подолання технічних викликів
Робота зі складними взаємозв’язками
Одним із найбільших викликів було перетворення вбудованих документів MongoDB на зв’язки Postgres. Наприклад, один документ MongoDB міг містити:
- Базові властивості
- Вкладені об’єкти, що представляють пов’язані сутності
- Масиви вбудованих документів
Це потрібно було ретельно декомпонувати на:
- Основні таблиці для головних сутностей
- Сполучні таблиці для зв’язків «багато-до-багатьох»
- Зв’язки зовнішніх ключів для асоціацій «один-до-багатьох»
Оптимізація запитів
Патерни запитів MongoDB не напряму переносяться на SQL. Мені довелося:
- Переписати складні конвеєри агрегації як SQL-з’єднання
- Оптимізувати індекси для нових патернів запитів
- Переконатися, що продуктивність запитів відповідала або перевищувала продуктивність MongoDB
Цілісність даних
Забезпечення цілісності даних під час міграції вимагало:
- Комплексних сценаріїв валідації
- Процедур відкоту
- Синхронізації даних у реальному часі під час перехідних періодів
Результати та вплив
Міграцію STMS з MongoDB на Postgres було успішно завершено без простою, зберігши майже всі функції та можливості. Результати перевершили очікування:
Покращення продуктивності:
- Продуктивність запитів покращилася для складних реляційних запитів
- Краща узгодженість і цілісність даних
- Більш ефективне використання сховища
Операційні переваги:
- Розширені можливості моніторингу та налагодження
- Краща інтеграція з наявними SQL-інструментами eBay
- Покращені процедури резервного копіювання та відновлення
Вплив на команду:
- Поглиблення знань команди про реляційні бази даних
- Створення підходів для майбутніх міграцій баз даних
- Створення повторно використовуваних інструментів і процесів
Отримані технічні навички
Цей проєкт суттєво розширив мою технічну експертизу:
Технології баз даних:
- Глибоке розуміння можливостей і оптимізації Postgres
- Оптимізація SQL-запитів і налаштування продуктивності
- Патерни проєктування баз даних і нормалізація
- Конфігурації баз даних primary-standby
Інструменти розробки:
- ORM Sequelize та побудова запитів
- Стратегії міграції баз даних
- Методології тестування продуктивності
- Валідація даних і перевірка цілісності
Архітектурні патерни:
- Стратегії міграції без простою
- Шари сумісності API
- Патерни абстракції баз даних
- Системи моніторингу та сповіщення
Особистий і професійний розвиток
Цей проєкт міграції став трансформаційним для мого професійного розвитку. Він вивів мене на незвідану територію, вимагаючи:
Навички лідерства:
- Керування складним технічним проєктом без попереднього досвіду
- Прийняття критичних архітектурних рішень під тиском
- Координація з кількома командами та зацікавленими сторонами
Здатність до розв’язання проблем:
- Розбиття складних проблем на керовані компоненти
- Розробка креативних рішень для безпрецедентних викликів
- Балансування кількох конкуруючих вимог і обмежень
Комунікація та командна робота:
- Пояснення технічних концепцій нетехнічним зацікавленим сторонам
- Документування процесів і рішень для подальшого використання
- Менторство для членів команди щодо нових технологій і підходів
Уроки, які я засвоїв
Технічні уроки
- Вибір бази даних має значення: Вибір між NoSQL і SQL має ґрунтуватися на конкретних сценаріях використання та довгострокових вимогах
- Тестування продуктивності є критичним: Теоретичні переваги не завжди перетворюються на реальні покращення продуктивності
- Планування міграції: Комплексне планування та тестування є необхідними для складних міграцій
- Інвестиції в інструменти: Створення належних інструментів на старті заощаджує значний час і зменшує кількість помилок
Уроки управління проєктами
- Комунікація із зацікавленими сторонами: Регулярні оновлення та чітка комунікація запобігають непорозумінням
- Управління ризиками: Наявність резервних планів і процедур відкоту є необхідною
- Керування графіком: Закладайте буферний час на неочікувані виклики та криві навчання
- Документація: Ретельна документація забезпечує передачу знань і майбутнє обслуговування
Висновок
Міграція STMS з MongoDB на Postgres є найскладнішою і водночас найбільш винагороджувальною технічною проблемою, яку я розв’язав у своїй кар’єрі. Вона вимагала не лише технічної експертизи, а й лідерства, планування та адаптивності. Успіх проєкту продемонстрував, що за умови належного планування, ретельного тестування та прагнення до досконалості навіть найскладніші технічні виклики можна подолати.
Цей досвід фундаментально змінив мій підхід до інженерії програмного забезпечення, підкресливши важливість:
- Розуміння повного контексту та вимог перед ухваленням технічних рішень
- Вкладення часу в належні інструменти та тестування
- Підтримання чіткої комунікації протягом складних проєктів
- Готовності вивчати нові технології та підходи, коли це необхідно
Успіх міграції не лише покращив можливості STMS, а й заклав підходи та процеси, які й надалі приносять користь інфраструктурним проєктам eBay. Це зміцнило моє переконання, що приймати невідомі виклики та досягати успіху через них є ключем як до особистого, так і до професійного розвитку.
Озираючись назад, я бачу в цьому проєкті переломний момент у своїй кар’єрі, який перетворив мене з розробника, що реалізує рішення, на інженера, здатного архітектурно проєктувати та очолювати складні технічні ініціативи. Упевненість і навички, здобуті завдяки цьому досвіду, і надалі спрямовують мій підхід до нових викликів і можливостей в інженерії програмного забезпечення.