Применение PHP в облачных вычислениях: Часть 3. Работа с Amazon SQS посредством Zend Framework

Использование простых очередей сообщений с помощью Zend Framework

Среда Zend Framework содержит несколько классов, которые облегчают использование служб на базе облака. Первая часть настоящего цикла статей Облачные вычисления с помощью PHP посвящена использованию классов Zend для облачной службы хранения данных Amazon S3. Во второй части рассматриваются классы Zend, которые облегчают работу с виртуальными машинами в системе Amazon Elastic Compute Cloud (EC2). Настоящая статья посвящена классам Zend для работы со службой простых очередей Amazon (Simple Queue Service – SQS).

Даг Тидуэл (Doug Tidwell), XML Evangelist, IBM

Дуг Тидуэлл (Doug Tidwell) работает старшим инженером-программистом в группе новых технологий IBM (IBM Emerging Technology). Он выступал на первой конференции по XML в 1997 году и уже много лет занимается языками разметки, Web-сервисами и технологией SOA (технология, на которой основаны облачные вычисления). Его доклады были представлены на десятках конференций по всему миру, а его презентация на конференции JavaOne по облачным вычислениям принесла ему в 2009 году приз Rock Star. Свою задачу как популяризатора видит в разъяснении стандартов и технологий, стоящих за "облачными вычислениями", и в оказании помощи по их интеграции в общую архитектуру предприятия и его стратегию. Является автором многих статей, опубликованных на developerWorks, и книги по XSLT, выпущенной издательством O'Reilly, экземпляры которой служат хорошим подарком на все случаи жизни. Живет со своей женой, дочерью и собакой в Чэпел-Хилле (Chapel Hill), штат Северная Каролина.


developerWorks Contributing author
        level

25.02.2011

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

Начало работы

Из этой статьи вы узнаете, как решать несколько важных задач, связанных с Simple Queue Service. Как и во всех статьях этого цикла, вы получите максимальную пользу от примеров, если перед началом работы установите среду Zend Framework. Если она у вас не установлена, загрузите и установите полный пакет с сайта Zend.com (см. раздел Ресурсы). При этом на компьютер установится Zend Framework, PHP и Web-сервер Apache. После завершения установки зайдите по адресу http://localhost/ZendServer/. За всеми деталями обращайтесь к инструкции по установке Zend Framework. Если вам удалось войти в консоль ZendServer, значит все готово.

Вам придется также создать учетную запись на Amazon (см. Ресурсы).

В примерах используется класс PHP Credentials, созданный в Части 1. Этот класс управляет верительными данными учетной записи Amazon. Верительные данные хранятся в файле .ini (листинг 1).

Листинг 1. Хранение верительных данных в файле РНР.ini
; Файл конфигурации для хранения секретных ключей, номеров 
; учетных записей и других полезных цепочек символов для Amazon и 
; других облачных служб.

[amazon]
accessKey=0123456789ABCDEFGHIJ
secretKey=0123456789abcdefghiABCDEFGHI1234567890AB
ownerId=123456789012

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


О примере приложения

Пример приложения состоит из одной страницы PHP (sqs.php), которая выполняет несколько функций:

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

Для начала создадим объект Zend_Service_Amazon_Sqs (листинг 2).

Листинг 2. Создание объекта Zend_Service_Amazon_Sqs
require_once 'Zend/Service/Amazon/Sqs.php'; 
require_once 'Credentials.php'; 
$creds = new Credentials;  
$sqs = new Zend_Service_Amazon_Sqs($creds->getCredential('amazon', 'accessKey'),  
   $creds->getCredential('amazon', 'secretKey'));

Этот объект позволяет работать с очередями, относящимися к вашей учетной записи. Метод Zend_Service_Amazon_Sqs->getQueues() возвращает массив, содержащий все имена очередей для учетной записи. PHP-страница отображает их в таблице (рисунок 1).

Рисунок 1. Список очередей SQS
Список очередей SQS

В имена очередей сообщений входит идентификатор владельца учетной записи. В этом примере очереди принадлежат владельцу с ID 123456789012. При обращении к очереди или сообщению нужно использовать полное имя очереди (http://queue.amazonaws.com/ownerId/queueName). Представленная здесь часть таблицы содержит также число видимых сообщений в каждой очереди. Код PHP представлен в листинге 3.

Листинг 3. Получение списка очередей и количества сообщений в каждой из них.
$queues = $sqs->getQueues();
foreach ($queues as $queue) {
  try {
 $messageCount = $sqs->count($queue);
    echo "<tr>";
    echo "<td>".$queue."</td>";
    echo "<td style='text-align: center;'>".$messageCount."</td>";

Для определения количества сообщений в каждой очереди в этом коде используется метод count(). (На самом деле это приблизительное количество сообщений; подробнее об этом ниже.) Если в очереди имеется хотя бы одно сообщение, PHP создает кнопку для получения следующего сообщения (листинг 4); в противном случае ячейка остается пустой (см. рисунок 2).

Листинг 4. Создание кнопки для получения следующего сообщения
echo "<td>";
if ($messageCount) {
  echo "<form action='".$_SERVER['PHP_SELF']."' method='post'>";
  echo "<input type='hidden' name='getNextMessage' value='1'>";
  echo "<input type='hidden' name='queueToUse' value='$queue'/>";
 echo "<input type='submit' value='Receive Next Message'>";
  echo "</form>";
} 
else
  echo "&nbsp;";
 echo "</td>";

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

Рисунок 2. Полная таблица очередей
Полная таблица очередей

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


Создание очереди

Создать очередь очень просто. Достаточно получить имя очереди и вызвать метод Zend_Service_Amazon_Sqs->create(). Страница PHP содержит простую форму для ввода имени очереди:

Рисунок 3. Создание очереди
Создание очереди

Код для создания новой очереди предельно прост (листинг 5).

Листинг 5. Создание очереди
try {
  $responseCode = $sqs->create($_POST['queueToCreate']);
  if ($responseCode)
    echo "The queue ".$_POST['queueToCreate']." was created successfully.";
  . . .
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The queue could not be created. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

Zend не предоставляет никаких специальных средств обработки ошибок для метода create(), так что если что-то не так, код просто выводит на странице детали исключительной ситуации. Создание очереди с недопустимым именем (например, queue#3) приводит к исключительной ситуации InvalidParameterValue, а создание повторяющегося имени – QueueAlreadyExists. Если очередь создана успешно, страница начинается с сообщения об успешном выполнении (листинг 4).

Листинг 4. Очередь успешно создана
Скриншот сообщения об успешном создании очереди

Создание сообщения

PHP-страница содержит также краткую форму для создания сообщения.

Рисунок 5. Создание сообщения
Создание сообщения

Обратите внимание, что раскрывающийся список заполнен именами очередей вашей учетной записи (рисунок 6).

Рисунок 6. Листинг очередей учетной записи
Листинг очередей учетной записи

Код PHP для создания раскрывающегося списка выглядит, как показано в листинге 6.

Листинг 6. Создание раскрывающегося списка всех очередей
<p>Select a queue:</p>
<select name="queueForNewMessage"> 
<?php
 foreach ($queues as $queue) { echo "<option>".$queue."</option>";
  }
?>
</select>
</code>

Для создания нового сообщения используется метод send() (листинг 7).

Листинг 7. Отправка сообщения в очередь
try {
 $response = $sqs->send($_POST['queueForNewMessage'], $_POST['newMessage']);
  if ($response) {
    echo "The new message was successfully created in queue ";
    echo $_POST['queueForNewMessage'];
    echo ".<br/>The message ID is ".$response.".";
  }
  else {
    echo "The new message could not be created in queue ";
    echo $_POST['queueForNewMessage'];
    echo ".";
  }
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The message could not be created. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

Код отправляет запрос в Amazon. Если что-то не так, на странице отображается исключение. В большинстве случаев на страницу выводится идентификатор успешно созданного сообщения (рисунок 7).

Рисунок 7. Сообщение создано успешно
Успешно созданное сообщение

Сообщение об успехе содержит идентификатор нового сообщения. Вы увидите ID этого сообщения еще раз, когда получите сообщение.


Несколько слов о задержке распространения

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

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

Чтобы преодолеть эту задержку, страница содержит кнопку обновления списка очередей (рисунок 8).

Рисунок 8. Обновление списка очередей
Обновление списка очередей

Если нажать эту кнопку, чтобы обновить очередь, в определенный момент таблица укажет правильное количество сообщений. (Кнопка позволяет обновлять таблицу без повторного запроса на создание сообщения.) В нашем примере приложения задержка распространения может вызвать проблему при удалении очереди. Несмотря на сообщения SQS об успешном удалении очереди ее имя часто отображается в списке. Если поинтересоваться у SQS количеством сообщений в этой очереди, вы получите исключение. По этой причине в коде, который генерирует список очередей, используется блок try, чтобы получить число сообщений в очереди. При неудачном обращении к методу count() код просто игнорирует исключение.

Для эффективного использования SQS нужно помнить о задержке распространения. Это относится и ко многим другим облачным службам.


Прием сообщения

Обработка сообщений в очереди выполняется за два шага: прием и удаление. При получении сообщения Amazon SQS помечает это сообщение как невидимое. Сообщение предназначено для вас, поэтому никто, кто обращается к очереди, не увидит его. Получив сообщение, вы должны удалить его в течение определенного периода времени. Для каждой очереди определяется с таймаут видимости; если не удалить сообщение в течение этого времени, оно становится видимым и может быть прочитано любым. По умолчанию таймаут видимости для очереди составляет 30 секунд.

Кстати, при создании очереди Amazon позволяет определить таймаут видимости для всех обрабатываемых сообщений. Zend Framework поддерживает второй параметр метода Zend_Service_Amazon_Sqs->create() определения таймаута видимости (листинг 8).

Листинг 8. Создание очереди с указанным таймаутом видимости
$responseCode = $sqs->create($_POST['queueToCreate'], 120);

В этом примере задан таймаут видимости 2 минуты.

Прием сообщения из очереди производится методом Zend_Service_Amazon_Sqs->receive(). Имя очереди сообщений передается из формы. Так как сообщение может содержать до 8K символов, оно отображается в элементе HTML <textarea>. Полученное сообщение состоит из четырех частей:

  • body, сам текст сообщения;
  • md5, дайджест тела сообщения;
  • message_id, уникальный идентификатор сообщения;
  • handle, идентификатор, используемый для удаления сообщение из очереди.

Доступ к четырем частям сообщения можно получить с помощью упомянутых выше ключей. Например, $message[0]['body'] можно использовать для обращения к телу сообщения, а $message[0]['handle'] возвращает идентификатор сообщения. Заметим, что хотя Amazon SQS позволяет запрашивать больше одного сообщение за раз, Zend Framework этого не делает. При каждом обращении к Zend_Service_Amazon_Sqs->receive() возвращается одно сообщение. Однако это сообщение возвращается в массиве, так что для получения доступа к части сообщения нужно использовать $message[0][...].

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

Нажав кнопку "Получить следующее сообщение", вы увидите нечто похожее на рисунок 9.

Рисунок 9. Полученное сообщение
Полученное сообщение

Таймаут видимости используется для генерации предложения "Оно возвратится в очередь через 30 секунд" (рисунок 10). Подробнее об атрибутах очереди поговорим ниже.

Рисунок 10. Идентификатор сообщения и таймаут видимости
Идентификатор сообщения и таймаут видимости

Как уже упоминалось, $message[0]['handle'] возвращает идентификатор сообщения. Чтобы получить таймаут видимости, можно воспользоваться методом getAttribute() (листинг 9).

Листинг 9. Определение таймаута видимости для очереди
$visibilityTimeout = 
 $sqs->getAttribute($_POST['queueToUse'], 'VisibilityTimeout');

Таймаут видимости используется для генерации предложения "Оно возвратится в очередь через 30 секунд". getAttribute() позволяет определять различные детали очереди; подробнее об атрибутах очереди см. ниже.

Код, приведенный в листинге 10, генерирует формы для отображения полученного сообщения.

Листинг 10. Создание формы для полученного сообщения
echo "<form action='".$_SERVER['PHP_SELF']."' method='post'>";

// Отображение самого сообщения в <textarea>
echo "The message from the queue is: <br/><br/>";
echo "<textarea cols='80' rows='8'>";
echo $message[0]['body'];
echo "</textarea><br/><br/>";

// Идентификатор сообщения и имя очереди – скрытые поля
echo "<input type='hidden' name='deleteMessage' value='1'/>";
echo "<input type='hidden' name='messageHandle' ";
echo "value='".$message[0]['handle']."'>";
echo "<input type='hidden' name='queueToUse' ";
echo "value='".$_POST['queueToUse']."'>";

// Кнопка Submit удаляет сообщение 
echo "To delete this message, click here: ";
echo "<input type='submit' value='Delete Message'><br/><br/>";

// Показать идентификатор сообщения, если пользователь хочет удалить его позже
echo "If you want to delete this message ";
echo "later, use this message handle: <br/><br/>";
echo "<textarea cols='80' rows='3'>";
echo $message[0]['handle']."</textarea><br/><br/>";

// Для информации, отображение таймаута видимости для очереди
echo "If you do not delete this message, it will  ";
echo "go back into the queue in ".$visibilityTimeout." seconds.";
echo "</form>";

Удаление сообщений

Как вы могли заметить, форма, которая отображает полученное сообщение, содержит кнопку для его удаления. Для обращения к методу Zend_Service_Amazon_Sqs->deleteMessage() требуется имя очереди и идентификатор сообщения (листинг 11).

Листинг 11. Удаление сообщений из очереди
try {
 $response = $sqs->deleteMessage($_POST['queueToUse'], $_POST['messageHandle']);
  echo "The message was deleted successfully.";
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The message could not be deleted. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

Если удаление проходит успешно, на странице отображается соответствующее сообщение (рисунок 11).

Рисунок 11. Успешное удаление сообщения
Успешное удаление сообщения

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


Получение атрибутов очереди

Мы видели, что при получении сообщения страница PHP отображает таймаут видимости очереди. Это достигается путем вызова getAttribute(). Первым атрибутом getAttribute() является имя очереди. В качестве второго аргумента Amazon в настоящее время поддерживает следующие атрибуты с чувствительными к регистру именами:

  • VisibilityTimeout – таймаут видимости для сообщений, полученных из очереди;
  • ApproximateNumberOfMessages – приблизительное количество сообщений в очереди. Оно не учитывает никаких полученных сообщений;
  • ApproximateNumberOfMessagesNotVisible – приблизительное количество сообщений, которые получены, но еще не удалены;
  • CreatedTimestamp – когда была создана очередь;
  • LastModifiedTimestamp – время последнего изменения атрибутов очереди или разрешений. Отправка, получение или удаление сообщения не изменяет эту метку времени;
  • All – возвращает все атрибуты. Это значение по умолчанию.

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

Листинг 12. Отображение всех своих очередей и их атрибутов
<?php
  $queues = $sqs->getQueues();
  foreach ($queues as $queue) {
    try {
      echo "<tr>";
      echo "<td>".$queue."</td>";
      echo "<td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'VisibilityTimeout');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'ApproximateNumberOfMessages');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'ApproximateNumberOfMessagesNotVisible');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'CreatedTimestamp');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'LastModifiedTimestamp')."</td>";
      echo "</tr>";
    }
    catch (Zend_Service_Amazon_SQS_Exception $sqse) {
    }
  }
?>

Атрибуты в таблице выглядит, как на рисунке 12.

Рисунок 12. Все атрибуты очереди
Все атрибуты очереди

(Этот код включен в примеры под именем sqs-attributes.php.)


Удаление очереди

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

Рисунок 13. Удаление очереди должно быть подтверждено
Удаление очереди должно быть подтверждено

Когда PHP генерирует форму для удаления очереди, он определяет диалоговое окно подтверждения с помощью атрибута onsubmit элемента <form> (листинг 13).

Листинг 13. Создание кнопки для удаления очереди
echo "<td>";
echo "<form action='".$_SERVER['PHP_SELF']."' method='post' ";
echo "onsubmit='return confirm(\"Do you really want to delete the ";
echo "queue $queue? This will delete all any messages in the queue ";
echo "as well.\");'>";
echo "<input type='hidden' name='deleteQueue' value='1'/>";
echo "<input type='hidden' name='queueToDelete' value='$queue'/>";
echo "<input type='submit' value='Delete Queue'>";
echo "</form>";
echo "</td>";

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

Листинг 14. Удаление очереди
try {
 $response = $sqs->delete($_POST['queueToDelete']);
  echo "The queue was deleted successfully.";
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The queue could not be deleted. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

Как и при удалении сообщения, при удалении очереди отображается сообщение об успешной операции или исключение (рисунок 14).

Рисунок 14. Успешное удаление очереди
Успешное удаление очереди

Если что-то не так, код просто отображает исключение.


Дополнительные темы

Amazon SQS поддерживает несколько операций, которые не входят в класс Zend_Service_Amazon_Sqs. Мы кратко опишем их здесь, хотя они и выходят за рамки Zend Framework. Для решения любой из этих задач необходимо использовать один из API более низкого уровня, предоставляемых Amazon. Вот эти операции:

  • AddPermission: можно определить разрешения, так чтобы другие пользователи могли получить доступ к очереди. Это позволяет использовать очереди как способ координирования работы между разными приложениями;
  • RemovePermission: можно также отменять разрешения;
  • SetQueueAttributes: Zend позволяет получить атрибуты очереди, но не позволит изменять их;
  • ChangeMessageVisibility: получив сообщение, можно изменить его таймаут видимости. Это оставляет больше времени на обработку сообщения, прежде чем оно будет возвращено в очередь. Этот метод применяется только для полученного сообщения; он не меняет таймаут видимости по умолчанию для самой очереди.

За более подробной информацией об этих методах обращайтесь к документации SQS.


Заключение

В данной статье представлена PHP-страница, которая позволяет работать со службой Amazon Simple Queue. Эту страницу можно использовать для создания и удаления очередей сообщений, отправки и получения сообщений, а также контроля состояния очереди. Подробная техническая информация фактических запросов, отправляемых на Amazon, скрыта за PHP-объектом, что упрощает использование очередей и сообщений. Применение Zend Framework обеспечивает элегантный набор объектов для работы с облачными вычислениями.


Загрузка

ОписаниеИмяРазмер
Пример кодаos-php-cloud3-source.zip5 KБ

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

  • Примите участие в блогах и в деятельности сообщества developerWorks. (EN)

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=629470
ArticleTitle=Применение PHP в облачных вычислениях: Часть 3. Работа с Amazon SQS посредством Zend Framework
publish-date=02252011