Проектирование аналога Google Docs

в 9:00, , рубрики: Google Docs, ruvds_перевод, одноранговая архитектура, онлайн-редакторы, текстовые редакторы

Проектирование аналога Google Docs - 1


Google docs – это сервис для совместного редактирования документов. В целом подобные сервисы можно спроектировать двумя способами:

  • В качестве централизованного ресурса, использующего клиент-серверную архитектуру для предоставления возможности редактирования документа всем пользователям.
  • На базе одноранговой архитектуры, позволяющей разным людям совместно работать над одним документом.

Большинство коммерческих решений ориентированы на клиент-серверный подход ввиду предоставляемого им более детального контроля. Так что и мы в этой статье разберём проектирование сервиса с использованием именно клиент-серверной архитектуры.

Требования

▍ Функциональные

  • Совместная работа над документом: система должна обеспечивать возможность одновременного просмотра или редактирования документов множеством пользователей.
  • Разрешение конфликтов: система должна интерактивно транслировать вносимые в документ правки по всем пользователям, которые над этим документом работают. При этом она также должна разрешать конфликты, возникающие между пользователями при редактировании одной и той же части документа.
  • Автодополнение: пользователю должны предлагаться варианты автозавершения часто используемых слов и фраз, а также исправление грамматических ошибок.
  • Число просмотров: редакторам должна быть доступна информация о количестве просмотров документа.
  • История: программа должна отображать историю совместной работы над документом.

▍ Нефункциональные

  • Задержка: во время работы над одним документом к системе может быть подключено множество пользователей. И если они будут географически распределены по удалённым локациям, то обеспечение устойчиво низкой задержки окажется непростой задачей.
  • Согласованность: система должна разрешать конфликты, возникающие при одновременном редактировании одних и тех же частей документа разными пользователями, обеспечивая его согласованное представление. В то же время пользователи из разных регионов должны наблюдать обновлённую версию документа. Поддержание согласованности является важным аспектом для всех пользователей, независимо от того, находятся они в одном регионе или в разных.
  • Доступность: сервис должен быть доступен всегда и являться устойчивым к сбоям.
  • Масштабируемость: на случай роста числа одновременных пользователей в архитектуру сервиса должна быть заложена возможность увеличения мощности.

Компоненты

▍ Хранилища данных

  • Реляционная база данных – для хранения информации о пользователях и документах. На основе этих данных будут предоставляться различные права доступа.
  • NoSQL — для хранения комментариев пользователей и организации быстрого доступа к ним.
  • Временной ряд — для сохранения истории изменения документов.
  • Хранилище BLOB-объектов — для хранения видео и изображений внутри документа.
  • Кэш — распределённый кэш вроде Redis и CDN для обеспечения высокой производительности на стороне конечных пользователей. Redis мы используем для хранения разных структур данных, включая пользовательские сессии, признаки для функции автозаполнения, а также часто используемые документы. При этом с помощью CDN мы сохраняем наиболее часто открываемые документы и тяжёлые объекты, такие как изображения и видео.

▍ Очередь на обработку

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

▍ Прочие компоненты

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

Проектирование аналога Google Docs - 2
Рис. 1 Подробная схема сервиса для совместного редактирования документов

Рабочий поток

  • Совместное редактирование и разрешение конфликтов: каждый запрос передаётся в очередь операций. Именно здесь разрешаются конфликты между правками одной и той же части документа. Если конфликтов нет, данные собираются в пакет и сохраняются в базе данных временных рядов через серверы сессий. Для повышения эффективности использования хранилища видео и изображения подвергаются сжатию. Символы обрабатываются сразу.
  • История: база данных временных рядов позволяет восстанавливать различные версии документа. При этом можно использовать операции DIFF, позволяющие сравнивать разные версии документа и определять отличия между ними для восстановления более старых ревизий.
  • Асинхронные операции: уведомления, электронные письма, количество просмотров и комментарии – всё это относится к асинхронным операциям, которые можно добавлять в очередь с помощью системы «издатель-подписчик» вроде Kafka. Шлюз API генерирует эти запросы и перенаправляет в модуль «издатель-подписчик».
  • Предложения: предложения реализуются через службу автозавершения, предлагающую автоматическое дополнение ввода часто используемых слов и фраз. Эта служба также может извлекать из документа атрибуты и ключевые слова, предлагая пользователю те или иные варианты. Поскольку слов может быть много, мы для этой задачи используем базу данных NoSQL. Кроме того, часто используемые слова и фразы будут сохраняться в кэше Redis.
  • Импорт и экспорт документов: серверы приложения выполняют ряд важных задач, включая импорт и экспорт документов. Помимо этого, они конвертируют документы из одного формата в другой. К примеру, документ .doc или .docx можно конвертировать в .pdf и наоборот. Серверы приложения также отвечают за извлечение признаков для службы автозавершения.

Подробный дизайн

▍ Текстовый редактор

Документ представляет собой набор символов, расположенных в определённом порядке. Каждый символ имеет значение и индекс размещения. В качестве символа может выступать буква, число, возврат каретки (
) или пробел. Индекс представляет позицию символа в упорядоченном списке всех символов.

Задача текстового редактора заключается в выполнении с содержащимися в нём символами таких операций, как insert(), delete(), edit() и многих других. Ниже показан пример документа и выполнения в нём этих операций.

Проектирование аналога Google Docs - 3
Рис. 2 Схема выполнения текстовым редактором различных операций

▍ Конкурентность

Совместная работа над одним документом разными пользователями порой может вызывать проблемы, связанные с одновременным редактированием. Бывает, что при изменении одной и той же части документа несколькими пользователями возникают конфликты. Поскольку у редактирующих есть локальная копия этого документа, итоговое его состояние на сервере может не совпадать с тем, что они видят на своей машине. Получается, что после передачи сервером обновлённой версии пользователи иногда наблюдают неожиданный результат.

Добавление символа в один и тот же позиционный индекс:

Проектирование аналога Google Docs - 4
Рис. 3 Как изменение двумя пользователями одного и того же символа может привести к конфликту

Удаление одного и того же символа:
Проектирование аналога Google Docs - 5
Рис. 4 Как удаление одного и того же символа может привести к неожиданным изменениям

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

В этом механизме должно быть учтено два аспекта:

  • Коммутативность: порядок применяемых операций не должен влиять на результат.
  • Идемпотентность: одинаковые операции в случае повторения должны применяться только раз.

Техники разрешения конфликтов

▍ Операционная трансформация (OT)

Эта техника широко используется для разрешения конфликтов при совместном редактировании текстов без применения блокировки. Если выполняемые разными людьми операции конфликтуют, OT разрешает этот конфликт и передаёт корректное итоговое состояние конечным пользователям, обеспечивая тем самым согласованное представление.

В этом случае разрешение конфликтов происходит за счёт использования в операциях позиционного индекса символов. Описанные выше проблемы эта техника решает за счёт сохранения коммутативности и идемпотентности.

Проектирование аналога Google Docs - 6
Рис. 5 Пример операционной трансформации

Текстовые редакторы, использующие ОТ, дают согласованные результаты, если соблюдают два свойства:

  • Сохранение последовательности: если операция a произошла до операции b, она выполняется до неё.
  • Конвергентность: все копии документа, находящиеся на разных клиентах, в конечном итоге оказываются одинаковыми.

Описанные выше свойства являются частью модели СС (Causal Сonsistency, причинная согласованность), используемой при совместном редактировании.

При этом у техники операционной трансформации есть два недостатка:

  • Любая операция с символами может привести к изменению позиционного индекса, а значит порядок их выполнения имеет значение.
  • Её сложно разрабатывать и реализовывать.

Операционная трансформация представляет собой набор алгоритмов, и её реализация в реальных проектах требует немалых усилий. Например, команде Google Wave для написания алгоритма ОТ потребовалось два года.

▍ Бесконфликтный реплицируемый тип данных (CRDT)

Этот принцип был разработал в качестве улучшенной альтернативы ОТ. CRDT (Conflict-free Replicated Data Type) имеет сложную структуру, но при этом является более простым алгоритмом.

Он выполняет условия коммутативности и идемпотентности за счёт применения к каждому символу двух ключевых свойств:

  • Глобально уникального идентификатора.
  • Глобального упорядочивания.

Теперь каждая операция имеет обновлённую структуру данных:

Проектирование аналога Google Docs - 7
Рис. 6 Упрощённая структура данных CRDT

Свойство SiteID с помощью Value и PositionalIndex уникально идентифицирует область, для которой пользователь запрашивает операцию. При этом значение PositionalIndex может быть представлено дробью, чтобы:

  • PositionalIndex других символов не изменялся вследствие каких-либо операций.
  • Исключить зависимость от порядка выполнения операций разными пользователями.

Пример ниже показывает, что пользователь с идентификатором области 123e4567-e89b-12d3 вставляет символ со значением A в PositionalIndex со значением 1.5. И хотя эта операция добавляет новый символ, позиционный индекс существующих символов сохраняется за счёт использования дробных значений. Таким образом исключается зависимость от последовательности выполнения операций. Как видно из примера, операция insert(), выполненная между O и T, не изменила позицию T.

Проектирование аналога Google Docs - 8
Рис. 7 Устранение зависимости от порядка выполнения операций

CRDT позволяет обеспечить стабильную согласованность текста у разных пользователей. Даже если некоторые из них в момент внесения правок окажутся офлайн, когда они вернуться в сеть, хранящиеся на их устройствах локальные копии документа будут приведены к единому представлению.

И хотя популярные платформы для онлайн-редактирования документов вроде Google Docs, Etherpad и Firepad используют технику OT, CRDT значительно упростил одновременную работу над общими документами, в том числе повысив её согласованность. В действительности с помощью CRDT можно реализовать бессерверный одноранговый сервис для совместного редактирования текстов.

Примечание: OT и CRDT являются прекрасными техниками для разрешения конфликтов в случае совместного редактирования, но за счёт использования WebSockets мы сможем исключить возникновение конфликтов в принципе. Как? Эта технология позволяет нам выделять в документе курсор активного участника, видимый всем остальным. В итоге другие редактирующие этот документ пользователи смогут видеть, в какой области происходит работа, и избегать внесения в неё параллельных правок.

Итоги

▍ Согласованность

Мы разобрали две техники, с помощью которых можно добиться стабильной согласованности при разрешении конфликтов редактирования: операционная трансформация (ОТ) и бесконфликтные реплицируемые типы данных (CRDT). Помимо этого, база данных временных рядов позволяет нам сохранять последовательность происходящих событий. После разрешения конфликта с помощью ОТ или CRDT итоговый результат сохраняется в этой базе данных. Таким образом мы достигаем согласованности между отдельными операциями.

Нам также нужно сохранять согласованность документа между разными серверами датацентра. Для одновременного копирования и обновления его состояния в одном датацентре можно использовать одноранговые протоколы вроде Gossip. И такая стратегия повысит не только согласованность, но и доступность.

▍ Доступность

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

В добавок ко всему, наши WebSocket-серверы могут подключать пользователей к серверам, обслуживающим сессии, которые, в свою очередь, будут определять, работает ли пользователь с документом. Наконец, мы задействуем службы кэширования и CDN (Content Delivery Network, сеть доставки содержимого) для повышения доступности в случае сбоев.

▍ Масштабируемость

За счёт использования архитектуры микросервисов мы с лёгкостью сможем масштабировать отдельные компоненты, если вдруг число запросов в очереди операций начнёт превышать ёмкость какого-либо из них. В этом случае каждая очередь операций будет связана с одним документом. Мы можем перенаправлять операции, запрошенные разными пользователями, связанными с одним документом, в отдельную очередь. В итоге число созданных очередей будет равно количеству активных документов. Таким образом мы реализуем горизонтальное масштабирование.

Автор: Дмитрий Брайт

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js