Как стать автором
Обновить
89.8
Skillfactory
Онлайн-школа IT-профессий

Postgres WASM от Snaplet и Supabase

Время на прочтение8 мин
Количество просмотров4.9K
Автор оригинала: Mark Burggraf


Сегодня мы с нашими друзьями из Snaplet открываем исходники postgres-wasm — запускаемый в браузере сервер PostgreSQL с полным набором функционала, включая сохранение состояния в браузере, восстановление из pg_dump и логическую репликацию из удалённой базы данных.


Впервые Postgres в браузере запустили в Crunchy Data, их потрясающая версия выложена на HN месяц назад. Вместе со Snaplet мы решили сделать версию с открытым кодом. Посмотрим, как она разрабатывается и какой функционал мы добавили. Подробности — к старту нашего флагманского курса по Data Science.


Что такое Snaplet?


Snaplet — это данные с продакшена и предварительные базы данных, с которыми разработчики могут писать код, сосредоточившись на переносимости. Посмотрите, как с помощью Snaplet клонировать среды Supabase.


Демо


Прежде чем перейти к техническим деталям, попробуйте сами (внимание: загрузится ~30 Мб).


Postgres внутри браузера

Postgres внутри браузера

Запускаем локально:


# From Snaplet Repo
git clone git@github.com:snaplet/postgres-wasm.git
cd postgres-browser/packages/pg-browser
npx serve

# From Supabase Fork
git clone git@github.com:supabase-community/postgres-wasm.git
cd postgres-wasm
git checkout web
cd packages/supabrowser
npx serve

И вводим в браузере localhost:3000.


Функционал


В нашей демоверсии — приятные плюшки!


  • Postgres 14.5, psql, pg_dump и т. д.
  • Сохранение/восстановление состояния в файл и из файла.
  • Сохранение/восстановление состояния Postgres в хранилище и из IndexedDB.
  • Быстрый запуск из файла состояния или полная перезагрузка эмулятора.
  • Параметры конфигурирования памяти от 128 до 1024 Мб.
  • Изменение размера шрифта для терминала.
  • Загрузка файлов в эмулятор, включая дампы БД и CSV-файлы.
  • Выгрузка файлов из эмулятора.
  • Сетевое подключение от эмулятора к интернету.
  • Входящий сетевой туннель в порт 5432 Postgres внутри эмулятора.

Для чего нужен postgres-wasm?


Хороший вопрос. postgres-wasm пока весит около 30 Мб, поэтому для общих вариантов применения запуск Postgres в браузере сейчас не так хорош. Но потенциал у него большой. Вот идеи, над которыми мы будем работать в ближайшие месяцы:


  • Документация: для учебных руководств и демоверсий.
  • Автономные данные: их запуск в браузере для автономного кеша аналогично sql.js или absurd-sql.
  • Автономный анализ данных: его применение в дашборде для автономного анализа данных и диаграмм.
  • Тестирование: функций PostgresSQL, триггеров, моделирования данных, логической репликации и т. д.
  • Среды разработки: их применение (извлечение данных из продакшена или добавление на продакшен новых данных, функций, триггеров, представлений).
  • Снимки: создание тестовой версии БД с образцом данных, а затем отправка её моментального снимка другим разработчикам.
  • Поддержка: отправка снимков БД с проблемой в службу поддержки.

Обзор репозитория


Мы разделили репозиторий на три папки: виртуальная машина, веб-приложение и сетевой прокси.


Виртуальная машина


Создаём встраиваемую ВМ при помощи Buildroot. Наша ВМ — это урезанная сборка Linux с установленным Postgres. Смотрите исходный код.


Веб-приложение


Дальше запускаем её в браузере с помощью WASM и v86. Демоверсия приложения очень проста — это обычный HTML с простыми стилями. Смотрите исходный код.


Прокси


Запускать Postgres в браузере — это хорошо, а подключаться к Postgres с помощью pgAdmin — ещё лучше. К сожалению, в браузерах блокируется сетевой TCP-доступ к ВМ, поэтому проксируем трафик через веб-сокеты. Запускаем форк Websockproxy для взаимодействия эмулятора с интернетом, то есть преобразования данных, отправляемых через порт веб-сокета, в TCP-пакеты. С этим форком можно пробросить туннель на сервер Postgres. Смотрите исходный код.


Технические подробности


В ходе разработки postgres-wasm обнаружилось много проблем.


WASM


Первая проблема: наша реализация — не чистый WASM. Мы пытались скомпилировать Postgres для WASM прямо из исходного кода, но это оказалось сложнее, чем мы ожидали.


В статье Crunchy на HN намекали на применяемый в работе подход — виртуализацию машины в браузере. Мы следовали этой стратегии с v86: с его помощью в браузере эмулируются аппаратное обеспечение и x86-совместимый ЦП.


Ошибки сегментации памяти (segfault) в PostgreSQL 14


PostgreSQL 13.3 с устаревшей версией Buildroot у нас запускалась быстро. А уже с версии PG14 не запускалась, и при инициализации выдавалась segfault.


Мы пробовали:


  • ручное копирование файлов сборки для PG14 в старые версии Buildroot;
  • сборку со многими более новыми копиями Buildroot;
  • настройку параметров ядра и среды, например выделенный эмулятору объём памяти и т. д.

В итоге Фабиан, создатель v86, предложил отключить JIT-компиляцию для v86. Так решилась эта проблема. Он свёл её к багу в v86 и добавил устраняющее этот баг обновление. Проблема решилась и для текущего выпуска V86 — переключением управления памятью Postgres с posix на sysv.


Оптимизация времени запуска и размера образа


Запустив PG14 в эмуляторе, мы переключились на производительность. Размер образа эмулятора оказался слишком велик для браузерного инструмента. Как мы ни старались сжать снимок, загружать более 30 Мб, прежде чем увидеть какую-то интерактивность, — многовато.


Мы решили эту проблему: запустили минимальный образ Linux, а после инициализации загрузили оставшуюся часть виртуальной машины динамически по HTTPS.


Делается это монтированием в ВМ сжатой файловой системы 9P. В 9P есть Python-скрипт. Скрипт берёт папку файловой системы, переименовывает каждый файл 8-символьным именем, и выдаёт файл filesystem.json — структуру с файлами, исходными именами файлов, размерами и т. д. Затем этот сжатый вывод копируется в виртуальную машину. Чтобы загружать прямо из файловой системы 9P, мы модифицировали командную строку ядра и параметры загрузки v86. И даже поместили в 9P файл ядра. Все необязательные файлы при необходимости также загружаются в браузере асинхронно по HTTPS.


Исходное состояние уменьшилось, но его размер оставался в пределах 15–20 Мб. Мы обсудили это с Фабианом, и он указал на параметр ядра page_poison=on, с помощью которого перед созданием снимков кеши очищаются, а в освобождённую память Linux вместо случайных байтов записываются произвольные. Поэтому неиспользуемая память сжимается намного эффективнее.


Каков итог всех этих изменений? Размер сжатого файла исходного состояния составляет около 12 Мб, в том числе состояние с активной сетью и Postgres 14.4 с загруженным psql.


Без запуска Postgres мы получили исходное состояние ещё меньше. Но инициализация Postgres обычно дольше загрузки дополнительных мегабайтов. Мы предпочли меньшее время запуска.


Кроме того, без состояния выполнения каждое обновление страницы чревато снижением производительности, ведь Postgres нужно каждый раз инициализироваться. В нашей текущей версии, после того как исходное состояние загружено и кешировано браузером, ВМ обновляется почти мгновенно.


Сеть


Особенно трудно решалась проблема сети. По соображениям безопасности в браузерах поддерживается доступ к ограниченному набору портов. В нашем случае у браузеров порты 80/443, а у Postgres — 5432, а значит, возможности взаимодействовать с внешним миром не было.


WASM здесь мало чем полезен. Запущенным в браузере модулем WebAssembly, как правило, никаких действий вне его не производится, кроме вызова предоставляемых из JavaScript функций.


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


В ВМ есть эмулированная сетевая карта ne2k-pci и параметр запуска proxy_url, который указывает на внешний сервер, где проксирование выполняется через веб-сокет. При этом подключения устанавливаются через порт веб-сокета, а затем принимаются необработанные Ethernet-пакеты, которые преобразуются в TCP/IP-пакеты и маршрутизируются между интернетом и ВМ.


Postgres WASM, прокси
Postgres WASM, прокси

После создания туннеля можно отправлять сетевой трафик во вне. Попробуем «запустить» сеть в ВМ, «выйти» из psql (cmd+D) и запустим ping 1.1.1.1.


Postgres WASM в интернете

Postgres WASM в интернете

В большинстве ВМ v86 используется открытый прокси-сервер wss://relay.widgetry.org/ на основе websockproxy. Благодаря ему возможны взаимодействие ВМ с внешним миром, отработка всех базовых сценариев, например загрузка данных из других БД PostgreSQL с помощью pg_dump и psql или работа в качестве реплики «только для чтения» другой БД.


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


Postgres WASM с psql

Postgres WASM с psql

Обратным прокси-сервером прослушивается ряд портов, каждый из которых сопоставляется с ВМ в определённом, нужном нам приватном адресе.

Простое решение — взять последние два сегмента приватного IP-адреса и сопоставить с номером порта. Так, если приватный IP-адрес 10.5.6.123, подключаемся к прокси-серверу в порте 6123 и оттуда направляемся в PostgreSQL, запускаемую на порте 5432 с приватным IP 10.5.6.123. Сокращённые адреса дополняются, поэтому 10.5.6.2 сопоставляется с портом 6002, а 10.5.6.44 — с 6044.


Postgres WASM с удалённым входом в систему

Postgres WASM с удалённым входом в систему

Отправка команд из пользовательского интерфейса браузера в эмулятор


После запуска эмулятор, по словам Фабиана, «выполняется как процесс типа «чёрный ящик», а единственный способ взаимодействия пользовательского интерфейса и запущенной в эмуляторе операционной системы — это serial0_send для отправки нажатий клавиш через эмулируемый последовательный порт. Либо функция create_file, которая загружает файл в запущенный эмулятор.


Чтобы после восстановления файла состояния перезапустить сеть, нужно выполнить короткий скрипт для отмены привязки и повторной привязки эмулированной сетевой карты. Так она получает новый mac-адрес и, следовательно, уникальный приватный IP-адрес на прокси-сервере. И затем запустить стандартную команду перезапуска сети. Можно было бы запустить этот скрипт, отправив в эмулятор нажатия клавиш, но это громоздко. Если пользователь в командной строке psql, отправляем \! script_command. А если в командной строке ОС?


Мы решили проблему созданием папки \inbox и добавлением в неё слушателя. При поступлении туда файла, который заканчивается на .sh (скрипт оболочки), применяем к файлу chmod +x, выполняем его, а затем удаляем. Так команды запускаются «в фоновом режиме», не затрагивая пользовательский интерфейс.


Попробуйте сами!


Подключитесь к экземпляру Postgres, запускаемому в браузере другого пользователя:


  1. Найдите кого-нибудь.
  2. Пусть он перейдёт по wasm.supabase.com.
  3. Запустит сеть и получит её адрес.
  4. Задаст пароль для своей БД ALTER ROLE postgres WITH PASSWORD 'my_password';.
  5. Откройте терминал на своём компьютере и запустите psql postgres://postgres:my_password@proxy.wasm.supabase.com:<PORT>.
  6. Вот и всё! Теперь вы подключаетесь к удалённому экземпляру Postgres внутри ВМ, в браузере, с терминала своего компьютера.

Репликация БД


Ещё круче — реплицировать данные из онлайн — БД PostgreSQL (например, проекта Supabase) в PostgreSQL, запускаемую в браузере. И, наоборот, используя логическую репликацию Postgres. То же относится к любой другой БД Postgres — просто используйте в качестве цели URL-адрес прокси-сервера.


Что дальше?


Пока всё это очень экспериментально, но с большим потенциалом. Чтобы поучаствовать, свяжитесь с нами или командой Snaplet. Они проделывают невероятную работу, и мы получили огромное удовольствие от сотрудничества с ними.



А мы научим работать с данными, чтобы вы прокачали карьеру или стали востребованным IT-специалистом:


Чтобы посмотреть все курсы, кликните по баннеру:



Теги:
Хабы:
Всего голосов 16: ↑16 и ↓0+16
Комментарии7

Публикации

Информация

Сайт
www.skillfactory.ru
Дата регистрации
Дата основания
Численность
501–1 000 человек
Местоположение
Россия
Представитель
Skillfactory School