Поделиться через


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

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

Служба хранилища Azure предлагает два варианта для геоизбыточной репликации данных: геоизбыточное хранилище (GRS) и хранилище, избыточное между зонами (GZRS). Чтобы использовать параметры геоизбыточного хранилища Azure, убедитесь, что учетная запись хранения настроена для геоизбыточного хранилища (RA-GRS) или геоизбыточного хранилища (RA-GZRS). Если это не так, вы можете узнать больше об изменении типа репликации учетной записи хранения.

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

Рекомендации по проектированию приложений

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

Имейте в виду эти ключевые аспекты при разработке приложения для обеспечения доступности и устойчивости с помощью RA-GRS или RA-GZRS:

  • Копия данных, храняемых только для чтения в основном регионе, асинхронно реплицируется в дополнительном регионе. Эта асинхронная репликация означает, что копия только для чтения в дополнительном регионе в конечном итоге согласована с данными в основном регионе. Служба хранилища определяет расположение дополнительного региона.

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

  • Если основной регион становится недоступным, можно инициировать отработку отказа учетной записи. Когда вы переключаетесь на вторичный регион, записи DNS, указывающие на основной регион, изменяются так, чтобы указывать на вторичный регион. После завершения переключения доступа на резерв, доступ на запись для счетов GRS и RA-GRS восстанавливается. Дополнительные сведения см. в статье Аварийное восстановление и отработка отказа учетной записи хранения.

Работа с согласованными данными

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

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

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

Обработка услуг отдельно или все вместе

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

Например, если в приложении используются очереди и большие двоичные объекты, вы можете поместить отдельный код для обработки повторных ошибок для каждой службы. Таким образом, ошибка службы BLOB-объектов будет влиять только на часть приложения, которая работает с большими двоичными объектами, оставляя очереди продолжать работать как обычно. Однако если вы решите обработать все повторные попытки службы хранилища, запросы к службам BLOB-объектов и очередей будут затронуты, если любая служба возвращает повторную ошибку.

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

Запуск вашего приложения в режиме только для чтения

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

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

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

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

Обработка обновлений в режиме только для чтения

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

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

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

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

Обработка повторных попыток

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

Чтение запросов

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

В этом примере обработка повторных попыток для хранилища BLOB-объектов настраивается в BlobClientOptions классе и будет применяться к объекту BlobServiceClient , который мы создадим с помощью этих параметров конфигурации. Эта конфигурация является основным и вторичным подходом, при котором повторные попытки чтения из основного региона перенаправляются в дополнительный регион. Этот подход лучше всего подходит, если ошибки в основном регионе, как ожидается, будут временными.

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
    Retry = {
        // The delay between retry attempts for a fixed approach or the delay
        // on which to base calculations for a backoff-based approach
        Delay = TimeSpan.FromSeconds(2),

        // The maximum number of retry attempts before giving up
        MaxRetries = 5,

        // The approach to use for calculating retry delays
        Mode = RetryMode.Exponential,

        // The maximum permissible delay between retry attempts
        MaxDelay = TimeSpan.FromSeconds(10)
    },

    // If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for 
    // GET or HEAD requests during retries.
    // If the status of the response from the secondary Uri is a 404, then subsequent retries
    // for the request will not use the secondary Uri again, as this indicates that the resource 
    // may not have propagated there yet.
    // Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
    GeoRedundantSecondaryUri = secondaryAccountUri
};

// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

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

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

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

Запросы на обновление

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

Паттерн Circuit Breaker также может быть применён к запросам на обновление. Для обработки ошибок запроса на обновление можно задать пороговое значение в коде, например 10 последовательных сбоев, и отслеживать количество сбоев запросов в основной регион. После выполнения порогового значения можно переключить приложение на режим только для чтения, чтобы запросы на обновление основного региона больше не выдавали.

Реализация шаблона разбиения цепи

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

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

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

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

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

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

Обработка данных с окончательной согласованностью

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

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

Время Транзакция Репликация время последней синхронизации Результат
T0 Транзакция A:
Вставить сотрудника
сущность в основном
Транзакция A вставлена в основную.
ещё не реплицировано.
Т1 Транзакция A
воспроизведено в
вторичный
Т1 Транзакция A была воспроизведена на вторичную.
Время последней синхронизации обновлено.
T2 Транзакция B:
Обновление
субъект трудовых отношений
в начальной школе
Т1 Транзакция B записана на основной.
ещё не реплицировано.
T3 Транзакция C:
Обновление
администратор
ролевой объект в
основной
Т1 Транзакция C записана в основной блок.
ещё не реплицировано.
T4 Транзакция C
воспроизведено в
вторичный
Т1 Транзакция C реплицирована на резервный.
Время последней синхронизации не обновлено, потому что
транзакция B еще не реплицирована.
T5 Считать сущности
из вторичной
Т1 Вы получаете устаревшее значение для сотрудника
единица, потому что транзакция B не завершена
реплицировано еще. Вы получаете новое значение для
роль администратора entity, поскольку у C есть
воссоздано. Время последней синхронизации все еще не пришло
"были обновлены из-за транзакции B"
не воспроизведено Вы можете сказать, что
Сущность роли администратора несовместима
Поскольку дата и время сущности истекает
Время последней синхронизации.
T6 Сделка B
воспроизведено в
вторичный
T6 T6 – Все транзакции через C имеют
была репликация, Время последней синхронизации
обновлено.

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

Чтобы определить, имеет ли учетная запись хранения потенциально несогласованные данные, клиент может проверить значение свойства Last Sync Time . Время последней синхронизации указывает время, когда данные в дополнительном регионе были в последний раз согласованы, и когда служба применила все транзакции до этого момента во времени. В приведенном выше примере, после того как служба вставляет сущность сотрудника в дополнительный регион, время последней синхронизации устанавливается на T1. Она остается в T1 до тех пор, пока служба не обновляет сущность сотрудника в дополнительном регионе, когда она установлена на T6. Если клиент получает время последней синхронизации, когда он считывает сущность в T5, он может сравнить его с временной меткой на сущности. Если метка времени для сущности позже последнего времени синхронизации, сущность находится в потенциально несогласованном состоянии, и вы можете выполнить соответствующее действие. Использование этого поля требует знания о том, когда было завершено последнее обновление основного.

Сведения о том, как проверить время последней синхронизации, см. в разделе "Проверка свойства времени последней синхронизации" для учетной записи хранения.

Тестирование

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

Одним из вариантов является использование Fiddler для перехвата и изменения ответов HTTP в скрипте. Этот скрипт может определить ответы, поступающие из основной конечной точки, и изменить код состояния HTTP на тот, который клиентская библиотека хранилища распознает как повторную ошибку. Этот фрагмент кода демонстрирует простой пример скрипта Fiddler, который перехватывает ответы на запросы на чтение к таблице employeedata, чтобы возвращать статус 502.

static function OnBeforeResponse(oSession: Session) {
    ...
    if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
      && (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
        oSession.responseCode = 502;
    }
}

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

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


Дальнейшие действия

Для получения полного примера, показывающего, как переключаться между основными и второстепенными конечными точками, смотрите Примеры Azure – Использование шаблона автоматического выключателя с хранилищем RA-GRS.