блокировка на ферме серверов (asp.net) - PullRequest
4 голосов
/ 21 декабря 2011

Я хотел бы знать, есть ли способы выполнить «блокировку» веб-приложения asp.net, которое развернуто на нескольких серверах, с использованием распределенного сервера, такого как MySQL Cluster.

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

Баланс учетной записи участника 1 равен 100.

  • Запрос A обращается к серверу 1, чтобы добавить 100 к балансу участника 1
  • Запрос B обращается к серверу 2добавить 50 к балансу члена 1

Таким образом, запрос A обновляет баланс с 100 до 200 и сохраняет.
Запрос B обновляет баланс до 150 и сохраняет.

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

Как можно заблокировать такой запрос, что Запрос B должен будет ждать, пока Запрос A завершится, пока не получитостаток средств.Если бы это был один процесс, он мог бы быть реализован блокировкой всего приложения.Однако, поскольку существует несколько независимых процессов, это не будет работать, так как для Сервера 1 он не заблокирован, и ни для Сервера 2

Какие-либо идеи или рекомендации, как это можно сделать?

Ответы [ 3 ]

4 голосов
/ 21 декабря 2011

Для этого предназначены транзакции.

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

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

Решение состоит в том, чтобыиспользуйте поле в таблице, которое изменяется при каждом изменении строки - в SQL Server 2008 это тип rowversion .

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

1 голос
/ 07 марта 2013

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

1 голос
/ 27 июня 2012

В созданной мной ORM реализован механизм блокировки.Каждый тип объекта, такой как Product, Customer и т. Д., Имеет 2 дополнительных поля: «LockedBy (int)» и «LockedAt (datetime)».

LockedBy содержит идентификатор пользователя, который заблокировал объект, иlockedAt содержит метку времени, в которую он был заблокирован.

Итак, когда пользователь хочет начать редактирование объекта, код проходит этот процесс:

Получить объект из БД, '1'будучи ProductID

Product p = new Product(1);

Заблокировать сущность для текущего пользователя, вошедшего в систему

entity.Lock();

Сохранить / зафиксировать сущность в базе данных, Save () вызывает LockCheck (), которая возвращает true, еслизарегистрированный пользователь имеет разрешение на сохранение объекта.

entity.Save();

Пользователь имеет право сохранить сущность, если:

 (LockedBy < 0 || LockedBy == LoggedInUser.UserID || LockedAt < DateTime.Now.AddMinutes(-30))

Примечание. Пользователи могут редактировать сущности, которые были заблокированы более 30 минут назад.Если у другого пользователя сущность открыта (на экране редактирования), то каждые 15 минут она будет всплывать и спрашивать, остается ли пользователь там, если это так, она делает запрос, который увеличивает LockedAt до Now (как скользящая блокировка)

На данный момент никакой другой пользователь не может редактировать эту сущность!

Код / пользователь может свободно редактировать эту сущность столько, сколько пожелает, и быть уверенным, что она не изменилась за ее спиной :)

Как только пользователь прекратил редактировать кодовые вызовы:

entity.Unlock()

затем

entity.Save()

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

...