Постановка Windows Azure <->, вызывающая конфликты и ошибки в табличном хранилище - PullRequest
0 голосов
/ 23 февраля 2012

У нас вчера была ужасная проблема / опыт, когда мы пытались поменять нашу постановочную <-> производственную роль.

Вот наша установка:

У нас есть рабочая роль, собирающая сообщения из очереди. Эти сообщения обрабатываются на роль. (Таблица хранения вставок, дБ выбирает и т. Д.). Это может занять от 1 до 3 секунд на сообщение в очереди, в зависимости от того, сколько сообщений в хранилище таблицы ему нужно сделать. Он удалит сообщение, когда все будет закончено.

Проблема при обмене:

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

Когда роль хотела обработать сообщение очереди, она выдавала постоянный поток ошибок ' EntityAlreadyExists '. Из-за этих ошибок сообщения очереди не удалялись. Это привело к тому, что сообщения очереди помещались обратно в очередь и возвращались к обработке и т. Д. ...

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

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

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

Возможные проблемы?

Мы почти не знали, что произошло на самом деле.

  • Может быть, обе роли получили одни и те же сообщения, и одна из них отправила сообщение, а другая допустила ошибку?
  • ... ???

Возможное решение (я)?

У нас есть идея, как решить эту «проблему».

  • Сделать ядовитое сообщение сбой системы? Когда счетчик очереди превысит X, мы должны просто удалить это сообщение очереди или поместить его в отдельную «ядовитую очередь».
  • Перехватите ошибку EntityAlreadyExists и просто удалите это сообщение очереди или поместите его в отдельную очередь.
  • ... ????

Несколько ролей

Полагаю, у нас будет одна и та же проблема при назначении нескольких ролей?

Большое спасибо.

РЕДАКТИРОВАТЬ 24/02/2012 - Дополнительная информация

  • На самом деле мы используем GetMessage ()
  • Каждый элемент в очереди уникален и генерирует уникальные сообщения в таблице Storage. Немного больше информации о процессе: пользователь что-то публикует и должен будет распространяться среди других пользователей. Сообщение, генерируемое этим пользователем, будет иметь уникальный идентификатор (guid). Это сообщение будет помещено в очередь и занято рабочей ролью. Сообщение распространяется по нескольким другим таблицам (partitionkey -> UserId, rowkey -> некоторая временная метка в тиках и уникальный идентификатор сообщения. Таким образом, почти нет шансов, что те же сообщения будут опубликованы в обычной ситуации.
  • Тайм-аут невидимости МОЖЕТ быть логическим объяснением , потому что некоторые сообщения могут быть распределены по 10-20 таблицам. Это означает 10-20 вставок без пакетной опции. Можете ли вы установить или расширить это время невидимости out?
  • Не удалять сообщение очереди из-за исключительной ситуации COULD также может быть объяснением, поскольку мы не реализовали ни одного вредоносного сообщения при сбое по YET;).

Ответы [ 5 ]

2 голосов
/ 23 февраля 2012

Независимо от проблемы Staging vs. Production, наличие механизма, который обрабатывает сообщения о ядах, является критически важным. Мы реализовали слой абстракции над очередями Azure, который автоматически перемещает сообщения в очередь с ошибками, если их пытались обрабатывать некоторое настраиваемое количество раз.

1 голос
/ 26 марта 2012

У вас явно есть ошибка при обработке двойных сообщений. Тот факт, что ваш идентификатор уникален, не означает, что сообщение не будет обработано дважды в некоторых случаях, таких как:

  1. Роль умирает и с частично законченной работой, поэтому сообщение вновь появится для обработки в очереди
  2. Сбой роли неожиданный, поэтому сообщение снова попадает в очередь
  3. Миграция FC перемещает вашу роль, и у вас нет кода для обработки этой ситуации, поэтому сообщение возвращается в очередь

Во всех случаях вам нужен код, который обрабатывает факт повторного появления сообщения. Один из способов - использовать свойство DequeueCount и проверить, сколько раз сообщение было удалено из очереди и получено для обработки. Убедитесь, что у вас есть код, который обрабатывает частичную обработку сообщения.

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

1 голос
/ 24 февраля 2012

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

Как и предполагали другие, причины могут быть

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

Не глядя на код, я предполагаю, что это либо опция 3, либо 4.

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

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

Добавлены 2/24

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

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

Итак, суть в том, чтобы быть идемпотентом. Вы можете попробовать использовать функцию сохранения (обновления или вставки) хранилища таблиц, чтобы избежать появления ошибки «EntitiyAlreadyExists», если это работает для вашего кода. Если все, что вы делаете, это вставляете новые сущности в хранилище таблиц Azure, тогда upsert должен решить вашу проблему с минимальным изменением кода.

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

1 голос
/ 24 февраля 2012

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

var queueMessage = GetNextMessageFromQueue();    

Foo myFoo = GetFooFromTableStorage(queueMessage.FooId);

if (myFoo == null)
{
    myFoo = new Foo {
                        PartitionKey = queueMessage.FooId
                    };

    AddFooToTableStorage(myFoo);
}

DeleteMessageFromQueue(queueMessage);

Если у вас есть два соседних сообщения в очереди с одинаковым FooId, вполне вероятно, что в итоге вы оба раза будете проверять, существует ли Foo, не находя его и пытаясь создать Это. Какой бы экземпляр ни пытался сохранить в последний раз, появится сообщение об ошибке «Объект уже существует». Из-за ошибки он никогда не попадает в часть кода удаления сообщения и, следовательно, становится видимым в очереди через некоторое время.

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

Обновление 27/02 Если это не последующие сообщения (которые основаны на вашей схеме ключей раздела / строки, я бы сказал, что это маловероятно), то моя следующая ставка будет состоять в том, что это то же самое сообщение, которое появится в очереди после истечения времени ожидания видимости. По умолчанию, если вы используете .GetMessage () , время ожидания составляет 30 секунд. Он имеет перегрузка , которая позволяет вам указать, как долго этот период времени. Существует также функция .UpdateMessage () , которая позволяет обновлять этот тайм-аут по мере обработки сообщения. Например, вы можете установить начальную видимость на 1 минуту, затем, если вы продолжаете обрабатывать сообщение через 50 секунд, увеличьте его еще на одну минуту.

1 голос
/ 24 февраля 2012

Есть несколько возможных причин:

Как вы читаете сообщения в очереди?Если вы делаете Peek Message, то сообщение все еще будет видимым, чтобы быть захваченным другим экземпляром роли (или вашей промежуточной средой), прежде чем сообщение будет удалено.Вы хотите убедиться, что используете Get Message, чтобы сообщение было невидимым до тех пор, пока его нельзя удалить.

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

Эта проблема почти наверняка не имеет ничего общего с Staging vs Production, но, скорее всего, она вызвана чтением нескольких экземпляров изта же очередьВероятно, вы можете воспроизвести ту же проблему, указав 2 экземпляра, или развернув один и тот же код в двух разных производственных службах, или запустив код локально на своем компьютере разработчика (все еще указывая на хранилище Azure), используя 2 экземпляра.

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

...