Follow Me Widget

понедельник, 9 апреля 2012 г.

Повышение отказоустойчивости облачных приложений при помощи Transient Fault Handling Block.

Привет всем ! Сегодня речь пойдет об отказоустойчивости облачных приложений. В принципе механизм, который будет рассматриваться в сегодняшней публикации, не новый. Мы все его прекрасно знаем – это обработка временных сбоев программы при помощи Retry Logic. Данная техника славится своей простотой и высокой надежностью.

В процессе написания облачного приложения, программист сталкивается с большим количеством программных сбоев, особое место среди которых занимают так называемые временные сбои. Это могут быть как проблемы с сетевой коммуникацией, так и проблемы связанные с определенными ограничениями используемого сервиса. Вероятность появления такого рода ошибок в облаке возрастает в разы, так как каждый сервис, предоставляемый платформой, содержит ряд ограничений. Например, в Azure Caching сервисе присутствует целый ряд ограничений, начиная от количества транзакций в час и заканчивая максимально допустимым количеством одновременных соединений (http://msdn.microsoft.com/en-us/library/windowsazure/hh697522.aspx#C_BKMK_FAQ8). Если ваше приложений превысит установленную квоту – сработает так называемый механизм тротлинга (throttling). При этом в приложении выскочит исключение, что естественно не порадует конечного пользователя. Как правило подобного рода сбои носят временный характер и если повторить операцию через определенный промежуток времени – она завершится успешно. Учитывая тот факт, что все облачные сервисы содержат ряд квот – данная проблема становится очень актуальной и важной.
Именно для решения подобного вида проблем командой Microsoft Patterns&Practices был разработан модуль библиотеки Enterprise Library, именуемый Thransient Fault Handling Application Block. Этот блок повышает отказоустойчивость вашего приложения путем предоставления механизмов для обработки временных сбоев. Блок доступен через NuGet, подключить его к вашему проекту можно при помощи следующей команды:

Install-Package EnterpriseLibrary.WindowsAzure.TransientFaultHandling

Блок оперирует таким понятием как стратегия. Стратегия позволяет блоку, во-первых, определить действительно ли сбой связан с временной проблемой, а во-вторых, предоставляет наилучший способ решения этой проблемы. На сегодняшний день вместе с блоком поставляются 4 стратегии для 4-х облачных сервисов:
  • SQL Azure
  • Windows Azure Service Bus
  • Windows Azure Storage Service
  • Windows Azure Caching Service
Способ решения временных сбоев у блока один – это повторное выполнение операции. Он позволяет настроить интервал времени, по прошествии которого операция будет повторно выполнена. По умолчанию поддерживаются 3 варианта формирования временного отрезка:
Transient Fault Handling Application Block
Кроме того блок позволяет настроить собственную политику формирования временных интервалов, а также механизмы определения временных сбоев, что предоставляет нам прекрасные возможности по расширению этого полезного модуля Enterprise Library.
Познакомившись с предназначением блока и с принципами его функционирования, давайте посмотрим как программно можно его использовать для повышения отказоустойчивости приложений, использующих SQL Azure.
 SQL Azure, как и многие другие, сервисы Windows Azure содержит ряд ограничений и квот, нарушение которых будет вести к "падениям" ваших приложений. Немного поискав в Интернете список ограничений SQL Azure я наткнулся на следующую табличку:


Throttling type

Soft Throttling limit exceeded

Hard Throttling limit exceeded

Temporary disk space problem occurred

0x01

0x02

Temporary log space problem occurred

0x04

0x08

High-volume transaction/write/update activity exists

0x10

0x20

High-volume database input/output (I/O) activity exists

0x40

0x80

High-volume CPU activity exists

0x100

0x200

Database quota exceeded

0x400

0x800

Too many concurrent requests occurred

0x4000

0x8000

То есть, например, если наше приложение открыло “тяжелый” курсор на сервере и он стал “пожирать” процессорное время – мы получим в приложении ошибку с кодом 0х100 (на самом деле код ошибки будем немного другим, но нас сейчас это не сильно интересует), на которую необходимо как-то реагировать. Первый и самый простой вариант – это попробовать заново выполнить неудачную операцию. И сделаем мы это при помощи Transient Fault Handling Application Block. Блок содержит в себе механизмы, применимые как к чистому ADO.NET так и к Entity Framework. Вот пример, как изменить программный код с целью добавления логики повторного выполнения неудачной операции:
RetryPolicy retryPolicy = new RetryPolicy‹SqlAzureTransientErrorDetectionStrategy›(3, TimeSpan.FromSeconds(30));
using (ReliableSqlConnection connection = new ReliableSqlConnection(connectionString, retryPolicy, retryPolicy))
{
    try
    {
        connection.Open();
        using (var command = connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM Employees";
            using (var rdr = cnn.ExecuteCommand‹IDataReader›(cmd))
            {
                //
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message.ToString());
    }
}
Как мы видим необходимо лишь задать политику и изменить стандартный класс SQLConnection на ReliableSqlConnection. В данном случае наша политика гласит: “Использовать стратегию определения временных падений SQL Azure. В случае неудачной операции – попробовать выполнить ее снова. Количество попыток равно 3. Интервал между попытками равен 30 секундам. В случае, если ничего не получится – передать исключение внешнему коду”. Похожим образом можно добавить логику повторных операций для приложений, использующих Entity Framework в качестве слоя для доступа к данным:
using (NorthwindEntities dc = new NorthwindEntities())
{
    RetryPolicy myPolicy = new RetryPolicy‹SqlAzureTransientErrorDetectionStrategy›(3);
    Employee e1 = myPolicy.ExecuteAction‹Employee›(() =>
        (from x in dc.Employees
            where x.LastName == "King"
            select x).First());
}
В данном случае мы снова создаем политику (логика работы такая же как и в предыдущем случае, так как 30-секундный интервал используется блоком по умолчанию). Но сам код немного изменился по сравнению с предыдущим случаем. Процесс создания контекста не изменился, изменился способ выполнения запроса. Он оборачивается методом политики ExecuteAction, принимающий в качестве параметра Action. Если запрос по каким-то причинам не выполнится, инфраструктура блока попробует запустить его заново по прошествии 30 секунд.
Как видим техника использования Transient Fault Handling Application Block довольно таки проста и понятна. Поэтому если в приложении вы используете вышеперечисленные Azure-сервисы (Storage, Service Bus, Caching, SQL Azure), не задумываясь прикручивайте retry-логику к нему – это сделает ваше приложение более отказоустойчивым, а ваши ночи более спокойными :)
Спасибо за внимание ! Надеюсь этот пост был для вас полезным.

Несколько ссылок для более глубокого знакомства с Transient Fault Handling Application Block:

Комментариев нет: