Real-Time Backend

Collaborative Whiteboard

100 дизайнеров открывают один Figma-файл и начинают двигать объекты одновременно. Никто не видит ошибок синхронизации, нет "кто последний тот и прав" блокировок. Как это возможно без единой точки координации?

  • **Figma** поддерживает 1000+ одновременных пользователей в одном файле через WebSocket + CRDT-подобную архитектуру. В 2020 году Figma опубликовала детали: каждый объект имеет уникальный ID, операции атомарны, LWW с серверным lamport clock разрешает конфликты.
  • **Miro** обслуживает 50M+ пользователей на canvas-инфраструктуре. Для sticky notes используется Yjs (CRDT) для текстового контента, для позиций объектов - LWW. Архитектура позволяет работать офлайн с последующим автоматическим мержем.
  • **Excalidraw** (open source) реализует полностью децентрализованный коллаборативный холст через WebRTC p2p + Yjs CRDT. Нет центрального сервера для координации - каждый клиент синхронизируется напрямую с peers.
  • **Google Jamboard** (до закрытия в 2024) использовал Firebase Realtime Database как транспорт для canvas операций. Firebase обеспечивал ordering через server timestamp, конфликты разрешались через транзакции.

Canvas Sync: архитектура общего холста

Коллаборативный холст - это распределённая структура данных: сотни курсоров, тысячи объектов, каждый может быть изменён одновременно. Наивный подход - lock-based редактирование - убивает UX. Figma решила эту задачу иначе: каждый клиент имеет локальную копию состояния, изменения передаются как операции, конфликты разрешаются детерминированно.

Figma поддерживает 1000+ одновременных пользователей в одном файле. Курсоры обновляются через WebSocket с throttling 60 fps -> 15 fps при высокой нагрузке. Объектные операции идут отдельным каналом с higher priority. Miro обслуживает 50M пользователей на canvas-инфраструктуре с аналогичной архитектурой.

Разделение каналов критично: cursor awareness - lossy (потеря позиции курсора не страшна), object operations - lossless (потеря изменения объекта - катастрофа). WebSocket обеспечивает надёжность для операций, но курсоры можно отправлять с throttling и не retransmit-ить при потере.

Почему в Figma cursor awareness и object operations идут по разным каналам с разными приоритетами?

Shape Operations: типы и атомарность

Каждое изменение на холсте должно быть выражено как **атомарная операция** с определённой семантикой. Не "нарисовать прямоугольник", а "insert shape с id X в позицию Y с размерами Z". Это позволяет применять, отменять и мержить операции детерминированно.

  • **INSERT**: добавить объект с уникальным id (UUID), начальными свойствами и позицией в z-order
  • **UPDATE**: изменить свойства существующего объекта (position, size, style) - только delta, не full replace
  • **DELETE**: пометить объект удалённым (soft delete для undo/redo и conflict resolution)
  • **MOVE**: изменить позицию и/или z-order объекта - отдельная операция для оптимизации частых перемещений
  • **GROUP/UNGROUP**: создать/разбить группу объектов - compound операция с гарантией атомарности

Зачем DELETE реализуется как soft delete (пометка удалённым) вместо физического удаления?

Vector Graphics Sync: пути Безье и трансформации

Векторная графика добавляет сложность: кривые Безье, трансформационные матрицы, вложенные группы. Синхронизация пути из 100 точек при редактировании одной точки не должна пересылать весь путь. Figma решает это через **path delta encoding**: передаётся только изменённая точка с индексом.

Figma использует protobuf для сериализации операций вместо JSON: бинарный формат в 3-5 раз компактнее. При 100 одновременных пользователях, активно рисующих, экономия на сериализации даёт заметное снижение bandwidth и задержки обработки.

Почему при редактировании одной точки пути Безье нужно передавать только delta (индекс + новые координаты), а не весь путь?

Whiteboard CRDT: конфликты без координатора

При одновременном редактировании одного объекта разными пользователями нужна стратегия разрешения конфликтов. Figma использует **Last-Write-Wins** (LWW) с серверным timestamp для большинства свойств: побеждает последняя запись. Для текстового контента в фреймах - Yjs (CRDT), где каждый символ имеет уникальный идентификатор.

CRDT (Conflict-free Replicated Data Type) для whiteboard: каждый объект имеет уникальный ID (клиент-id + lamport clock), операции коммутативны и идемпотентны. Два клиента, применившие один и тот же набор операций в разном порядке, придут к одному состоянию. Excalidraw (open source) использует эту модель без центрального сервера.

Miro использует operational transformation (OT) для совместного редактирования sticky notes (текст), но LWW для позиций и размеров объектов. Гибридный подход: CRDT/LWW для структурных свойств, OT для текстового контента, где символьная precision важна.

Для коллаборативного холста достаточно WebSocket broadcast - каждый клиент применяет все операции в порядке получения

Порядок получения операций у разных клиентов может отличаться. Без CRDT или OT diverged state гарантирован при concurrent edit

Клиент A отправляет op1 (move X to 100), клиент B отправляет op2 (move X to 200) одновременно. A получает [op1, op2] -> X=200. B получает [op2, op1] -> X=100. State diverged. CRDT с LWW даёт детерминированный результат независимо от порядка применения.

Почему LWW (Last-Write-Wins) подходит для позиций объектов, но не для текстового контента?

Итоги

  • **Двухканальная архитектура**: cursor awareness (lossy, throttled 60->15 fps) и object operations (lossless) требуют разных QoS гарантий и должны идти по разным каналам
  • **Атомарные операции** (INSERT/UPDATE/DELETE/MOVE) с уникальными ID объектов - единственный способ детерминированно мержить concurrent changes без координатора
  • **LWW для структурных свойств + CRDT/OT для текста** - гибридная стратегия Figma и Miro: позиции разрешаются по timestamp, текст мержится посимвольно через Yjs

Связанные темы

Collaborative whiteboard - прикладная область для фундаментальных концепций realtime-систем:

  • CRDT Structures — Математическая основа conflict-free репликации, которую использует Figma для объектных операций
  • Operational Transformation — Альтернативный подход к конфликт-резолюции, используемый для текстового контента в Miro и Google Docs
  • Live Location Tracking — Схожая задача: синхронизация позиций множества объектов в реальном времени с разными QoS требованиями

Вопросы для размышления

  • Как бы изменилась архитектура Figma, если бы нужно было поддерживать офлайн-редактирование с синхронизацией при восстановлении соединения?
  • При каком количестве одновременных пользователей LWW-стратегия разрешения конфликтов начинает создавать заметный UX-дискомфорт? Как это зависит от типа контента?
  • Почему Excalidraw выбрал p2p WebRTC вместо центрального сервера? Какие архитектурные компромиссы это создаёт?

Связанные уроки

  • net-01-intro
Collaborative Whiteboard

0

1

Войти