Как создать многопользовательское веб-приложение ajax для обеспечения безопасности одновременно

У меня есть веб-страница, на которой отображается большой объем данных с сервера. Связь выполняется через ajax.

Каждый раз, когда пользователь взаимодействует и изменяет эти данные (скажем, пользователь A переименовывает что-то), он сообщает серверу выполнить действие, и сервер возвращает новые измененные данные.

Если пользователь B одновременно обращается к странице и создает новый объект данных, он снова сообщает серверу через ajax, и сервер вернется с новым объектом для пользователя.

На странице есть данные с переименованным объектом. А на странице B мы имеем данные с новым объектом. На сервере данные имеют как переименованный объект, так и новый объект.

Каковы мои настройки для синхронизации страницы с сервером, когда несколько пользователей используют его одновременно?

Такие опции, как блокирование всей страницы или сброс всего состояния пользователю при каждом изменении, скорее всего не будут устранены.

Если это помогает, в этом конкретном примере веб-страница вызывает статический веб-метод, который запускает хранимую процедуру в базе данных. Хранимая процедура вернет любые данные, которые она изменила, и не более. Затем статический веб-метод пересылает клиенту возврат хранимой процедуры.

Bounty Edit:

Как вы создаете многопользовательское веб-приложение, которое использует Ajax для связи с сервером, но избегает проблем с concurrency?

т.е. одновременный доступ к функциям и данные в базе данных без риска заражения данными или состояниями.

Ответ 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 должен поддерживать соединения с несколькими серверами одновременно.

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

Кристоф Страшен

Ответ 2

Я знаю, что это старый вопрос, но я думал, что просто включился.

OT (операционные преобразования) кажутся подходящими для вашего требования к параллельному и последовательному многопользовательскому редактированию. Это метод используемый в Документах Google (и также использовался в Google Wave):

Там есть JS-библиотека для использования Operational Transforms - ShareJS (http://sharejs.org/), написанная членом команды Google Wave.

И если вы хотите, есть полная веб-фреймворк MVC - DerbyJS (http://derbyjs.com/), построенный на ShareJS, который делает все это для вы.

Он использует BrowserChannel для связи между сервером и клиентами (и я считаю, что поддержка WebSockets должна быть в работе - она ​​была там ранее через Socket.IO, но была выведена из-за проблем с разработчиками с Socket.io) Новичок docs немного редки в данный момент.

Ответ 3

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

Ответ 4

Вам нужно использовать методы push (также известные как Comet или reverse Ajax) для распространения изменений пользователю, как только они будут сделаны в db. Лучшей техникой, доступной в настоящее время для этого, кажется, является длинный опрос Ajax, но он не поддерживается каждым браузером, поэтому вам нужны резервные копии. К счастью, уже есть решения, которые обрабатывают это для вас. Среди них: orbited.org и уже упомянутый socket.io.

В будущем будет более простой способ сделать это, который называется WebSockets, но пока не уверен, когда этот стандарт будет готов к прайм-тайму, так как есть проблемы безопасности относительно текущего состояния стандарта.

В базе данных с новыми объектами не должно быть проблем concurrency. Но когда пользователь редактирует объект, сервер должен иметь некоторую логику, которая проверяет, был ли объект отредактирован или удален тем временем. Если объект был удален, решение снова просто: просто отмените редактирование.

Но самая сложная проблема возникает, когда несколько пользователей одновременно редактируют один и тот же объект. Если пользователь 1 и 2 начнут редактировать объект одновременно, они оба сделают свои изменения на одни и те же данные. Скажем, изменения, внесенные пользователем 1, сначала отправляются на сервер, пока Пользователь 2 все еще редактирует данные. У вас есть два варианта: вы можете попытаться объединить изменения User 1 в данные User 2 или вы могли бы сообщить User 2, что его данные устарели, и вывести ему сообщение об ошибке, как только его данные будут отправлены на сервер. Последнее здесь не очень удобно, но первое очень сложно реализовать.

Одна из немногих реализаций, которая действительно получила это право в первый раз, была EtherPad, которая была приобретена Google. Я полагаю, что они использовали некоторые технологии EtherPad в Документах Google и Google Wave, но я не могу этого точно сказать. Google также открыл EtherPad, поэтому, возможно, стоит посмотреть, в зависимости от того, что вы пытаетесь сделать.

Это очень непросто сделать одновременно с редактированием материала, потому что из-за латентности невозможно выполнять атомарные операции в Интернете. Возможно, эта статья поможет вам узнать больше о теме.

Ответ 5

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

Я обнаружил, что структура Meteor делает это хорошо (http://docs.meteor.com/#reactivity).

"Meteor охватывает концепцию реактивного программирования. Это означает, что вы можете написать свой код в простом императивном стиле, и результат будет автоматически пересчитываться всякий раз, когда данные изменятся, зависит ваш код."

"Этот простой шаблон (реактивный расчет + реактивный источник данных) имеет широкую применимость. Программист сохраняется от записи отказов от подписки/повторной подписки и обеспечения того, чтобы их вызывали в нужное время, исключая целые классы кода распространения данных, которые в противном случае заткните приложение с ошибкой, подверженной ошибкам".

Ответ 6

Не могу поверить, что никто не упомянул Meteor. Это совершенно новая и незрелая структура (и только официально поддерживает одну БД), но она требует всякой работы и мышления из многопользовательского приложения, как описывает плакат. На самом деле вы не можете создать многопользовательское приложение для обновления в реальном времени. Вот краткое резюме:

  • Все находится в node.js(JavaScript или CoffeeScript), поэтому вы можете делиться такими вещами, как проверки между клиентом и сервером.
  • Он использует веб-узлы, но может отступить для старых браузеров.
  • Он фокусируется на немедленных обновлениях локального объекта (т.е. пользовательский интерфейс чувствует себя быстро), при этом изменения отправляются на сервер в фоновом режиме. Разрешается только упрощение обновлений для микширования. Обновления, отклоненные на сервере, откатываются.
  • В качестве бонуса он обрабатывает перезагрузки Live code для вас и будет сохранять состояние пользователя, даже если приложение радикально изменится.

Метеор достаточно прост, и я предлагаю вам хотя бы взглянуть на него, чтобы идеи украли.

Ответ 7

Эти страницы в Википедии могут помочь добавить перспективу в изучение concurrency и параллельные вычисления для разработки ajax веб-приложение, что либо тянет, либо нажал state event (EDA) сообщения в шаблоне обмена сообщениями. В основном, сообщения реплицируются на канальные абоненты, которые реагируют на изменения событий и запросы синхронизации.

Существует много форм параллельного веб-интерфейса совместного программного обеспечения.

Существует несколько клиентских библиотек HTTP API для etherpad-lite, совлокальный редактор в режиме реального времени.

django-realtime-playground реализует приложение чата реального времени в Django с различными технологиями реального времени, такими как Socket.io.

Оба AppEngine и AppScale реализуют API канала AppEngine; который отличается от Google Realtime API, который демонстрируется googledrive/realtime-playground.

Ответ 8

Технологии на стороне сервера - вот путь. Comet является (или было?) звуковым словом.

Особое ваше направление зависит от вашего стека серверов и от того, насколько вы гибки. Если вы можете, я бы посмотрел на socket.io, который обеспечивает кросс-браузерную реализацию веб-гейтов, которые обеспечивают очень простой способ имеют двунаправленную связь с сервером, позволяя серверу нажимать обновления для клиентов.

В частности, см. эту демонстрацию автором библиотеки, которая демонстрирует почти точную ситуацию, которую вы описываете.