Astro DB: подробный разбор

Автор
Matthew Phillips

Вчера мы запустили полностью управляемый SQL-сервис баз данных, созданный исключительно для веб-фреймворка Astro. Давайте погрузимся в детали реализации Astro DB: как это работает, зачем мы это создали и почему мы приняли libSQL.

Как мы сюда пришли

Astro уникален фокусом на контентных сайтах. В центре этого, конечно, контент — поэтому в Astro 2.0 мы выпустили Content Collections. Пользователям это понравилось как способ управлять локальным контентом.

WordPress всегда был для нас большим вдохновением. Одна из вещей, делающих WordPress особенным — встроенная база данных. Вы управляете не только контентом статей, но и данными, страницами, блоками, изображениями и целой экосистемой плагинов.

Мы хотели что-то подобное для Astro, но быстро поняли, что достигли предела того, как далеко могут завести статические данные репозитория.

Поиск (и потеря) SQLite

Пытаясь развить Content Collections с data collections и ссылками, мы поняли, что строим ORM, похожий на базу данных, поверх файловой системы, и столкнулись с несколькими проблемами. Член core-команды Erika предложила идею: почему бы просто не использовать базу данных, SQLite?

Мы влюбились в идею лёгкой базы данных, встроенной в сам Astro. SQLite идеально подходил для read-heavy нагрузок большинства контентных сайтов.

Мы сделали прототип, но столкнулись с несколькими препятствиями. SQLite — это C-библиотека, поэтому для работы в Node.js нужны нативные аддоны. Для локальной разработки это нормально, но нативные аддоны сложно деплоить на serverless-хостинги, а время старта вызывало опасения. Кроме того, ключевые окружения вроде StackBlitz вообще не могли его запустить.

Побеждённые, мы отложили идею и сосредоточились на другом. Была весна 2023 года.

Поиск (и влюблённость в) libSQL

В то же время — на другом конце света и совершенно неизвестно для нас — другая команда работала над этой же проблемой. Это была команда Turso, а их решением стал libSQL.

libSQL — форк SQLite, добавляющий набор улучшений runtime при сохранении совместимости с классическим SQLite. libSQL предлагал современный клиент базы данных для JavaScript/TypeScript, избегая нативных биндингов и шагов компиляции, которые мучили остальную экосистему. Он мог даже работать на StackBlitz через WASM.

Turso также предлагал хостинг libSQL-баз с фокусом на масштаб, который нам был нужен (подробнее чуть позже). Картина Astro DB начала складываться, но только в декабре 2023 все части наконец встали на место.

Проектирование локальной базы по-астровски

Astro DB даёт полностью локальную libSQL-базу, как только вы запускаете dev-сервер. С нашим бэкграундом как генератора статических сайтов было важно, чтобы базу можно было собрать с нуля при старте — в будущем это позволит питать content layer, где данные поступают из разных источников, включая файловую систему.

Когда вы запускаете astro dev, Astro DB:

  • Создаёт пустую базу в .astro/data.db
  • Читает схему из db/config.ts
  • Заполняет базу из db/seed.ts
  • Клиент базы данных готов

Workflow во многом повторяет Content Collections workflow, который пользователи Astro уже любят. Важно, что сама база (data.db) не персистентна. Она создаётся заново при каждом запуске dev-сервера. Это даёт простые, воспроизводимые одноразовые базы.

Astro DB объединяет веб-фреймворк, схему, seed-файл и саму базу в единую историю. Мы даже включаем ORM: Drizzle. Мы выбрали Drizzle, потому что это типобезопасный ORM, позволяющий работать максимально близко к металлу, и при этом расширяемый — мы смогли добавить своё поведение поверх.

Удалённая работа с хостинговой базой

Astro DB включает хостинговую libSQL-базу, к которой можно подключаться при локальной разработке и в продакшене. Всё управляется через платформу Astro Studio. Новую базу для проекта можно создать примерно за ~30 секунд.

Чтобы достичь масштаба, который нам был нужен на платформе, мы сотрудничаем с Turso, которые поддерживают libSQL и управляют крупнейшей платформой хостинга libSQL. Их приверженность модели «база на тенанта» идеально подошла для нашей потребности запускать сотни тысяч баз по требованию.

Мы также потратили время в прошлом году на прототип Cloudflare D1. Нам понравилось видение проекта, но мы столкнулись с дополнительным слоем абстракции workers и worker bindings, когда нам нужна была только база. Мы также сомневались строить на проприетарной технологии (D1), особенно если это означало встраивание в сам Astro. В итоге D1 не подошёл для нашего use case.

Миграции схемы без простоя

Схема базы определяется в файле db/config.ts проекта. При изменении схемы нужно отправить изменения в хостинговую базу так, чтобы исключить риск потери данных и простоя. Поэтому мы создали astro db push.

Команда push спроектирована как баланс простоты и лучших практик для крупных продакшен-проектов. В Astro DB нет файлов миграций для управления. Вместо этого при push схема автоматически сравнивается с хостинговой продакшен-базой, и новые изменения применяются. Если изменения нельзя добавить безопасно или они рискуют потерей данных, они не применяются.

Это поощряет стратегию миграций “expand and contract” в приложениях Astro DB. Конечно, при быстрой разработке, когда не страшно сбрасывать базу, можно запустить astro db push --force-reset, чтобы отправить любые изменения схемы, включая сброс базы.

Мы прошли несколько итераций системы миграций схемы, прежде чем пришли к финальной версии. Когда-то у нас даже была папка migrations/, куда вручную создавали и коммитили явные файлы планов миграций. Некоторым нравится эта модель, но для большинства пользователей это была раздражающая лишняя задача — помнить создавать миграцию при каждом изменении схемы.

Итоги

Мы довольны балансом, найденным в первой итерации Astro DB: закладываем основу для будущих локальных use case и даём простой способ деплоить продакшен-базы сегодня. Одна деталь, не вошедшая в статью — как интеграции могут предоставлять свои таблицы и данные; надеемся раскрыть это по мере развития следующей итерации контента и плагинов в Astro.

Чтобы начать интеграцию приложения, загляните в документацию.