Как разрабатывать real-time collaborative offline-first приложения без backend сервисов и баз данных Вместо: Client + Backend + DB + Cache + Files storage + Realtime Layer + Kubernetes + Servers Нужны всего-лишь: Client + Files storage + Realtime Layer
От автора
i. Вводные
- Вся бизнес-логика и все вычисления должны происходить на клиенте
- Вся работа с БД должны происходить на стороне клиента
- Система должна поддерживать работу со множества устройств одного пользователя
- Cистема должна быть многопользовательской
- Система должна также уметь хранить файлы (фото, видео, аудио, pdf, etc.)
- Система должна быть безопасной
- File Storage – внешнее файловое хранилище* S3-like, Google Drive-like или IPFS-like сервисы для персистенции и передачи данных и файлов между устройствами и пользователями. При этом, пользователь может использовать свои собственные хранилища без необходимости нам предоставлять свой backend.
- Web Socket-like Broker для маршрутизации сообщений между клиентами. Особенность clientful реализации позволит использовать абсолютно любой сервис, который даст возможность подключатся к комнате и бродкастить сообщения всем подключенным пользователям
ii. Преимущества
a. Бизнес
- 0 стоимость инфраструктуры – для некоторых бизнесов стоимость хранения данных пользователей и обработки их запросов – непреодолимый барьер из-за которого они не успевают дожить до окупаемости. В clientful все вычислительные ресурсы и системы хранения полностью отданы на сторону пользователя, а значит вам вообще не придется платить за сервера, приложения, базы данных, кэши и подобное.
- Скорость интеграции – вся система представляет собой набор из клиентского приложения (например, html, css, js), S3-like хранилища и WS сервера. Это позволяет крайне быстро интегрировать подобные продукты в сторонние системы
- Own Your Data – данные могут полностью хранится на стороне пользователей и могут быть абсолютно зашифрованы, что может стать критическим преимуществом на фоне ваших конкурентов
- 99.9999% uptime – приложение или существует на устройствах пользователя и крупных клаудах типа Google Drive, или же подключено к вашему S3 серверу, а значит система имеет наименьшую возможную вероятность падения
- Максимально интерактивный UI — пользователь никогда не ждет “ответа сервера”, всё меняется локально, поэтому приложение ощущается максимально быстрым, а как только приходят внешние изменения, они моментально отображаются в UI
- Приложение всегда будет у пользователя – пока у него есть копия вашего html / css / js приложение всегда будет у пользователя и будет работать, поэтому вы можете продавать свой продукт с гарантией, что человек сможет им пользоваться с этого момента и до самого конца
b. Технологически
- Нет vendor lock-in — нет вообще никакой зависимости от серверных провайдеров
- Infinite scalability by design — каждый новый пользователь приносит свои ресурсы, нагрузка не растёт
- Скорость разработки – никаких стейджинг и дев серверов, никакого деплоя 10-ка приложений, никакого kubernetes и даже docker, вам не нужно абсолютно ничего, кроме как разрабатывать клиентское веб или нативное приложение, которому просто нужен CDN и все.
- E2E тестирование из коробки – вся система это буквально только клиент, поэтому написание теста на клиент это все равно что написать E2E тест, тестирующий всю инфраструктуру
- LLM-optimized – все приложение это буквально клиентский код, а значит LLM нужен только контекст этого приложения для знания о всей системе.
- Стабильность работы – как часто технология не работало просто по факту отвала backend приложения, или сервера, или БД? В данной ситуации мы имеем offline-first
- Offline-first из коробки — приложение работает без интернета, данные всегда под рукой
- Non-internet connection – вы можете коммуницировать между устройствами на любом протоколе, например, LAN, BLE, I2C и подобные.
- Возможность централизации – в реальности, если в вашем проекте требуется центральная “БД”, в которой будут хранится все или частично данные, вы можете подрубать свое центральное S3-like / GoogleDrive-like хранилище и публиковать часть контента пользователей туда
- Real-time-native – как только любое изменение доходит до клиента интерфейс моментально отоюражает
c. Безопасность
- Меньше attack surface — нет сервера = нет точки атаки для хакеров.
- Privacy by default — данные не покидают устройство пользователя, не нужно думать о GDPR и утечках.
- Теоретически невзламываемая система – возможны стратегии шифрования, при которых ключи создаются и всегда находятся на устройствах пользователей, их буквально не существует ни в одном централизованном месте, и даже если скачать из file storage их невозможно будет расшифровать в обратную сторону.
iii. Реализация
- Алгоритм хранения данных
- Хранилище
- Протокол коммуникации
- Auth / Identity
- Шифрование
a. Алгоритм хранения данных
- Использования множества устройств – пользователь, используя приложение на другом устройстве (например, на компьютере и телефоне), должен иметь возможность работать над теми же самыми данными
- Коллаборации множества пользователей – пользователи должны иметь возможность коллаборативно работать над одними и теми же данными, как по отдельности и видеть сохраненные изменения, так и в real-time
- Pure P2P – каждый узел равнозначен и может полностью самостоятельно принимать решение
- Host-base P2P – в какой-то конкретный момент времени или на определенные операции какой-то из узлов должен становится главным и обрабатывать запросы от других узлов
- Pure P2P
- CRDT — структур данных и алгоритмы, позволяющие нескольким узлам независимо менять одно и то же состояние, а затем без конфликтов смержить изменения так, чтобы все реплики сошлись к одному результату.
- CouchDB — eventual consistency документная БД и протокол репликации: узлы обмениваются версионированными документами, а конфликты фиксируются как альтернативные версии и требуют стратегии разрешения (то есть merge не “магический”, как у CRDT, а задаётся моделью/логикой приложения).
- Blockchain — распределённый журнал (ledger), где узлы приходят к единому порядку транзакций через механизм консенсуса (PoW/PoS и т.п.). Это “демократия” в том смысле, что нет доверенного центра, но “демократия” достигается ценой дорогого консенсуса.
- Git-like log – пользователи буквально или руками, или автоматически по логике приложения создают на изменения ветки, а потом, при обмене сообщениями мерджат друг в друга.
- Host-base P2P
- OT — подход к коллаборативному редактированию, где изменения представляются как операции (insert/delete/replace и т.д.), а при конкуренции операции трансформируются относительно друг друга так, чтобы все пришли к одному результату.
- PAXOS / Raft — алгоритмы консенсуса для репликации лога в кластере: группа узлов выбирает лидера, лидер принимает команды (записи в лог), реплицирует их на кворум.
- Yjs — одна из самых распространенных библиотек CRDT
- Automerge – еще одна реализация CRDT, но хранит данные как неизменяемый граф (как git дерево)
- OrbitDB – бд основанная на “жернале операци” поверх CRDT, с встроенным протоколом коммуникации libp2p поверх IPFS и расширенными операциями над CRDT структурами
- PouchDB – реализации CouchDB протокола на клиенте
- Gun.js — распределенная графовая БД с P2P синхронизацией
- Hypercore – распределенный append-only иммутабельный лог (и куча экосистемы вокруг)
- SQLite + CRDT – библиотеки, которые объединяют CRDT и sqlite
Но в реальности смысл имеет только CRDT
- OT – чаще всего, все-таки предполагает единый узел, который будет собирать последовательность операций.
- CouchDB – протокол разрабатывался с идейей eventual consistency DB, в которой клиенты могут поключаться к центральным узлам и трансформировать часть данных. И на данный момент, попытки сделать его полностью P2P правда существуют, но они абсолютно эксперементальны.
- PAXOS / Raft – вот они вполне себе возможны, но они имеет преимущество над CRDT, когда (а) вам нужна строгая транзакционность, (б) вы можете доверять одному из участников. Сложность реализации настолько большая, что смысл прибегать в PAXOS / RAFT только если нет никаких других вариантов решения вопроса.
- Blockchain – практически схож с PAXOS / Raft, но требует доверия не к 1 узлу, а большинству узлов, но точно также имеет такую большую технологическую сложность, что его использование должно иметь невероятно весомую причину.
- Git-like log – интересная модель, НО предполагает или разруливание со стороны пользователя, или просто не подходит для большого количества бизнес-кейсов.
Бонус
- SQLite – даже без встроенного CRDT, вы можете сохранять CRDT контент прямо в sqlite базу, может быть полезно, если вы хотите, например, часть этого контента индексировать.
- PGlite – тоже самое, что и SQLite, но только буквально PostgreSQL на WASM (причем, работающий, так еще и с extensions).
- DuckDB – аналитическая встраиваемая БД, которая умеет даже в подгрузку файлов по URL (например, напрямую из S3), что делает ее идеальным кандидатом для использования в clientful.
- LanceDB – тоже самое, что и DuckDB, но векторная и из коробки предполагающая хранение во внешних файловых хранилищах
b. Хранилища
- Удаленные
- Google Drive-like – идеальный кандидат, потому что такие хранилища есть у большинства клиентов, а значит, есть возможность полностью перенести хранение файлов на них
- S3-like – любой Minio, rustfs, Cloud S3 идеально подходит для данной задачи
- CDN-like – использование любого CDN провайдера для загрузки и скачивания файлов
- IPFS / Filecoin — децентрализованное крипто-хранилище
- Nostr-like — децентрализованный протокол хранения/обмена данными без сервера.
- Torrent – и опять же, почему нет, это буквально протокол для P2P передачи и хранения данных.
- Git-like – использовать git репозитории для персистенции и передачи файлов? А почему нет?
- Локальные
- Browser Local Storage / IndexedDB / OPFS — нативное браузерное хранилище, идеально для client-side first
- File System – буквально локальная файловая система
c. Communication
- WebRTC – возможность p2p соединения клиентов
- WebSocket – постоянное двустороннее соединение через TCP
- QUIC – свеженький протокол на UDP, с гарантиями TCP и защищенностью TLS
d. Auth / Identity
- Google Drive-like OAuth
- Используем OAuth провайдера как источник идентичности (Google/Microsoft/и т.д.).
- Токены нужны не только для login, но и для доступа к File Storage пользователя (Drive/Dropbox/etc.) — то есть авторизация на операции чтения/записи файлов происходит “встроенно” через провайдера.
- Плюсы: минимальный UX friction, понятная модель доступов, часто уже есть у большинства пользователей.
- Минусы: зависимость от провайдера, ограничения/квоты API, возможные сложности с shared-папками и доступами между пользователями.
- Sign-in with Ethereum (SIWE)
- Идентичность = владение приватным ключом кошелька; вход = подпись challenge (nonce) сообщением.
- Авторизация между пользователями может строиться через on-chain / off-chain ACL: например, “кто может читать/писать” определяется списком адресов и ролей.
- Плюсы: переносимая идентичность, нет центра, удобно для web3/комьюнити продуктов.
- Минусы: UX/seed-фразы, кошельки/chain-specific, сложнее для массовой аудитории; всё равно часто нужен внешний канал доставки данных (storage/broker).
- Local-first keys (device/user keys)
- Идентичность строится вокруг локально сгенерированных ключей (например, Ed25519/X25519):
- ключ устройства (device key) + ключ пользователя (user key) +/или ключи рабочих пространств (workspace keys).
- Публичные ключи распространяются через File Storage/реестр/инвайты; приватные никогда не покидают устройства.
- Авторизация = подписи и capability-токены (например, “этот ключ может писать в эту папку/документ”).
- Плюсы: максимально соответствует идее clientful/privacy-by-default, можно сделать E2E-шифрование.
- Минусы: восстановление доступа (recovery), ротация ключей, онбординг новых устройств, отзыв доступов.
- AT Protocol (Bluesky stack)
- Идентичность = DID (Decentralized Identifier), привязанная к handle/домену; переносимость аккаунта обеспечивается протоколом.
- Можно использовать AT как “identity + directory + transport” слой, а данные приложения хранить в File Storage, привязывая права к DID.
- Плюсы: децентрализованная идентичность, встроенные механизмы репликации/федерирования, потенциально удобно для social-like продуктов.
- Минусы: стек относительно специфичен; придётся аккуратно разделять, что живёт в AT, а что — в вашем файловом хранилище/CRDT-данных.
e. (coming soon) Шифрование
f. Backend-like
iv. Сложности
1. Зависимость от реализации CRDT
2. Только коллаборация
- Использовать подписи приватными ключами и проверку публичными на каждую операцию и в случае некорректности помечать как ненадежные
- Использовать Merkel Tree для пересчета состояний сущностей с учетом подписей
- Использовать blockhain-like структур
- Или назначать 1 master-клиента, который может принимать решения об легальности того или иного действия
3. Неконсистентные состояния
- Группа людей работает над каким-то документом, один из них садится в самолет
- Пока он в оффлайне, он удаляет этот документ.
- Остальные продолжают работать с тем документом.
- Когда он попадает в онлайн, его состояние синхронизируется и так как никто не “отменял удаление”, этот документ реально “удалится”, даже если его коллеги работали над ним
- При “удалении” сначала перемещать документ в “корзину”, а не удалять, и при выходе в онлайн, если надо документом была проведена работа, то восстанавливать его автоматически
- Или запрещать удалять документы в оффлайне
- Или формировать задачу “удаление”, но не применять ее, пока пользователь не вышел в онлайн и не увидел изменения коллег
4. “Если Х то можно / нельзя Y” не работает
- Клиент А создает пост
- Клиент Б получает этот пост
- Клиент А создает к нему комментарий
- Клиент Б видит комментарий
- Клиент А удаляет пост и вместе с ним все (один) комментарий
- Клиент А пытается создать к посту новый комментрий, но его запрещают это сделать, потому что поста уже нет
- Клиент Б еще не получил информацию про удаленный пост, поэтому спокойно создает второй комментарий
- Клиент А и Б получают изменения друг друга и получается, что пост удален, а при этом второй комментарий будет существовать
- Aftermath Compensation – после обновления состояния смотреть есть ли комментарии без постов и удалять их
- Preemptive Compensation – создавая комментарий (в локальной транзакции) “пересоздать пост, если вдруг он не существует”, то есть вы отправляете всем клиентам и свой комментарий, и пост, к которому вы его создали, а значит, даже если он был удален у клиента А, он будет заново у него создан.
- Conflict management – видеть этот конфликт и выводить сообщение пользователям о нем (причем, например, не удалять пост полностью пока он не синхронизируется у большинства узлов)
5. Классические проблемы оффлайн приложений
- Миграции данных – вы должны помнить, что данные у клиента уже лежат и нельзя просто взять и “удалить ключ и поменять его на новый”, вы должны будете в какой-то момент времени мигрировать данные из старого формата в новый
- Если состояние ломается, вы не можете зайти в центральную БД и посмотреть что произошло, вам придется иметь механизмы удаленной проверки того, что случилось с состоянием у клиента
- Разные версии на разных устройствах
v. Что мы имеем в сухом остатке
vi. Что нас ждет дальше
- Буду рассказывать и показывать как строится библиотеки для clientful
- Реальные примеры проблем clientful приложений и используемых технологий и их решения
- Разборы существующих проектов
- Изучать вопрос транзакционности в подобных системах
- Как clientful встраивается в текущую экосистему AI пайплайнов и агентов
- Структуры, которые расширяют возможности CRDT (Merkel Tree, Merge Tree, etc.)
- Авторизация операций
vii. Полезные ссылки
a. Технологии формата clientful
GitHubGitHub - alexanderop/awesome-local-first: Useful Links for Everything related to LocalFirstGitHub - alexanderop/awesome-local-first: Useful Links for Everything related to LocalFirst
Useful Links for Everything related to LocalFirst. Contribute to alexanderop/awesome-local-first development by creating an account on GitHub.
Pears_p2pPears | Unleash the Power of P2P
Pears | Unleash the Power of P2P
Empowering Developers, Disrupting the Norm!
b. Транзакции в P2P системах
YouTubeCRDT Research Meetup // AntidoteDB - Nuno Preguiça
CRDT Research Meetup // AntidoteDB - Nuno Preguiça
Originally recorded during the Lisbon Hack Week from May 21-25, 2018, this talk provides an overview of AntidoteDB and other CRDT-related projects on-going at NOVA LINCS. AntidoteDB (antidotedb.eu) is an open-source geo-replicated database that provides high availability while ensuring strong semantics for applications. To this end, AntidoteDB features CRDTs for providing data convergence, highly available transactions for providing atomic operations over multiple objects, causal consistency for enforcing the causal relations among updates, and mechanisms for enforcing global invariants without compromising availability. AntidoteDB is being developed in the context of EU H2020 LightKone project.
YouTubeAnnette Bieniusa - AntidoteDB: highly available, transactional database - Code BEAM Lite Munich 2018
Annette Bieniusa - AntidoteDB: highly available, transactional database - Code BEAM Lite Munich 2018
This video was recorded at Code BEAM Lite Munich 18: https://codesync.global/conferences/cbl-munich-2018/ Get involved in Code BEAM Lite conference: https://codesync.global/conferences/code-beam-lite-italy/ --- TALK TITLE AntidoteDB: a planet scale, highly available, transactional database by Annette Bieniusa Cloud-scale applications must be highly available and offer low latency responses while serving an ever-growing number of users concurrently. To achieve these goals, these apps rely on distributed cloud data stores that provide availability even under network partition. It takes significant effort and expertise from programmers to understand the intricate semantics and develop correct applications on top of such highly available databases. In my talk, I will show how AntidoteDB supports a principled approach to build highly-available, yet correct applications by combining conflict-free replicated data types (CRDTs), highly-available transactions and stronger synchronisation mechanisms. --- TALK OBJECTIVES You will learn how conflict-free replicated datatypes (CRDTs), transactions, and causal consistency interact to keep application data safe. Further, you will see how to identify patterns in your application that have specific synchronisation requirements und learn how to employ them with AntidoteDB. --- THEMES Consistency CRDTs AntidoteDB --- Code BEAM Lite LDN was brought to you by Code Sync. CODE SYNC Website: www.codesync.global Twitter: www.twitter.com/CodeMeshIO Facebook: https://www.facebook.com/CodeSyncGlobal LinkedIn: https://www.linkedin.com/company/code-sync/ Mail: info at codesync.global
c. CRDT
ElectricSQLIntroducing Rich-CRDTs | ElectricSQL
Introducing Rich-CRDTs | ElectricSQL
Rich-CRDTs are conflict-free data types extended to provide additional database guarantees.
EDB Postgres Distributed (PGD) v4.3.8 - Conflicts
EDB Postgres Distributed (PGD) v4.3.8 - Conflicts
BDR is an active/active or multi-master DBMS. If used asynchronously, writes to the same or related rows from multiple different nodes can result in data conflicts when using standard data types.