Статьи

Модуль автоматического масштабирования для приложений PHP в Windows Azure

Одним из основных ценностных предложений Windows Azure является возможность иметь автоматическую эластичную масштабируемость для ваших приложений (т. Е. Автоматически увеличивать или уменьшать количество экземпляров, на которых ваше приложение работает, на основе некоторых критериев). В этой статье я познакомлю вас с настраиваемым модулем PHP, который автоматически масштабирует приложение на основе счетчиков производительности. Исходный код модуля доступен на GitHub здесь: https://github.com/brian-swan/PHP-Auto-Scaler .

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

Примечание . Большая часть кода в этом модуле основана на серии из 4 частей по масштабированию приложений PHP, которая начинается здесь: Масштабирование приложений PHP в Windows Azure, часть 1 . Я рекомендую прочитать эту серию, если вы хотите заполнить некоторые детали масштабирования, которые я здесь опускаю.

обзор

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

  1. Вы развертываете свое приложение в Windows Azure с включенной диагностикой Windows Azure и модулем автоматического масштабирования, работающим в рабочей роли. (Дополнительные сведения о диагностике см. В разделе Как получить диагностическую информацию для приложений Azure / PHP — часть 1 и Как получить диагностическую информацию для приложений Azure / PHP — часть 2. )
  2. Диагностический монитор Windows Azure регулярно записывает диагностические данные (такие как загрузка ЦП, доступная память и т. Д.) В вашу учетную запись хранения ( точнее, в хранилище таблиц ).
  3. Рабочая роль периодически считывает данные из вашей учетной записи хранения и сокращает числа. Модуль включает в себя некоторую логику «хруста» по умолчанию (подробности ниже), но вы, несомненно, захотите настроить эту логику. (Дополнительные сведения о рабочих ролях см. В разделе « Поддержка рабочих ролей» в Windows Azure SDK для PHP .)
  4. Исходя из сокращения числа, роль «Рабочий» использует API-интерфейс управления Windows Azure для увеличения или уменьшения (или оставления того же) числа экземпляров, на которых выполняется ваше приложение.
  5. Шаги 2-4 автоматически повторяются.

образ

Шаг за шагом

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

1. Предпосылки

Чтобы использовать модуль масштабирования, вам нужно сначала позаботиться о нескольких вещах:

  1. Создайте подписку Windows Azure . Запишите свой идентификатор подписки.
  2. Создайте учетную запись хранения . Запишите имя своей учетной записи хранения и закрытый ключ.
  3. Создать размещенный сервис . Запишите префикс URL для вашей службы.
  4. Создайте свое PHP-приложение.

2. Настройте модуль масштабирования

В файле storageConfig.php модуля масштабирования вам необходимо определить несколько констант:

    define ('SUBSCRIPTION_ID', 'your subscription id');
    define("STORAGE_ACCOUNT_NAME", "your_storage_account_name");
    define("STORAGE_ACCOUNT_KEY", "your_storage_account_key");
    define('DNS_PREFIX', 'the dns prefix for your hosted service');
    define("PROD_SITE", true);
    define("EXCEPTION_TABLE", "ExceptionEntry");
    define("STATUS_TABLE", "StatusTable");
    define('ROLE_NAME', 'your web role name');
    define('DEPLOYMENT_SLOT', 'production or staging');
    define('MIN_INSTANCES', 2); 
    define('MAX_INSTANCES', 20);
    define ('AVERAGE_INTERVAL', "-15 minutes");
    define('COLLECTION_FREQUENCY', 60); // in seconds
    $certificate = 'your_cert_name.pem';
  • SUBSCRIPTION_ID, STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY и DNS_PREFIX должны исходить из ваших заметок на шаге 1.
  • PROD_SITE должен быть установлен в true, если ваше приложение будет работать в облаке. Если вы тестируете приложение локально, оно должно быть установлено в false .
  • EXCEPTION_TABLE и STATUS_TABLE — это имена таблиц в вашей учетной записи хранения, в которые будут записываться данные. Не меняйте их.
  • ROLE_NAME — это название вашей веб-роли. (Подробнее об этом позже.)
  • DEPLOYMENT_SLOT — это производственная или промежуточная версия, в зависимости от того, развертываетесь ли вы в промежуточную или производственную ячейку размещенной службы.
  • MIN_INSTANCES и MAX_INSTANCES — это минимальное и максимальное количество экземпляров, на которых вы хотите, чтобы ваше приложение работало.
  • AVERAGE_INTERVAL — это период, за который вы хотите усреднить счетчики производительности. Значение по умолчанию составляет 15 минут, поэтому, когда модуль считывает данные из вашей учетной записи хранения, он просматривает и усредняет данные за 15 минут.
  • COLLECTION_FREQUENCY определяет, как часто модуль собирает данные о производительности из вашей учетной записи хранения. По умолчанию это 60 секунд.
  • $ Certificate — это имя вашего сертификата .pem , которое необходимо при использовании API управления Windows Azure. Ваш сертификат должен быть включен в корневой каталог вашей рабочей роли. Вы можете узнать больше о том, что вам нужно сделать, в разделе « Создание и выгрузка сертификата API управления службами» этого руководства: Обзор развертывания и управления командной строкой с помощью Windows Azure SDK для PHP .

3. Настройте логику масштабирования

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

Функция get_metrics запрашивает вашу учетную запись хранения для записей, возвращающихся во времени за 15 минут (по умолчанию), и усредняет каждый из счетчиков производительности, которые вы просматриваете (настроено в файле Diagnics.wadcfg вашей веб-роли):

    function get_metrics($deployment_id, $ago = "-15 minutes") {    
        $table = new Microsoft_WindowsAzure_Storage_Table('table.core.windows.net', STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_KEY);     
        
        // get DateTime.Ticks in past 
        $ago = str_to_ticks($ago); 
        
        // build query 
        $filter = "PartitionKey gt '0$ago' and DeploymentId eq '$deployment_id'"; 
     
        // run query 
        $metrics = $table->retrieveEntities('WADPerformanceCountersTable', $filter);     
        
        $arr = array();    
        foreach ($metrics AS $m) {
            // Global totals 
            $arr['totals'][$m->countername]['count'] = (!isset($arr['totals'][$m->countername]['count'])) ? 1 : $arr['totals'][$m->countername]['count'] + 1;        
            $arr['totals'][$m->countername]['total'] = (!isset($arr['totals'][$m->countername]['total'])) ? $m->countervalue : $arr['totals'][$m->countername]['total'] + $m->countervalue;        
            $arr['totals'][$m->countername]['average'] = (!isset($arr['totals'][$m->countername]['average'])) ? $m->countervalue : $arr['totals'][$m->countername]['total'] / $arr['totals'][$m->countername]['count'];         
            
            // Totals by instance 
            $arr[$m->roleinstance][$m->countername]['count'] = (!isset($arr[$m->roleinstance][$m->countername]['count'])) ? 1 : $arr[$m->roleinstance][$m->countername]['count'] + 1;        
            $arr[$m->roleinstance][$m->countername]['total'] = (!isset($arr[$m->roleinstance][$m->countername]['total'])) ? $m->countervalue : $arr[$m->roleinstance][$m->countername]['total'] + $m->countervalue;        
            $arr[$m->roleinstance][$m->countername]['average'] = (!isset($arr[$m->roleinstance][$m->countername]['average'])) ? $m->countervalue : ($arr[$m->roleinstance][$m->countername]['total'] / $arr[$m->roleinstance][$m->countername]['count']);    
        }    
        return $arr;
    }

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

Функция scale_check по существу берет выходные данные функции get_metrics и возвращает 1, 0 или –1 в зависимости от того, нужно ли добавить экземпляр, счетчик экземпляров не требует корректировки или экземпляр должен быть вычтен. Логика, используемая для определения этого, является упрощенной (как вы можете видеть в функции). Возможно, вы захотите настроить логику в соответствии с вашим приложением. (Обратите внимание, что по умолчанию логика масштабирования основана на 3 счетчиках производительности: процент использования ЦП, доступная память и количество соединений TCPv4.)

    function scale_check($metrics) {
        $percent_proc_usage = (isset($metrics['totals']['\Processor(_Total)\% Processor Time']['average'])) ? $metrics['totals']['\Processor(_Total)\% Processor Time']['average'] : null;
        $available_MB_memory = (isset($metrics['totals']['\Memory\Available Mbytes']['average'])) ? $metrics['totals']['\Memory\Available Mbytes']['average'] : null;
        $number_TCPv4_connections = (isset($metrics['totals']['\TCPv4\Connections Established']['average'])) ? $metrics['totals']['\TCPv4\Connections Established']['average'] : null;
        
        if(!is_null($percent_proc_usage)) {
            if( $percent_proc_usage > 75 )
                return 1;
            else if( $percent_proc_usage < 25)
                return -1;
        }
     
        if(!is_null($available_MB_memory)) {
            if( $available_MB_memory < 25 )
                return 1;
            else if( $available_MB_memory > 1000)
                return -1;
        }
        
        if(!is_null($number_TCPv4_connections)) {
            if( $number_TCPv4_connections > 120 )
                return 1;
            else if( $number_TCPv4_connections < 20)
                return -1;
        }
        
        return 0;
    }

4. Упакуйте и разверните ваше приложение

Теперь вы готовы упаковать и развернуть свое приложение. Инструкции по этому вопросу содержатся в этом сообщении в блоге: Поддержка рабочих ролей в Windows Azure SDK для PHP . Однако есть пара вещей, которые вам нужно знать, но они не включены в этот пост:

  • Когда вы запускаете скаффолер по умолчанию и задаете имя для своей веб-роли, это имя будет значением константы ROLE_NAME на шаге 2 выше. т.е. когда вы запускаете эту команду …
scaffolder run -out="c:\path\to\output\directory" -web="WebRoleName" -workers="WorkerRoleName"

WebRoleName будет значением ROLE_NAME .

  • После запуска скаффолдера по умолчанию и добавления исходного кода приложения в каталог веб-роли необходимо настроить диагностику Windows Azure. Инструкции для этого приведены здесь: Как получить диагностическую информацию для приложений Azure / PHP — часть 1 . Как показано в этом посте, диагностической информацией, на которую опирается модуль автоматического масштабирования (по умолчанию), являются три счетчика производительности: загрузка ЦП, доступная память и соединения TCPv4. Вы можете собирать различную диагностическую информацию, но чтобы использовать ее для принятия решений о масштабировании, вам придется настроить логику масштабирования в модуле масштабирования (см. Шаг 3 выше).
  • В каталоге рабочих ролей откройте файл run.bat и измените его содержимое на php scale_module.php . Это говорит рабочей роли запускать scale_module.php при запуске.
  • Вам нужно будет включить библиотеку Windows Azure SDK для PHP с вашей рабочей ролью.

Основной цикл

Сложив, основной цикл (в файле scale_module.php ) выглядит так

    while(1) {
        
        //Calls to management API here
        //based on metrics.
            
        sleep(COLLECTION_FREQUENCY); 
    }

По сути, он многократно вызывает get_metrics и scale_check и вызывает API-интерфейс управления (на основе возвращаемого значения scale_check ) для увеличения или уменьшения количества экземпляров. Чтобы избежать этого слишком часто, в каждом цикле он останавливается на COLLECTION_FREQUENCY секунд.

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

    while($ready_count != $instance_count) {
        $ready_count = 0;
        foreach($deployment->roleinstancelist as $instance) {
            if ($instance['rolename'] == ROLE_NAME && $instance['instancestatus'] == 'Ready')
                $ready_count++;
        }
        sleep(10); // Avoid being too chatty.
        $scale_status = new ScaleStatus();
        $scale_status ->statusmessage = "Checking instances. Ready count = " . $ready_count . ". Instance count = " . $instance_count;
        $scale_status ->send();
    }

Я не буду публиковать остаток основного цикла здесь (вы можете увидеть его на GitHub здесь: https://github.com/brian-swan/PHP-Auto-Scaler/blob/master/scale_module.php ), но я укажу две вещи о коде, как сейчас:

  1. Вы увидите несколько вызовов, которые пишут в таблицу с именем ScaleStatus (как в приведенном выше фрагменте). Это там, чтобы я мог видеть (в таблице), что делал мой модуль масштабирования. Я думаю, что эти звонки могут быть удалены в будущем.
  2. Вы увидите попробуйте … поймать блоки вокруг моего кода. В некоторых случаях я обнаружил, что при возникновении тайм-аута было сгенерировано исключение. Эта информация в настоящее время записывается в хранилище таблиц. Очевидно, что это должно быть улучшено.

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