Согласованность данных хранилища таблиц Azure

Допустим, у меня есть таблица в хранилище таблиц Azure.

public class MyTable
{
  public string PK {get; set;}
  public string RowPK {get; set;}

  public double Amount {get; set;}
}

И сообщение в очереди Azure с текстом Добавить 10 к сумме.

Теперь допустим одна рабочая роль

  1. Берет это сообщение из очереди
  2. Берет строку из таблицы
  3. Сумма += 10
  4. Обновляет строку в таблице
  5. И терпит неудачу

Через некоторое время сообщение снова доступно в очереди. Итак, следующая рабочая роль:

  1. Берет это сообщение из очереди
  2. Берет строку из таблицы
  3. Сумма += 10
  4. Обновляет строку в таблице
  5. Удаляет сообщение из очереди

Эти действия приводят к Amount += 20 вместо Amount += 10.

Как мне избежать таких ситуаций?


person SeeR    schedule 19.11.2009    source источник


Ответы (4)


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

Таким образом, вторая рабочая роль, которая пытается обновить строку, сначала проверит, что текущее значение по-прежнему равно «предыдущему значению». Если нет, рабочая роль знает, что что-то пошло не так, и может, например, просто отменить сообщение, не выполняя обновление. И, возможно, также поднять ошибку в каком-то журнале.

person FrenchData    schedule 11.12.2009

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

Поэтому вместо суммы += 10 в качестве задачи сделайте что-то вроде суммы = 300. Получите текущую сумму в веб-ролике, добавьте к ней 10 и поместите новую сумму в очередь.

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

person Korenaga    schedule 24.11.2009
comment
Кажется, это хорошая история для поиска источников событий; вы бы не хотели, чтобы отложенные сообщения следовали в неправильном порядке, не так ли? - person Henrik; 15.11.2010

вы реализовали это или строки кода там всего лишь несколько мыслей?

«сумма» подразумевает, что вы думаете о каком-то сценарии банковской транзакции. Вероятно, было бы лучше работать напрямую с SQL Azure (поскольку у вас есть гарантии ACID: http://blogs.msdn.com/ssds/archive/2009/03/12/9471765.aspx «Мы всегда поддерживали все возможности ACID в службе и будем продолжать это делать». )

Афаик, можно сказать, что «таблицы» в Windows Azure — это что-то вроде googles bigtable, не так ли?

person dayscott    schedule 09.04.2010

  1. Иметь уникальный MessageId для вашего сообщения в очереди.
  2. Рабочая роль читает сообщение из очереди, читает сущность из таблицы
  3. Обновляет поле Сумма
  4. Выполняет пакетную операцию и вставляет 2 строки обратно в таблицу. Первый — это обновленный объект, объединенный обратно в таблицу, а второй — объект, вставленный с тем же ключом раздела и идентификатором сообщения, что и ключ строки.

Пакетная операция будет выполняться атомарно.

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

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

person Dogu Arslan    schedule 07.02.2016