如何通过 PHP 使用服务总线队列How to use Service Bus queues with PHP

本教程介绍如何创建 PHP 应用程序,以便向服务总线队列发送消息以及从中接收消息。In this tutorial, you learn how to create PHP applications to send messages to and receive messages from a Service Bus queue.

先决条件Prerequisites

  1. Azure 订阅。An Azure subscription. 若要完成本教程,需要一个 Azure 帐户。To complete this tutorial, you need an Azure account. 可以激活 MSDN 订阅者权益注册试用帐户You can activate your MSDN subscriber benefits or sign up for a trial account.
  2. 如果没有可使用的队列,请遵循使用 Azure 门户创建服务总线队列一文来创建队列。If you don't have a queue to work with, follow steps in the Use Azure portal to create a Service Bus queue article to create a queue.
    1. 阅读服务总线队列的快速概述Read the quick overview of Service Bus queues.

    2. 创建一个服务总线命名空间Create a Service Bus namespace.

    3. 获取连接字符串Get the connection string.

      Note

      在本教程中,需使用 PHP 在服务总线命名空间中创建一个队列You will create a queue in the Service Bus namespace by using PHP in this tutorial.

  3. Azure SDK for PHPAzure SDK for PHP

创建 PHP 应用程序Create a PHP application

创建访问 Azure Blob 服务的 PHP 应用程序的唯一要求是从代码内引用用于 PHP 的 Azure SDK 中的类。The only requirement for creating a PHP application that accesses the Azure Blob service is the referencing of classes in the Azure SDK for PHP from within your code. 可以使用任何开发工具或记事本创建应用程序。You can use any development tools to create your application, or Notepad.

Note

在安装 PHP 的过程中,还必须安装并启用 OpenSSL 扩展Your PHP installation must also have the OpenSSL extension installed and enabled.

在本指南中,将使用服务功能,这些功能可在 PHP 应用程序中本地调用,或通过在 Azure 的 Web 角色、辅助角色或网站中运行的代码调用。In this guide, you will use service features which can be called from within a PHP application locally, or in code running within an Azure web role, worker role, or website.

获取 Azure 客户端库Get the Azure client libraries

通过 Composer 安装Install via Composer

  1. 安装 GitInstall Git. 请注意,在 Windows 上,还需要向 PATH 环境变量添加 Git 可执行文件。Note that on Windows, you must also add the Git executable to your PATH environment variable.

  2. 在项目的根目录中创建一个名为 composer.json 的文件并向其添加以下代码:Create a file named composer.json in the root of your project and add the following code to it:

    {
        "repositories": [
            {
                "type": "pear",
                "url": "http://pear.php.net"
            }
        ],
        "require": {
            "pear-pear.php.net/mail_mime" : "*",
            "pear-pear.php.net/http_request2" : "*",
            "pear-pear.php.net/mail_mimedecode" : "*",
            "microsoft/windowsazure": "*"
        }
    }
    
  3. composer.phar 下载到项目根目录中。Download composer.phar in your project root.

  4. 打开命令提示符并在项目根目录中执行以下命令Open a command prompt and execute the following command in your project root

    php composer.phar install
    

手动安装Install manually

若要手动下载并安装 Azure 的 PHP 客户端库,请执行下列步骤:To download and install the PHP Client Libraries for Azure manually, follow these steps:

Note

Azure 的 PHP 客户端库依赖于 HTTP_Request2Mail_mimeMail_mimeDecode PEAR 程序包。The PHP Client Libraries for Azure have a dependency on the HTTP_Request2, Mail_mime, and Mail_mimeDecode PEAR packages. 若要解析这些依赖关系,建议的方法是使用 PEAR 程序包管理器安装这些包。The recommended way to resolve these dependencies is to install these packages using the PEAR package manager.

  1. GitHub 下载包含库的 .zip 存档。Download a .zip archive that contains the libraries from GitHub. 或者,分叉存储库并将其克隆到本地计算机。Alternatively, fork the repository and clone it to your local machine. 后一种方式需要一个 GitHub 帐户并要求在本地安装 Git。The latter option requires a GitHub account and having Git installed locally.

  2. 将所下载的存档的 WindowsAzure 目录复制到应用程序目录结构中。Copy the WindowsAzure directory of the downloaded archive to your application directory structure.

有关安装 Azure 的 PHP 客户端库的详细信息(包括安装为 PEAR 程序包的信息),请参阅下载 Azure SDK for PHPFor more information about installing the PHP Client Libraries for Azure (including information about installing as a PEAR package), see Download the Azure SDK for PHP.

配置应用程序以使用应用程序Configure your application to use Service Bus

若要使用服务总线队列 API,请执行以下操作:To use the Service Bus queue APIs, do the following:

  1. 使用 require_once 语句引用 autoloader 文件。Reference the autoloader file using the require_once statement.
  2. 引用所用的任意类。Reference any classes you might use.

下面的示例演示了如何包括 autoloader 文件并引用 ServicesBuilder 类。The following example shows how to include the autoloader file and reference the ServicesBuilder class.

Note

本示例(以及本文中的其他示例)假定你已通过 Composer 安装了用于 Azure 的 PHP 客户端库。This example (and other examples in this article) assumes you have installed the PHP Client Libraries for Azure via Composer. 如果已手动安装这些库或将其作为 PEAR 包安装,则必须引用 WindowsAzure.php autoloader 文件。If you installed the libraries manually or as a PEAR package, you must reference the WindowsAzure.php autoloader file.

require_once 'vendor/autoload.php';
use WindowsAzure\Common\ServicesBuilder;

在以下示例中, require_once 语句将始终显示,但只会引用执行该示例所需的类。In the examples below, the require_once statement will always be shown, but only the classes necessary for the example to execute are referenced.

设置服务总线连接Set up a Service Bus connection

若要实例化服务总线客户端,必须先设置采用以下格式的有效连接字符串:To instantiate a Service Bus client, you must first have a valid connection string in this format:

Endpoint=[yourEndpoint];SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=[Primary Key]

其中,Endpoint 的格式通常为 [yourNamespace].servicebus.chinacloudapi.cnWhere Endpoint is typically of the format [yourNamespace].servicebus.chinacloudapi.cn.

若要创建任何 Azure 服务客户端,必须使用 ServicesBuilder 类。To create any Azure service client you must use the ServicesBuilder class. 方法:You can:

  • 将连接字符串直接传递给它。Pass the connection string directly to it.
  • 使用 CloudConfigurationManager (CCM) 检查多个外部源以获取连接字符串:Use the CloudConfigurationManager (CCM) to check multiple external sources for the connection string:
    • 默认情况下,它附带了对一个外部源的支持 - 环境变量By default it comes with support for one external source - environmental variables
    • 可通过扩展 ConnectionStringSource 类来添加新源You can add new sources by extending the ConnectionStringSource class

在此处列出的示例中,将直接传递连接字符串。For the examples outlined here, the connection string is passed directly.

require_once 'vendor/autoload.php';

use WindowsAzure\Common\ServicesBuilder;

$connectionString = "Endpoint=[yourEndpoint];SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=[Primary Key]";

$serviceBusRestProxy = ServicesBuilder::getInstance()->createServiceBusService($connectionString);

创建队列Create a queue

可以通过 ServiceBusRestProxy 类对服务总线队列执行管理操作。You can perform management operations for Service Bus queues via the ServiceBusRestProxy class. ServiceBusRestProxy 对象是通过 ServicesBuilder::createServiceBusService 工厂方法构造的,包含一个适当的连接字符串,该字符串封装了令牌权限以对它进行管理。A ServiceBusRestProxy object is constructed via the ServicesBuilder::createServiceBusService factory method with an appropriate connection string that encapsulates the token permissions to manage it.

以下示例演示了如何实例化 ServiceBusRestProxy 并调用 ServiceBusRestProxy->createQueue 以在 MySBNamespace 服务命名空间内创建名为 myqueue 的队列:The following example shows how to instantiate a ServiceBusRestProxy and call ServiceBusRestProxy->createQueue to create a queue named myqueue within a MySBNamespace service namespace:

require_once 'vendor/autoload.php';

use WindowsAzure\Common\ServicesBuilder;
use WindowsAzure\Common\ServiceException;
use WindowsAzure\ServiceBus\Models\QueueInfo;

// Create Service Bus REST proxy.
$serviceBusRestProxy = ServicesBuilder::getInstance()->createServiceBusService($connectionString);

try {
    $queueInfo = new QueueInfo("myqueue");

    // Create queue.
    $serviceBusRestProxy->createQueue($queueInfo);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here: 
    // https://docs.microsoft.com/rest/api/storageservices/Common-REST-API-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

Note

可以对 ServiceBusRestProxy 对象使用 listQueues 方法,以检查具有指定名称的队列是否已位于命名空间中。You can use the listQueues method on ServiceBusRestProxy objects to check if a queue with a specified name already exists within a namespace.

向队列发送消息Send messages to a queue

要将消息发送到服务总线队列,应用程序应调用 ServiceBusRestProxy->sendQueueMessage 方法。To send a message to a Service Bus queue, your application calls the ServiceBusRestProxy->sendQueueMessage method. 下面的代码演示了如何将消息发送到先前在 MySBNamespace 服务命名空间内创建的 myqueue 队列。The following code shows how to send a message to the myqueue queue previously created within the MySBNamespace service namespace.

require_once 'vendor/autoload.php';

use WindowsAzure\Common\ServicesBuilder;
use WindowsAzure\Common\ServiceException;
use WindowsAzure\ServiceBus\Models\BrokeredMessage;

// Create Service Bus REST proxy.
$serviceBusRestProxy = ServicesBuilder::getInstance()->createServiceBusService($connectionString);

try {
    // Create message.
    $message = new BrokeredMessage();
    $message->setBody("my message");

    // Send message.
    $serviceBusRestProxy->sendQueueMessage("myqueue", $message);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here: 
    // https://docs.microsoft.com/rest/api/storageservices/Common-REST-API-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

发送到服务总线(以及从服务总线收到)的消息是 BrokeredMessage 类的实例。Messages sent to (and received from ) Service Bus queues are instances of the BrokeredMessage class. BrokeredMessage 对象包含一组标准方法和属性,用于保存特定于自定义应用程序的属性,以及大量随机应用程序数据。BrokeredMessage objects have a set of standard methods and properties that are used to hold custom application-specific properties, and a body of arbitrary application data.

服务总线队列在标准层中支持的最大消息大小为 256 KB,在高级层中则为 1 MB。Service Bus queues support a maximum message size of 256 KB in the Standard tier and 1 MB in the Premium tier. 标头最大大小为 64 KB,其中包括标准和自定义应用程序属性。The header, which includes the standard and custom application properties, can have a maximum size of 64 KB. 一个队列中包含的消息数量不受限制,但消息的总大小受限制。There is no limit on the number of messages held in a queue but there is a cap on the total size of the messages held by a queue. 队列大小的上限为 5 GB。This upper limit on queue size is 5 GB.

从队列接收消息Receive messages from a queue

从队列接收消息的最佳方法是使用 ServiceBusRestProxy->receiveQueueMessage 方法。The best way to receive messages from a queue is to use a ServiceBusRestProxy->receiveQueueMessage method. 可在两种不同的模式下接收消息:ReceiveAndDeletePeekLockMessages can be received in two different modes: ReceiveAndDelete and PeekLock. PeekLock 是默认设置。PeekLock is the default.

使用 ReceiveAndDelete 模式时,接收是一项单步操作,即当服务总线接收到队列中某条消息的读取请求时,它会将该消息标记为“已使用”并将其返回给应用程序。When using ReceiveAndDelete mode, receive is a single-shot operation; that is, when Service Bus receives a read request for a message in a queue, it marks the message as being consumed and returns it to the application. ReceiveAndDelete 模式是最简单的模式,最适合应用程序允许出现故障时不处理消息的方案。ReceiveAndDelete mode is the simplest model and works best for scenarios in which an application can tolerate not processing a message in the event of a failure. 为了理解这一点,可以考虑这样一种情形:使用方发出接收请求,但在处理该请求前发生了崩溃。To understand this, consider a scenario in which the consumer issues the receive request and then crashes before processing it. 由于服务总线会将消息标记为“已使用”,因此当应用程序重启并重新开始使用消息时,它会遗漏在发生崩溃前使用的消息。Because Service Bus will have marked the message as being consumed, then when the application restarts and begins consuming messages again, it will have missed the message that was consumed prior to the crash.

在默认的 PeekLock 模式下,接收消息会变成一个双阶段操作,这将能够支持不能允许丢失消息的应用程序。In the default PeekLock mode, receiving a message becomes a two stage operation, which makes it possible to support applications that cannot tolerate missing messages. 当 Service Bus 收到请求时,它会找到要使用的下一个消息,将其锁定以防其他使用方接收它,并将该消息返回给应用程序。When Service Bus receives a request, it finds the next message to be consumed, locks it to prevent other consumers from receiving it, and then returns it to the application. 应用程序完成消息处理(或可靠地存储消息以供日后处理)后,它会将收到的消息传递到 ServiceBusRestProxy->deleteMessage,从而完成接收过程的第二阶段。After the application finishes processing the message (or stores it reliably for future processing), it completes the second stage of the receive process by passing the received message to ServiceBusRestProxy->deleteMessage. 当服务总线发现 deleteMessage 调用时,它会将消息标记为“已使用”并将其从队列中删除。When Service Bus sees the deleteMessage call, it will mark the message as being consumed and remove it from the queue.

以下示例演示了如何使用 PeekLock 模式(默认模式)接收和处理消息。The following example shows how to receive and process a message using PeekLock mode (the default mode).

require_once 'vendor/autoload.php';

use WindowsAzure\Common\ServicesBuilder;
use WindowsAzure\Common\ServiceException;
use WindowsAzure\ServiceBus\Models\ReceiveMessageOptions;

// Create Service Bus REST proxy.
$serviceBusRestProxy = ServicesBuilder::getInstance()->createServiceBusService($connectionString);

try {
    // Set the receive mode to PeekLock (default is ReceiveAndDelete).
    $options = new ReceiveMessageOptions();
    $options->setPeekLock();

    // Receive message.
    $message = $serviceBusRestProxy->receiveQueueMessage("myqueue", $options);
    echo "Body: ".$message->getBody()."<br />";
    echo "MessageID: ".$message->getMessageId()."<br />";

    /*---------------------------
        Process message here.
    ----------------------------*/

    // Delete message. Not necessary if peek lock is not set.
    echo "Message deleted.<br />";
    $serviceBusRestProxy->deleteMessage($message);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://docs.microsoft.com/rest/api/storageservices/Common-REST-API-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

如何处理应用程序崩溃和不可读消息How to handle application crashes and unreadable messages

Service Bus 提供了相关功能来帮助你轻松地从应用程序错误或消息处理问题中恢复。Service Bus provides functionality to help you gracefully recover from errors in your application or difficulties processing a message. 如果接收方应用程序出于某种原因无法处理消息,它可以对收到的消息调用 unlockMessage 方法(而不是 deleteMessage 方法)。If a receiver application is unable to process the message for some reason, then it can call the unlockMessage method on the received message (instead of the deleteMessage method). 这会导致 Service Bus 解锁队列中的消息并使其能够重新被同一个正在使用的应用程序或其他正在使用的应用程序接收。This will cause Service Bus to unlock the message within the queue and make it available to be received again, either by the same consuming application or by another consuming application.

还存在与队列中已锁定的消息相关联的超时,并且如果应用程序未能在锁定超时到期之前处理消息(例如,如果应用程序崩溃),服务总线则将自动解锁该消息,使它可以再次被接收。There is also a timeout associated with a message locked within the queue, and if the application fails to process the message before the lock timeout expires (for example, if the application crashes), then Service Bus will unlock the message automatically and make it available to be received again.

如果在处理消息之后,发出 deleteMessage 请求之前,应用程序发生崩溃,则在应用程序重启时会将该消息重新传送给它。In the event that the application crashes after processing the message but before the deleteMessage request is issued, then the message will be redelivered to the application when it restarts. 此情况通常称作至少处理一次,即每条消息将至少被处理一次,但在某些情况下,同一消息可能会被重新传送。This is often called At Least Once processing; that is, each message is processed at least once but in certain situations the same message may be redelivered. 如果某个场景不允许重复处理,则建议向应用程序添加其他逻辑来处理重复消息传送。If the scenario cannot tolerate duplicate processing, then adding additional logic to applications to handle duplicate message delivery is recommended. 这通常可以通过使用消息的 getMessageId 方法来实现,消息在多次传送尝试中保持不变。This is often achieved using the getMessageId method of the message, which remains constant across delivery attempts.

后续步骤Next steps

了解服务总线队列的基础知识后,请参阅队列、主题和订阅以获取更多信息。Now that you've learned the basics of Service Bus queues, see Queues, topics, and subscriptions for more information.

有关详细信息,另请访问 PHP 开发人员中心For more information, also visit the PHP Developer Center.