65.9K
CodeProject 正在变化。 阅读更多。
Home

设计使用 COM+ 队列服务的异步处理

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.83/5 (6投票s)

2003年6月1日

13分钟阅读

viewsIcon

72769

COM+ 队列服务简介。

引言

在 COM+ 引入之前,开发人员负责处理线程分配、安全和其他资源管理任务。通过提供对象/线程池、事务支持(跨越网络上的多个数据库)、JIT 对象激活和其他重要方面等功能,COM+ 使应用程序更具可伸缩性并确保数据完整性。在此背景下,COM+ 可以看作是增强 Microsoft® 组件对象模型 (COM) 和 Microsoft 事务服务器 (MTS) 的下一步。

队列组件通过提供一种环境进一步增强了 COM+ 编程模型,在该环境中,组件可以同步(实时)或异步(排队)调用。组件无需知道它是以排队还是实时方式调用的。

更多关于 COM+ 队列组件

COM+ 队列服务与 MS 消息队列服务紧密集成,并提供了一种异步调用服务器端组件及其方法的方式。接收方组件在发送方调用接收方组件时不必可用。同样,在消息实际由服务器端接收方组件处理时,发送方也不必可用。

通常,MSMQ 队列是一个存储区域,MSMQ 在其中保存来自不同发送方对象的邮件。这些邮件可供接收方对象以后收集。接收方对象不必直接与发送方通信即可接收发送方消息。发送方和接收方之间的通信是间接的,并且通过队列来实现。这种间接通信提供了非常低的耦合度,使发送方和接收方都能独立运行。

同样,在使用 COM+ 队列服务时,客户端对象即使在服务器应用程序在请求时不可用,也可以访问 COM+ 服务器应用程序中的组件并调用其方法。服务器应用程序不可用这一事实不会导致错误。客户端请求保存在队列中。当服务器应用程序可用时,请求就会被处理。

并非所有实际业务场景都适合异步排队处理。

案例 - I

让我们考虑将 URL 提交到基于 Web 的目录列表服务的典型情况。一些目录列表服务在用户提交 URL 时会进行手动验证;它不会立即添加到搜索过程。除了 URL 信息外,用户还可以提交其他数据,例如公司/姓氏、地址、电话和电子邮件。

将用户提交的数据作为实时操作存储在数据库中的任务可能会让客户端一直等待数据库操作完成(或)超时。在此场景中可以应用排队处理,其中数据库保存操作被排队并在稍后执行(非实时),最好是在服务器负载较低时。这极大地提高了提交过程的可伸缩性。

案例 - II

与上述示例相比,销售电话卡的在线商店的订单处理通常是实时的。用户在处理完成后会立即看到电话卡号码。

优点

从上面案例 1 和 2 可以看出,并非所有业务场景都适合排队处理。应用 COM+ 排队处理时,具有以下优点:

  • 极低的运行时依赖性
    • 使用 COM+ 队列服务时,所有客户端请求都存储在队列中,供接收方检索和处理。客户端发送请求时,接收方不必可用/可访问,反之亦然。
       
  • 保证送达
    • COM+ 队列组件建立在 MSMQ 的基础上。MSMQ 凭借保护数据的内置功能,提供可靠、有保证的消息传递。因此,当客户端请求发送到 MSMQ 队列时,保证将请求传送到服务器。MSMQ 会在服务器故障时回滚事务,以防止任何消息丢失。
       
  • 更好的负载平衡
    • 大多数应用程序(特别是 Web 应用程序)都实现某种形式的负载平衡来提高应用程序的可伸缩性和可用性,其中用户请求会分发到多个服务器。

      识别并将排队处理应用于不需要即时、直接处理的进程可以增强负载平衡。单独的服务器可以处理所有排队的请求。这减少了处理实时请求的服务器的负载。

      在具有 n 层体系结构的应用程序中,业务逻辑通常封装在一组业务服务对象中。这些组件用于处理实时请求和排队请求。在非高峰时段执行排队请求处理会减轻托管这些组件的服务器的负载。
       

  • 服务器故障时高可用性
    • 客户端和服务器不直接连接的特性使得客户端应用程序能够像服务器应用程序可用一样继续处理其请求(即使服务器发生故障)。
       
  • 易用性
    • 在不使用 COM+ 队列服务的情况下,可以从客户端向服务器发送消息,实现与 COM+ 队列服务相同的可靠性。但这样做需要自定义编程来与 MSMQ 队列交互。COM+ 队列组件隐藏了所有 MSMQ 机制。使用 COM+ 队列服务时,向 MSMQ 发送消息与调用 COM 对象上的方法调用没有区别。在服务器端,无需额外的编程即可从队列中检索客户端请求。

限制

  1. 仅在 Microsoft Win2K 和 Win XP 上可用。
  2. 在 Windows NT 4.0 客户端和 2000/XP 服务器的设置中,您需要在客户端使用自定义代码显式创建和发送消息到 MSMQ。在服务器端,需要自定义编码来创建自己的侦听器服务。

与 DCOM 和中间件消息传递软件应用程序的比较

与 COM+ 队列服务相比,使用 DCOM 进行方法调用时,如果关联的服务器应用程序在方法调用时不可用,则会产生错误。尽管中间件消息传递软件应用程序为客户端发送请求提供了必要的机制,但当服务器不可用时,它们需要客户端显式构建消息(通常采用 XML 格式)。客户端将无法以透明的方式在远程服务器对象上进行方法调用。

使用队列服务进行请求处理

客户端和服务器端共同的三种组件构成了 COM+ 队列组件服务。

  1. 客户端端的录制器,充当服务器组件的代理。

  2. 服务器端的侦听器。

  3. 服务器端的播放器。

图 1:COM+ 队列服务上下文中的方法调用执行流程

当客户端对象调用队列组件的方法时,该调用首先由代理(录制器)接收。录制器将方法调用存储为消息的一部分,并将其放入 MSMQ 队列。录制器还将客户端安全上下文封送(marshal)到消息中。

在服务器端,队列组件侦听器检索此消息并将其交给队列组件播放器。

一旦客户端组件完成并且记录了方法的事务已提交,播放器

  1. 解封送(unmarshal)客户端安全上下文
  2. 调用服务器端 COM 组件
  3. 进行方法调用

要求

  1. MSMQ 安装在具有该组件的计算机上
  2. 要用作队列组件的类中的所有方法都必须满足以下要求:

    1. 方法不能有返回值,即只能使用定义为子例程的方法。

    2. 所有方法参数都必须是输入参数,即传递给子例程的所有参数都必须指定为 ByVal。

由于服务器组件异步处理请求,有时客户端可能在实际处理时不可用。在这种情况下,服务器计算机将无法以任何直接方式与客户端通信。通过强制执行上述要求,COM+ 队列服务消除了尝试与客户端进行任何此类直接通信的可能性。

响应客户端

从上面的要求部分可以看出,异步处理期间不可能进行双向通信。但有时客户端可能希望在请求处理后收到通知。这可以根据底层业务需求以多种方式实现。

最简单的方法是向相关收件人发送电子邮件。这通常在需要通知最终用户请求处理的情况下进行。

图 2:从服务器到用户的电子邮件通知

或者,可以使用一系列单向通信将回复从服务器发送到客户端。这可以通过让服务器端队列组件实例化一个实际上驻留在客户端计算机上的组件来实现,该组件使用 DCOM/COM+ 队列服务。这可以直接(或)通过中间组件完成。

图 3:通过一系列单向调用响应客户端。

部署与配置

组件必须配置为队列组件才能异步调用其方法。可以使用 Win2K 的组件服务管理工具,通过以下一系列步骤完成此操作:

  1. 创建一个新的空 COM+ 服务器应用程序(例如,QCOM)。

  2. 将您的组件添加到此应用程序。

  3. 选择 COM+ 应用程序 -> 右键单击并转到 COM+ 应用程序的属性 -> 单击“排队”选项卡 -> 选择“排队”属性 -> 选择“侦听”属性。

    排队选项 - 允许客户端对象异步调用服务器组件。

    侦听选项 - 使服务器组件处理客户端请求。

  4. 现在需要将实际的 COM+ 组件接口标记为排队。

    选择 COM+ 应用程序(例如,QCOM)-> 展开 COM+ 应用程序 -> 展开“组件”文件夹 -> 展开 COM+ 组件(例如,qc.sm)-> 展开“接口”文件夹 -> 选择要标记为排队的组件接口 -> 右键单击并转到属性 -> 单击“排队”选项卡 -> 选择“排队”属性。

    注意:如果看到排队复选框被禁用,请确保组件的所有方法都满足上面“要求”部分中提到的方法规则。

工作组模式限制

工作组配置不允许 COM+ 队列组件服务支持应用程序安全。因此,必须禁用此配置中访问的每个 COM+ 应用程序上的安全。当 Microsoft 消息队列配置为在工作组模式下运行(而不是与域控制器一起工作)时,可以通过以下一系列步骤将 COM+ 应用程序的身份验证级别设置为“无”来完成此操作:

  1. 打开组件服务 MMC 管理单元。

  2. 选择 COM+ 应用程序 -> 右键单击并转到属性 -> 单击“安全性”选项卡 -> 选择“无”作为调用的身份验证级别。

示例应用程序

让我们以一个虚构的在线求职网站上的在线雇主注册过程为例。注册过程如下:

  1. 用户(雇主)可以通过提供详细信息在线注册。

  2. 用户不会立即注册。用户提交内容被排队,求职网站的管理部门会对雇主公司的真实性进行手动检查。将向符合条件的申请人发送带有用户 ID/密码的电子邮件。下面提供的示例代码演示了用户提交以及在服务器端从消息队列中检索。为简单起见,服务器组件仅将雇主详细信息写入平面文件NewEmployer.txt

假设

  1. MSMQ 已安装。

  2. 客户端(名为 ClientComputer)和服务器(名为 ServerComputer)都运行在 win2k 上。

然后,当你开始迭代 2(这是构建迭代的开始)时,你可能想要复制测试用例并将它们重新分类到迭代 2。这还允许对测试用例进行粒度跟踪,并允许你说某个测试用例在一个迭代中是准备好的,但在另一个迭代中不是。同样,如何做到这一点取决于你以及你希望如何报告。 “场景”部分提供了更多细节。

  1. 创建注册用户界面

    将以下 HTML 保存到文件NewRegistration.html

    <HTML>
    <HEAD>
    <TITLE></TITLE>
    </HEAD>
    <BODY>
    
    <form action="ProcessRegistration.asp" method="post">
    
    <table width=350 border=0 bgcolor="#2B61AE">
    <tr>
       <td align=center colspan=2>
           <font size=+1 color=#FFFFFF>
           New Employer Registration</font>
       </td>
    </tr>
    <tr>
       <td colspan=2>
           <font size=+1>
           &nbsp;</font>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>First Name</font>
       </td>
       <td>
           <input type="text" name="FName" width=15>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>Last Name</font>
       </td>
       <td>
           <input type="text" name="LName" size=15>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>Company</font>
       </td>
       <td>
           <input type="text" name="Company" size=25>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>Email Address</font>
       </td>
       <td>
           <input type="text" name="EMail" size=25>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>Phone</font>
       </td>
       <td>
           <input type="text" name="Phone" size=10>
       </td>
    </tr>
    <tr>
       <td>
           <font color=#FFFFFF>FAX</font>
       </td>
       <td>
           <input type="text" name="FAX" size=10>
       </td>
    </tr>
    <tr>
       <td colspan=2>
           <font size=+1>
           &nbsp;</font>
       </td>
    </tr>
    <tr>
       <td colspan=2 align=center>
           <input type=submit value="Register">
           <input type=reset>
       </td>
    </tr>
    </table>
    
    </form>
    
    </BODY>
    </HTML>
    

    将此文件保存在客户端计算机上的 IIS 默认根目录c:\inetpub\wwwroot(或可通过 IIS 访问的任何其他目录)中。

     

  2. 创建服务器端组件

    创建一个 Visual Basic ActiveX DLL 项目来创建 COM+ 队列组件。

    项目名称 = qc

    类名 = sm

    将以下代码复制到 sm 类模块中。

    Const FIELD_SEPARATOR = ""
    
    Public Sub Save(ByVal FName As String, _
        ByVal LName As String, _
        ByVal Company As String, _
        ByVal EMailAddress As String, _
        ByVal Phone As String, _
        ByVal FAX As String)
        
        Dim FileID As Integer
        Dim DataLine As String
        
        FileID = FreeFile
        DataLine = FName & FIELD_SEPARATOR & _
        LName & FIELD_SEPARATOR & Company & _
        FIELD_SEPARATOR & EMailAddress & _
            FIELD_SEPARATOR & Phone & _
            FIELD_SEPARATOR & FAX
        
        '//Write the data to a database
        Open "c:\NewEmployers.txt" For _
            Append As #FileID
        Print #FileID, DataLine
        Close (FileID)
    End Sub
  3. 创建 DLL (qc.dll)。

    按照“部署与配置”部分中的说明,在服务器计算机上将上述组件 qc.dll 部署并配置为排队,COM+ 应用程序名称为 QCOM。

  4. 导出 COM+ 应用程序

    打开组件服务 MMC 管理单元 -> 选择 QCOM COM+ 应用程序 -> 右键单击 -> 导出(导出为应用程序代理)

  5. 在客户端计算机上安装代理。

    将导出的 .msi 和 .cab 文件复制到客户端计算机。只需双击 .msi 文件即可安装代理。

    注意:请确保客户端计算机上没有名为 QCOM 的 COM+ 应用程序。如果已存在,请在第 3 步中使用不同的名称。

     

  6. 创建客户端应用程序

    将以下脚本保存到客户端计算机c:\inetpub\wwwroot目录下的ProcessRegistration.asp

    <%
    dim fname
    dim lname
    dim company
    dim email
    dim phone
    dim fax
    
    fname=Request.Form ("fname")
    lname=Request.Form ("lname")
    company=Request.Form ("company")
    email=Request.Form ("email")
    phone=Request.Form ("phone")
    fax=Request.Form ("fax")
    
    ‘//specify the queue moniker
    
    set obj=getobject ("queue:FormatName=DIRECT=" & _
       "OS:ServerComputer\PRIVATE$\QCOM/new:qc.sm")
    
    obj.save fname,lname,company,email,phone,fax
    set obj=nothing
    
    %>
    
    <center><font color=#cc0000>
    Your registration information has been 
    sent successfully.
    <br>
    Registration at our website requires 
    manual verification.
    <br>
    We will contact you shortly.
    </center>
    

    在本示例设置中,组件是从远程计算机创建的(即客户端和服务器计算机不同),并且 MSMQ 在工作组模式下安装,因此使用 DIRECT 格式名称指定队列标识符(moniker)为:

    set obj=getobject ("queue:FormatName=DIRECT=" & _ 
      "OS:ServerComputer\PRIVATE$\QCOM/new:qc.sm")

    否则,简单的标识符形式(如下)应该可以工作。

    set obj=getobject ("queue:/new:qc.sm")

测试

  1. 访问 URL http://ClientComputer/NewRegistration.html

  2. 填写数据并提交

  3. 服务器端的 c:\NewEmployer.txt 文件中应创建包含输入数据的文件。

以下步骤概述了服务器不可用的场景的测试过程:

  1. 关闭服务器计算机
  2. 再次访问 URL http://ClientComputer/NewRegistration.html

  3. 提交表单时不会报告错误。方法调用将存储为 MSMQ 消息。

  4. 现在启动服务器计算机。

  5. 在服务器计算机上转到组件服务 MMC 管理单元。

  6. 激活 COM+ 应用程序。

    1. 选择 QCOM COM+ 应用程序 -> 右键单击 -> 启动

  7. 队列组件处理排队的消息,新数据将追加到数据文件c:\NewEmployer.txt

自动组件激活

队列组件的激活似乎很繁琐,因为它涉及手动干预。此任务可以通过以下步骤自动化:

  • 创建一个名为StartApp的 VB 项目。添加对 COM+ Admin Type Library 的引用。
  • 向其添加一个模块并粘贴以下代码:

    Sub main()
    Dim catalog As COMAdminCatalog
    
    Set catalog = New COMAdminCatalog
    
    catalog.StartApplication _
    ("{44AC1CF9-A6D2-4CF1-937E-BF1557F1FB50}"End Sub
  • StartApplication方法的参数是要激活的 COM+ 应用程序的ApplicationID。这可以从 QCOM COM+ 应用程序的属性窗口中获取。

    使用项目属性窗口将启动对象设置为 Sub Main。创建一个 exe。

    运行此可执行文件将启动指定的 COM+ 应用程序。可以使用 Windows 计划程序按需安排其运行。

结论

COM+ 队列服务是组件对象模型领域一项令人兴奋的新功能。它为 Web 应用程序带来了更具可伸缩性、易于构建且可靠的异步处理模型。朝这个方向迈出的重要一步是根据应用程序的业务需求,识别和分析应用程序中可以应用异步处理的区域。

本文旨在提供有关队列处理的必要详细信息,以便您开始。这并不涵盖 COM+ 队列处理的所有方面。与任何其他技术一样,没有比实践经验更好的学习方法了。处理此主题的最佳方法是从小型、简单的应用程序开始,并随着您的进步继续探索其他方面。

历史

  • 2003 年 6 月 1 日:首次修订。


© . All rights reserved.