Deno выпустила celld, self-hosted альтернативу Durable Objects от Cloudflare

Deno выпустила celld, self-hosted альтернативу Durable Objects от Cloudflare

Компания Deno Land Inc., которая опубликовала репозиторий denoland/celld на GitHub, выпустила celld, open-source демон, запускающий настоящие Cloudflare Workers и Durable Objects на серверах, которые контролирует сам пользователь, в обход облака Cloudflare. Durable Objects, собственный сервис Cloudflare: изолированный объект с постоянным состоянием и привязанным к нему хранилищем, который прежде можно было получить только как часть облака компании, вместе с кодом Cloudflare Workers, её serverless-платформы для выполнения JavaScript/TypeScript-кода в своей сети. Каждый узел celld встраивает движок V8 и выполняет настоящие бандлы, собранные Wrangler, официальным инструментом командной строки Cloudflare для Workers, то есть переписывать существующий код Worker-проекта под celld не нужно.

Технически каждый Durable Object в celld, это отдельная SQLite-база, адресованная по имени и непрерывно реплицируемая в S3-совместимый бакет, которым владеет сам пользователь (подходит и Amazon S3, и, например, Cloudflare R2, и любое другое совместимое хранилище). Узлы celld договариваются, кто из них сейчас обслуживает конкретный объект («ячейку», по терминологии проекта), исключительно через операции compare-and-swap над этим бакетом, без выделенного управляющего сервиса, детектора отказов или отдельного протокола консенсуса: именно объектное хранилище гарантирует, что в любой момент ячейкой владеет ровно один узел. Источником истины служит сам бакет, а не какой-то конкретный узел, когда ячейка переезжает на другой узел или «просыпается», новый владелец восстанавливает её SQLite-базу из бакета и продолжает работу с того же места, а узлы celld можно свободно заменять.

Поскольку каждый объект, это своя отдельная небольшая база данных, приложения на celld шардируются самой конструкцией системы: проблема конкуренции за ресурсы и эффект «одна упавшая база данных обрушивает всех остальных», типичные для архитектуры с единой общей базой, здесь не устраняются вручную, а изначально отсутствуют. Простаивающие ячейки «засыпают» и почти не потребляют ресурсов, пока к ним нет обращений.

Протокол обмена данными между узлами (peer HTTP) сам по себе не шифрует трафик, README прямо требует размещать все адреса, которые узел объявляет остальным, в доверенной приватной сети или за зашифрованным оверлеем вроде WireGuard или Tailscale и не открывать порт для обмена между узлами напрямую в интернет; буквальный публичный IP-адрес в качестве объявляемого celld отклоняет, если явно не передан флаг --unsafe-public-advertise. Первый «текущий» узел флота создаёт в бакете файл с общим секретом флота, и все запросы между узлами версионируются по протоколу, привязаны к телу запроса, аутентифицируются HMAC-подписью, ограничены по времени и защищены от повторного воспроизведения этим секретом; README прямо предупреждает, доступ к бакету и его учётным данным нужно приравнивать к правам администратора всего флота.

README описывает рантайм celld и его совместимость с Workers и Durable Objects как «всё ещё развивающиеся». Публичные автоматические тесты в репозитории покрывают только «дымовой» путь автономного движка; полное соответствие эталонному поведению Workers и Durable Objects, а также детерминированная симуляция распределённого протокола под внедрёнными сбоями запускаются перед каждым релизом, но текст не говорит, что эти прогоны публичны или воспроизводимы сторонними пользователями. Пул-реквесты на GitHub отключены: в README это объясняют тем, что ИИ-агенты кодирования слишком облегчают отправку больших изменений с низким пониманием контекста, которые обходятся мейнтейнерам дороже, чем экономят, вклад по-прежнему принимается, но только патчем по почте на ry@deno.com и по лицензионному соглашению, которое передаёт Deno Land Inc. права на этот патч. Номер версии, дата релиза, название лицензии и имя конкретного автора или мейнтейнера в тексте не указаны, как и независимые бенчмарки, оценка стоимости или прямое сравнение производительности с облачным сервисом Durable Objects, который предлагает сама Cloudflare.

Ключевые факты

  • Deno Land Inc. выпустила celld, open-source демон, который запускает настоящие Cloudflare Workers и Durable Objects на собственных серверах пользователя, в обход облака Cloudflare.
  • Каждый Durable Object хранится как отдельная SQLite-база, реплицируется в S3-совместимый бакет пользователя, а узлы celld договариваются о владении ячейками через compare-and-swap над этим бакетом, без выделенного управляющего сервиса, детектора отказов или протокола консенсуса.
  • Раздельная база на каждый объект избавляет от конкуренции за ресурсы и эффекта «одна упавшая база валит всех» по самой конструкции системы; простаивающие ячейки почти не потребляют ресурсов, а источником истины служит бакет, а не конкретный узел.
  • Установка, скриптом с проверяемым происхождением бинарника (gh attestation verify) или Docker-образом для Linux x86-64/ARM64; протокол между узлами не шифрует трафик сам по себе, поэтому узлы держат в приватной сети или за WireGuard/Tailscale, а буквальный публичный IP как объявляемый адрес celld отклоняет без явного флага --unsafe-public-advertise.
  • Репозиторий denoland/celld открыт, но пул-реквесты на GitHub отключены, в README это объясняют тем, что ИИ-агенты кодирования слишком облегчают отправку больших изменений с низким пониманием контекста; вклад принимается только патчами по почте на ry@deno.com под лицензионным соглашением, которое передаёт права на патч Deno Land Inc.

Почему это важно

Durable Objects, один из самых характерных, но и самых «закрытых» элементов платформы Cloudflare: примитив с постоянным состоянием и привязанным хранилищем, который прежде можно было получить только как часть облака компании. celld воспроизводит ту же модель программирования, тот же код Cloudflare Workers, исполняемый настоящим движком V8 из настоящих бандлов Wrangler, но на серверах, которые контролирует сам разработчик, то есть переписывать приложение, чтобы уйти от привязки к одному облаку, не нужно. Отдельного внимания заслуживает способ координации: вместо специализированного протокола консенсуса или протокола членства узлов, обычного пути для такого класса задач, celld полагается только на compare-and-swap поверх S3-совместимого объектного хранилища, чтобы гарантировать единственного владельца ячейки. Это архитектурный минимализм: не нужно разворачивать и обслуживать отдельный управляющий сервис, детектор отказов или протокол консенсуса, ценой того, что задержки и поведение всей системы теперь зависят от свойств выбранного объектного хранилища. А раз источником истины служит бакет, а не конкретная машина, любой узел celld можно заменить без потери данных, иная модель эксплуатации по сравнению с типичным стейтфул-кластером, где потеря «правильного» узла критична.

Кому это важно

В первую очередь, командам, которые уже пишут код для Cloudflare Workers и Durable Objects и хотят исполнять его вне сети Cloudflare: например, из соображений стоимости, требований к размещению данных или чтобы не зависеть от единственного облачного провайдера в этой части инфраструктуры. Раз celld запускает настоящие бандлы Wrangler в собственном движке V8, перенести такой код, судя по README, можно без переписывания. Также это интересно инженерам распределённых систем и платформенным командам: координация через compare-and-swap над обычным объектным хранилищем, без отдельного управляющего сервиса и протокола консенсуса, самостоятельный архитектурный приём, любопытный отдельно от Durable Objects как таковых. И наконец, командам, которые уже используют S3-совместимое хранилище (Amazon S3, Cloudflare R2 или другое) и хотят добавить к нему серверлес-подобные стейтфул-вычисления на собственном железе.

Как это применить

Установить celld можно скриптом установки (curl -fsSL https://celld.dev/install.sh | sh), который скачивает бинарник с проверяемым происхождением, командой gh attestation verify, и кладёт проверенные релизы в ~/.local/lib/celld/releases с атомарным переключением текущей версии; для удаления есть отдельный «страхующий» скрипт (curl -fsSL https://celld.dev/uninstall.sh | sh). Тем, кому нужен контейнер, подойдёт образ ghcr.io/denoland/celld, опубликованный для Linux x86-64 и ARM64, в примере README его запускают с отдельным диском для хранения состояния (docker volume) и передают внутрь стандартные переменные окружения с учётными данными AWS. Дальше процесс такой: сначала celld deploy . --bucket указывает на S3-совместимый бакет (для Cloudflare R2 или другого стороннего хранилища добавляются флаги --endpoint и --region, для настоящего AWS S3 их можно не указывать), а затем сам демон запускается с флагами --listen и --advertise, указывающими на тот же бакет; для узлов за балансировщиком нагрузки каждому нужен свой, отличающийся от остальных адрес, переданный во флаге --advertise. Для сборки Worker-кода команде celld deploy нужен esbuild в PATH; проектам только со статическими файлами он не нужен. В самом репозитории есть небольшие примеры Wrangler-проектов в папке examples/, которые показывают поддерживаемую часть API Worker и Durable Object. Проверить состояние флота помогает celld diagnose: без аргументов команда перебирает данные об аренде всех узлов и напрямую опрашивает каждый живой узел, а флагом --peer можно ограничить проверку конкретными узлами. Вытеснение ячеек под нагрузкой (pressure shedding) по умолчанию выключено, README приводит лишь пример настройки порогов через переменные CELLD_MAX_RESIDENT_CELLS и CELLD_RESIDENT_LOW_WATER (в примере 1000 и 800 соответственно, но это не значения по умолчанию: README прямо говорит, что безопасные значения для первого релиза ещё уточняются), а на Linux к ним можно добавить пределы по памяти процесса и загрузке CPU. Под нагрузкой celld в первую очередь надёжно реплицирует и вытесняет простаивающие ячейки, к которым дольше всего не было обращений (LRU), и публикует их как свободные, не принимая новые свободные ячейки, пока не будет достигнут нижний порог; ячейки с активной работой или живыми WebSocket-соединениями под вытеснение не попадают, а пустой резервный узел получает такие освободившиеся ячейки не проактивно, а только когда до него доходит обычный трафик. Изменить код через GitHub нельзя, пул-реквесты отключены; патч нужно отправить письмом (git format-patch) на ry@deno.com, согласившись с лицензионным соглашением проекта.

Можно ли доверять

Источник, официальный README проекта в открытом репозитории denoland/celld на GitHub, а не пересказ через третьи руки. В отличие от простой маркетинговой страницы, здесь есть настоящий исходный код, документированные команды сборки и тестов (cargo build, cargo test, cargo clippy) и способ проверить происхождение готового бинарника (gh attestation verify), часть заявлений можно проверить напрямую, а не просто принять на слово. README не только описывает возможности, но и честно называет границы: рантайм и совместимость celld с Workers и Durable Objects прямо названы «всё ещё развивающимися», публичные автотесты покрывают лишь «дымовой» путь автономного движка, а вытеснение ячеек под нагрузкой описано как ещё не до конца откалиброванная опциональная функция. При этом в тексте нет номера версии и даты релиза, нет названия лицензии, нет имени конкретного автора или мейнтейнера, только название компании Deno Land Inc. и один голый адрес для патчей без подписи, а также нет независимых бенчмарков, оценки стоимости или прямого сравнения производительности с облачным сервисом Durable Objects, который предлагает сама Cloudflare. На Hacker News материал набрал 170 баллов и 30 комментариев на момент сбора данных для этого пересказа, заметный, но не экстраординарный отклик; о содержании самого обсуждения источник ничего не сообщает.

Риски и подводные камни

Модель безопасности требует дисциплины от того, кто разворачивает флот: протокол между узлами сам по себе не шифрует трафик, и адреса, объявленные не в приватной сети и не за шифрованным оверлеем вроде WireGuard или Tailscale, оставляют узлы уязвимыми; защита по умолчанию (отказ от буквального публичного IP-адреса) снимается одним явным флагом --unsafe-public-advertise. Доступ к самому S3-совместимому бакету и его учётным данным, фактически единая точка отказа: получив его, можно управлять всем флотом, поэтому README прямо приравнивает такой доступ к правам администратора. Вытеснение ячеек под нагрузкой опционально и, по признанию самого README, ещё не имеет проверенных безопасных значений по умолчанию для первого релиза, то есть без ручной настройки флот не защищён от исчерпания ресурсов автоматически. Проект сам называет себя «всё ещё развивающимся», а из README не следует, что более полный набор проверок перед каждым релизом (соответствие эталонному поведению Workers и Durable Objects, симуляция сбоев) публичен или воспроизводим сторонними пользователями, независимой проверки заявленной надёжности в источнике нет. Наконец, разработка централизована сильнее, чем в типичном open-source проекте на GitHub: пул-реквесты отключены, а любой принятый патч по условиям лицензионного соглашения передаёт права на него Deno Land Inc.