Вчера мы запустили полностью управляемый 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.
Чтобы начать интеграцию приложения, загляните в документацию.
