2009-11-19 2 views
2

Пусть у меня есть таблица в Azure Table Storageданных Azure Table Storage Консистенция

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

    public double Amount {get; set;} 
} 

И сообщение в Azure Queue, который говорит Добавить 10 до Сумма.

теперь говорят, один работник роль

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

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

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

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

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

ответ

1

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

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

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

+0

Похоже, что это хорошая история для поиска событий; вы не хотели бы, чтобы отложенные сообщения следовали в неправильном порядке, не так ли? – Henrik

2

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

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

0

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

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

Afaik, можно сказать, что« столы »в окнах лазури - это что-то вроде googles bigtable, не так ли?

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

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

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

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