Ответ 1
Обзор:
- Введение
- Архитектура сервера
- Архитектура клиента
- Случай обновления
- Дело с фиксацией
- Конфликтный случай
- Производительность и масштабируемость
Привет, Рейнос,
Здесь я не буду обсуждать какой-либо конкретный продукт. То, о чем говорили другие, - это хороший набор инструментов, который можно посмотреть уже (возможно, добавить в этот список node.js).
С архитектурной точки зрения у вас, похоже, та же проблема, что и в программном обеспечении для управления версиями. Один пользователь проверяет изменение объекта, другой пользователь хочет изменить один и тот же объект по-другому = > конфликт. Вы должны интегрировать изменения пользователей в объекты и в то же время своевременно и эффективно предоставлять обновления, обнаруживать и разрешать конфликты, подобные приведенным выше.
Если бы я был на твоем месте, я бы разработал что-то вроде этого:
1. Серверный:
-
Определите разумный уровень, на котором вы бы определили, что я бы назвал "атомными артефактами" (страница? Объекты на странице? Значения внутри объектов?). Это будет зависеть от ваших веб-серверов, базы данных и оборудования для кеширования, # пользователя, # объектов и т.д. Нелегкое решение сделать.
-
Для каждого атомного артефакта:
- уникальный уникальный идентификатор
- инкрементирующий идентификатор версии
- механизм блокировки для доступа к записи (возможно, mutex)
- небольшая история или "журнал изменений" внутри ringbuffer (общая память хорошо работает для них). Одна пара ключей и значений может быть в порядке, хотя и менее расширяемой. см. http://en.wikipedia.org/wiki/Circular_buffer
-
Сервер или псевдо-серверный компонент, способный эффективно доставлять соответствующие изменения для подключенного пользователя. Observer-Pattern - ваш друг для этого.
2. Клиентский:
-
Клиент javascript, который может иметь длительное HTTP-соединение с указанным сервером выше или использует легкий опрос.
-
Компонент artfact-updater javascript, который обновляет содержимое сайтов, когда подключенный клиент javascript уведомляет об изменениях в просмотренных артефактах-истории. (опять-таки шаблон наблюдателя может быть хорошим выбором)
-
Компонент артефакта javascript-коммиттера, который может запрашивать изменение атомного артефакта, пытаясь получить блокировку мьютекса. Он обнаружит, изменилось ли состояние артефакта другим пользователем за несколько секунд до этого (латентность клиента javascript и факторы процесса фиксации) путем сравнения известного идентификатора артефакта-версии clientide и текущего идентификатора артефакта-сервера serveride.
-
Решатель, разрешающий javascript, позволяющий человеку, который имеет право изменить решение. Возможно, вы не захотите просто сказать пользователю: "Кто-то был быстрее вас, я удалил ваши изменения. Многие варианты из довольно технических различий или более удобные для пользователя решения кажутся возможными.
Итак, как бы он катился...
Случай 1: диаграмма типа последовательности для обновления:
- Браузер отображает страницу
- javascript "видит" артефакты, каждый из которых имеет по крайней мере одно поле значения, уникальный и идентификатор версии
- запускается javascript-клиент, запрашивая "посмотреть" найденную историю артефактов, начиная с найденных версий (более старые изменения не интересны).
- Серверный процесс отмечает запрос и постоянно проверяет и/или отправляет историю
- Записи истории могут содержать простые уведомления: "артефакт x изменился, данные запроса клиента pls", позволяющие клиенту опросить независимо или полные наборы данных "артефакт x изменился на значение foo"
- javascript artefact-updater делает все возможное, чтобы получить новые значения, как только они станут известны для обновления. Он выполняет новые запросы ajax или получает питание от javascript-клиента.
- Обновлены страницы DOM-контента, пользователь дополнительно уведомлен. Наблюдение за историей продолжается.
Случай 2: теперь для фиксации:
- Артефакт-коммиттер знает нужное новое значение из пользовательского ввода и отправляет запрос на изменение на сервер
- serveride mutex получен
- Сервер получает "Эй, я знаю состояние артефакта x из версии 123, позвольте мне установить его значение foo pls."
- Если версия артефакта x Serverside равна (не может быть меньше), чем 123, новое значение принимается, генерируется новый идентификатор версии 124.
- Новая информация о состоянии "обновлена до версии 124" и необязательно новое значение foo помещается в начало артефакта x ringbuffer (changelog/history)
- serverute mutex выпущен
- запрос посредника артефакта с радостью получит подтверждение фиксации вместе с новым идентификатором.
- Между тем серверный серверный сервер продолжает опрос/нажатие буферов для подключенных клиентов. Все клиенты, наблюдающие за буфером артефакта x, получат новую информацию о состоянии и значение в пределах их обычной латентности (см. Случай 1.)
Случай 3: для конфликтов:
- Коммандер артефакта знает нужное новое значение из пользовательского ввода и отправляет запрос на изменение на сервер
- в то время как другой пользователь успешно обновил тот же артефакт (см. случай 2.), но из-за различных задержек это еще неизвестно нашему другому пользователю.
- Таким образом, мьютекс с серверами приобретается (или дожидается до тех пор, пока пользователь "быстрее" не выполнит свое изменение).
- Сервер получает "Эй, я знаю состояние артефакта x из версии 123, позвольте мне установить его значение foo".
- На Serverside версия артефакта x теперь уже 124. Запрашивающий клиент не может знать значение, которое он будет переписывать.
- Очевидно, что сервер должен отклонить запрос на изменение (не считая приоритетных приоритетов перезаписывания богов), освобождает мьютекс и достаточно любезно отправить обратно новый идентификатор версии и новое значение непосредственно клиенту.
- столкнулся с отклоненным запросом на совершение сделки и значением, которое еще не знал пользователь, запрашивающий изменения, коммиттер javascript-артефакт ссылается на разрешающий процесс конфликта, который отображает и объясняет проблему пользователю.
- Пользователь, которому предоставлены некоторые параметры интеллектуальным конфликтом-резольвером JS, разрешается другая попытка изменить значение.
- Как только пользователь выбрал значение, которое он считает правильным, процесс начинается с случая 2 (или случай 3, если кто-то был быстрее, снова)
Несколько слов о производительности и масштабируемости
HTTP-опрос против HTTP "pushing"
- Опрос создает запросы, по одному в секунду, 5 в секунду, независимо от того, что вы считаете приемлемой задержкой. Это может быть довольно жестоко для вашей инфраструктуры, если вы не настроите свои (Apache?) И (php?) Достаточно хорошо, чтобы быть "легкими" стартерами. Желательно оптимизировать запрос опроса на сервере, чтобы он работал намного меньше времени, чем длина интервала опроса. Разделение этой рабочей среды пополам может означать снижение всей загрузки системы на 50%,
- Нажатие по HTTP (при условии, что веб-работники слишком далеки для их поддержки) потребует, чтобы у каждого пользователя все время был доступен один процесс apache/lighthttpd. Резидентная память, зарезервированная для каждого из этих процессов, и общая память вашей системы будет одним очень ограниченным пределом масштабирования, с которым вы столкнетесь. Будет необходимо сократить объем памяти в связи с подключением, а также ограничить количество непрерывных операций ЦП и ввода/вывода в каждом из них (вы хотите много времени сна/простоя)
масштабирование бэкэнд
- Забудьте о базе данных и файловой системе, вам потребуется какой-то бэкэнд на основе разделяемой памяти для частого опроса (если клиент не проводит опрос напрямую, тогда будет выполняться каждый запущенный серверный процесс)
- Если вы идете на memcache, вы можете масштабироваться лучше, но его еще дороже
- Мьютекс для commits должен работать глобально, даже если вы хотите иметь несколько интерфейсных серверов для балансировки.
масштабирование интерфейса
- независимо от того, хотите ли вы опросить или получить "толкает", попробуйте получить информацию обо всех наблюдаемых артефактах за один шаг.
"творческие" настройки
- Если клиенты опроса и многие пользователи имеют тенденцию наблюдать одни и те же артефакты, вы можете попытаться опубликовать историю этих артефактов как статический файл, позволяя apache кэшировать его, тем не менее обновляя его на сервере, когда артефакты меняются. Это заставляет PHP/memcache выходить из игры для запросов. Lighthttpd эффективен при обслуживании статических файлов.
- используйте сеть доставки контента, например, cotendo.com, чтобы указать историю артефактов. Задержка с нажатием будет больше, но масштабируемость - мечта.
- написать реальный сервер (не используя HTTP), с которым пользователи подключаются к использованию java или flash (?). Вы должны иметь дело с обслуживанием многих пользователей в одном серверном потоке. Велоспорт через открытые сокеты, выполнение (или делегирование) требуемой работы. Может масштабироваться с помощью процессов forking или запускать больше серверов. Мьютексы должны оставаться глобальными уникальными, хотя.
- В зависимости от сценариев загрузки группируйте свои интерфейсные и серверные серверы с помощью диапазонов артефакт-идентификаторов. Это позволит лучше использовать постоянную память (без базы данных все данные) и позволяет масштабировать мьютекс. Ваш javascript должен поддерживать соединения с несколькими серверами одновременно.
Хорошо, я надеюсь, что это может стать началом для ваших собственных идей. Я уверен, что есть еще много возможностей. Я более чем приветствую любую критику или усовершенствования этого сообщения, вики разрешены.
Кристоф Страшен