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

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

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

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

на странице A у нас есть данные с переименованным объектом. И на странице B у нас есть данные с новым объектом. На сервере данные и переименованный объект и новый объект.

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

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

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

Bounty Edit:

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

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

8 ответов


описание:

  • интро
  • архитектура сервера
  • архитектура клиент
  • случае обновления
  • совершить дело
  • случае конфликта
  • производительность и масштабируемость

Привет Raynos,

Я не буду обсуждать какой-либо конкретный продукт здесь. То, что другие упоминали, - это хороший набор инструментов, на который уже можно взглянуть (возможно, добавить узел.js к этому списку).

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

Если бы я был на вашем месте, я бы развил что-то вроде этого:

1. Серверная Сторона:

  • определите разумный уровень, на котором вы определили бы то, что я бы назвал "атомными артефактами" (страница? Объекты на странице? Значения внутри объектов?). Это будет зависеть от ваших веб-серверов, базы данных и оборудования кэширования, # пользователя, # объектов и т. д. Нелегкое решение.

  • для каждого атомарного артефакта есть:

    • приложение-широкий уникальный id
    • инкрементный версия-код
    • механизм блокировки для доступа на запись (возможно, мьютекс)
    • небольшая история или "список изменений" внутри ringbuffer (общая память хорошо работает для них). Одна пара ключ-значение может быть в порядке, хотя и менее расширяемой. см.http://en.wikipedia.org/wiki/Circular_buffer
  • сервер или псевдо-серверный компонент, который способен доставить соответствующей изменения для подключенного пользователя эффективно. Наблюдатель-образец-ваш друг для этого.

2. Сторона Клиента:

  • клиент javascript, который может иметь длительное HTTP-соединение с указанным выше сервером или использует легкий опрос.

  • компонент javascript artifact-updater, который обновляет содержимое сайтов, когда подключенный клиент javascript уведомляет об изменениях в истории наблюдаемых артефактов. (опять же, шаблон наблюдателя может быть хорошим выбор)

  • компонент JavaScript artifact-committer, который может запросить изменение атомарного артефакта, пытаясь получить блокировку мьютекса. Он определит, было ли состояние артефакта изменено другим пользователем за несколько секунд до этого (латансия клиента javascript и фиксация факторов процесса) путем сравнения известного артефакта на стороне клиента-version-id и текущего артефакта на стороне сервера-version-id.

  • решатель конфликтов javascript, позволяющий человеку какое-изменение-правильное решение. Вы не можете просто сказать пользователю: "кто-то был быстрее вас. Я удалил твою сдачу. Иди поплачь.". Многие варианты из довольно технических различий или более удобных решений кажутся возможными.

Итак, как он будет катиться ...

Случай 1: вид последовательности диаграмм для обновления:

  • браузер отображает страницы
  • javascript "видит" артефакты, каждый из которых имеет хотя бы одно поле значений, уникальное-и версия-код
  • клиент javascript запускается, запрашивая "посмотреть" историю найденных артефактов, начиная с их найденных версий (старые изменения не интересны)
  • серверный процесс отмечает запрос и непрерывно проверяет и / или отправляет историю
  • записи истории могут содержать простые уведомления "артефакт x изменился, данные запроса клиента pls", позволяющие клиенту опрашивать независимо или полные наборы данных " артефакт x изменился на значение foo"
  • JavaScript artifact-updater делает все возможное, чтобы получить новые значения, как только станет известно, что они обновлены. Он выполняет новые запросы ajax или получает питание от клиента javascript.
  • страницы DOM-content обновляется, пользователь дополнительно уведомляется. Наблюдение за историей продолжается.

случай 2: Теперь для совершения:

  • artifact-committer знает желаемое новое значение из пользовательского ввода и отправляет запрос на изменение сервер
  • приобретен мьютекс serverside
  • сервер получает " Эй, я знаю состояние артефакта x от версии 123, позвольте мне установить его в значение foo pls."
  • если серверная версия артефакта x равна (не может быть меньше) 123, принимается новое значение, генерируется новый идентификатор версии 124.
  • новое состояние-информация "обновлено до версии 124" и, возможно, новое значение foo помещаются в начале ringbuffer артефакта x (журнал изменений/история)
  • выпущен мьютекс serverside
  • запрашивающий фиксатор артефактов рад получить подтверждение фиксации вместе с новым идентификатором.
  • тем временем серверный серверный компонент поддерживает опрос/толкает ringbuffers для подключенных клиентов. Все клиенты, наблюдающие за буфером артефакта x, получат новую информацию о состоянии и значение в пределах своей обычной задержки (см. случай 1.)

Случай 3: для конфликты:

  • Artifact committer знает желаемое новое значение из пользовательского ввода и отправляет запрос на изменение на сервер
  • тем временем другой пользователь успешно обновил тот же артефакт (см. случай 2.) но из-за различных задержек это еще неизвестно нашему другому пользователю.
  • таким образом, серверный мьютекс приобретается (или ждал, пока "более быстрый" пользователь не совершит свое изменение)
  • сервер получает " Эй, я знаю состояние артефакта x из версии 123, позвольте мне установить значение foo."
  • на стороне сервера версия артефакта x теперь уже 124. Запрашивающий клиент не может знать значение, которое он будет перезаписывать.
  • очевидно, что сервер должен отклонить запрос на изменение (не считая приоритетов перезаписи с вмешательством Бога), освобождает мьютекс и достаточно любезен, чтобы отправить обратно новый идентификатор версии и новое значение непосредственно клиенту.
  • столкнулся с отклоненным запросом фиксации и значением пользователь, запрашивающий изменение, еще не знал, что фиксатор артефактов javascript ссылается на распознаватель конфликтов, который отображает и объясняет проблему пользователю.
  • пользователь, будучи представлены некоторые варианты смарт-конфликт-резолвер в JS, допускается еще одна попытка изменить значение.
  • как только пользователь выбрал значение, которое он считает правильным, процесс начинается с случая 2 (или случая 3, Если кто-то другой был быстрее, снова)

несколько слов о производительности & Масштабируемость

HTTP Polling vs. HTTP"pushing"

  • опрос создает запросы, один в секунду, 5 в секунду, независимо от того, что вы считаете приемлемой задержкой. Это может быть довольно жестоко для вашей инфраструктуры, если вы не настроите свой (Apache?) и (РНР?) достаточно хорошо, чтобы быть" легкими " стартерами. Желательно оптимизировать запрос опроса на стороне сервера, чтобы он выполнялся в течение гораздо меньшего времени, чем длина интервала опроса. Разделить это время выполнения в два раза может означать снижение всей нагрузки системы до 50%,
  • нажатие через HTTP (предполагая, что веб-рабочие слишком далеки, чтобы поддерживать их) потребует от вас одного процесса apache/lighthttpd для каждого пользователя все время. Резидентная память, зарезервированная для каждого из этих процессов, и общая память вашей системы будут одним очень определенным ограничением масштабирования, с которым вы столкнетесь. Уменьшение объема памяти соединения будет необходимо, так как а также ограничение количества непрерывной работы процессора и ввода-вывода в каждом из них (вы хотите много сна/простоя)

бэкэнд масштабирование

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

интерфейс масштабирование

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

"творческих" настроек

  • если клиенты опрашивают и многие пользователи склонны смотреть те же артефакты, вы можете попытаться опубликовать историю этих артефактов как статический файл, позволяющий apache кэшировать его, тем не менее обновляя его на стороне сервера при изменении артефактов. Это выводит PHP / memcache из игры для некоторых запросов. Lighthttpd очень эффективен при обслуживании статических файлов.
  • используйте сеть доставки контента, например cotendo.com чтобы протолкнуть туда историю артефактов. Толчок-задержка будет больше, но масштабируемость-это мечта
  • напишите реальный сервер (не используя HTTP), к которому пользователи подключаются с помощью java или flash (?). Ты должен разобраться. с обслуживанием многих пользователей в одном сервере-потоке. Езда на велосипеде через открытые сокеты, выполнение (или делегирование) требуемой работы. Может масштабироваться с помощью процессов разветвления или запуска нескольких серверов. Однако мьютексы должны оставаться глобально уникальными.
  • в зависимости от сценариев загрузки сгруппируйте интерфейсные и серверные серверы по диапазонам идентификаторов артефактов. Это позволит лучше использовать постоянную память (ни одна база данных не имеет всех данных) и позволяет масштабировать мьютексинг. Ваш javascript должен поддерживать соединения с несколькими серверами одновременно.

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

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


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

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

существует библиотека на основе JS для использования операционных преобразований-ShareJS (http://sharejs.org/), написанный участником из Google Wave команда.

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

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


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


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

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

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

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

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

Это действительно нелегко сделать это одновременно с редактированием материала, потому что невозможно выполнять атомарные операции в интернете из-за задержки. Может быть!--13-->в этой статье поможет вам узнать больше о теме.


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

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

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

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


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

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

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


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

там есть много форм параллельных веб-основе совместное программное обеспечение.

есть несколько клиентские библиотеки HTTP API для etherpad-lite, a совместный редактор в реальном времени.

Джанго-в реальном времени-площадка реализует чат приложение в реальном времени в Django с различными технологиями реального времени, как гнездо.io.

Как AppEngine, так и AppScale реализуют Канал AppEngine В API; который отличается от Google realtime API, что подтверждается googledrive / realtime-игровая площадка.


серверный push методы-это путь сюда. Комета есть (или был?) модное слово.

конкретное направление, которое вы принимаете, сильно зависит от вашего стека сервера и насколько вы/он гибки. Если можете, я хотел бы взглянуть на гнездо.Ио, который обеспечивает кросс-браузерную реализацию websockets, которые обеспечивают очень упрощенный способ двунаправленной связи с сервером, позволяя серверу нажимать обновления на клиенты.

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