首页 > 开发 > XML > 正文

可靠的 XML Web Service (1)

2024-09-05 20:55:53
字体:
来源:转载
供稿:网友
国内最大的酷站演示中心!
可靠的 xml web service
eric schmidt
microsoft corporation,xml core services 组,项目经理
2001 年 12 月 11 日

下载此专栏的示例代码。

注意:要下载与本文相关的代码,您需要:
visual studio .net release candidate(英文)
sql server 2000(英文)
在 pdc 上,我谈论了有关可靠的 xml web service(web 服务)的话题,这个话题源于过去一年来的多次交流。在有关建立 xml web service 的众多常见问题中,可靠性问题是开发人员实现分散式 web 服务所面临的五个最重要的问题之一。如果分开来讲,这个问题并不是太难,因此,本月我准备谈一谈建立可靠的 xml web service 这一棘手的问题。

概述
global xml web services architecture(gxa [英文])最突出的一面就是可以使用可合成处理协议扩展该体系结构。这些协议主要通过 soap 标头实现,可以提供包括安全性、加密、路由和可靠性的广泛服务。当您开始构建基于 gxa 的应用程序时,您将发现 gxa 实质上是一种消息处理体系结构,它通过基于标准的编码技术 (soap) 在系统和服务之间提供协同工作能力。到目前为止,大部分实现工作都集中在 soap 1.1 和 wsdl 兼容服务上,因此 web 服务实现方案可以与多种语言和操作系统协同工作。

这是一个了不起的概念。任何两个系统之间都能够进行交流,只要它们能够分析 xml 并理解 soap 规范的规则。但是,简单的消息交换并不能满足复杂的业务应用程序的需要。真正的应用程序(不管其内部域体系结构如何)均需要标准化的服务,例如处于 web 服务消息处理层上的安全性、授权和可靠性。在 global xml web services architecture(具体地说就是 soap、soap 模块和基础结构协议)的创建和实现背后有一个巨大的动力。随着今年十月份四项新规范(ws-routing、ws-referral、ws-licensing 和 ws-security)的发布,我们已经开始着手下一代 xml web service 实现工作。尽管发布了这么多的新规范,但仍有两个领域尚无公共规范,即事务处理和可靠的消息处理,这主要是因为这些基础结构协议依赖于底层 soap 模块。

本专栏主要从 gxa 环境的角度讨论可靠性和可靠的消息处理的含义。而且我还要花一些时间探讨通过在 .net 框架中扩展现有 web 服务类来开发可靠性协议需要做些什么。本专栏有两个主要目的:

让读者了解可靠性概念,为以后各种规范的实施做好准备。请注意,本文不是规范,而只是一篇文章,旨在引发读者思考下面要讨论的问题。
说明 .net 框架中 web 服务和 soap 类强大的、基于标准的功能。
xml web service 的可靠性
我们把问题分开来讲。我们前面讲过,gxa 服务实现方案属于消息处理服务,它们需要在分散式环境中发送和接收基于标准的编码消息。在 web 服务实现方案中发送 soap 消息的主要传输协议是 http,它易于实现和管理,但本身不可靠。我们无需深入探讨 http 不可靠的具体原因,但只要知道 http 没有基于标准的服务来保证终点或服务器能够接收到请求就足够了。尽管内置的网络层设备可以在发生一般灾难性故障(例如未找到资源)时产生错误,但是却没有机制可以确保客户端能够以可靠的方式接收请求或响应。

通常是通过简单的重新发送操作处理 http 故障,但在业务处理环境中这既不利于提高效率也没有效果。它导致不必要的通信量,并增加了重复交易的风险。

目前市场上有多种能够更有效解决此问题的消息处理技术,包括传输协议(如 httpr)、企业基础结构(如 msmq 和 mq series)以及业务处理协议(如 ebxml)。尽管每种技术针对特定的实现方案各有优点,但都不能以可在所有传输协议上跨域应用的可扩展方式解决可靠性问题;而且,在消息交换和处理方面的功能层次上也不尽相同。

面对所有这些问题,我决定总结一个需求列表,看一看在 web 服务环境中实现可靠性原型需要做哪些工作。

以下是我自己创建的可靠性层的主要需求列表:

基于标准并应用于消息协议层
确认发送
有序发送
对称对话
加快异步处理
基于标准
该协议必须由现有的基于标准的技术组成。而且,该协议还应该对 soap 1.1 规范进行扩展,然后应用到消息编码层而不是传输层。这样,消息才能够在所有可用的机制(从 http 到某些专用套接字实现方案)上进行传输。

确认发送
为了有章可循,该协议必须采用某种发送确认机制,也就是说,使用该协议发送的消息应当从处理器接收一个且只有一个关于该消息状态的确认信息。

有序发送
有序发送引入了对话概念,即客户端和服务器可以交换消息和确认(确认也是可唯一标识的对话的一部分)。收到消息后,将检查消息以进行排序,确保处理器收到一组有序的消息。

对称对话
建立在对话机制之上的协议,还必须确保消息和确认的对称性。必须确保每条消息只被处理一次,并且只生成一个确认。

加快异步处理
这是需求列表中最重要的一点,所以留在最后说明。http 是基于同步请求响应模型的,适用于处理任务量小或运行时间短的简单应用程序。web 服务实现方案有一个不太高明的小秘密,即用户不需要从处理的角度了解服务是如何在后端实现的。也就是说,web 服务实现方案处理一个请求可能只需要三秒钟,也可能会花上三个小时。这导致消息处理体系结构效率低下,且无法扩缩。我们需要的是一个能够加快异步消息处理体系结构的处理模型。但是要注意,异步模型实现方案要比紧耦合的请求响应实现方案复杂得多,因为它需要更多的基础结构。

我来解释一下。在使用标准 http 的同步消息处理模型中,客户端在向服务器发送请求后、从服务器接收到响应之前一直保持停滞状态。在这段时间内,可能会发生许多灾难性事件:

连接可能会因外部原因而断开,从而丢失请求或响应。
服务器可能会因脱机或过载而超时。
服务器进程可能取决于下行服务,而这种服务的响应时间无法控制。
同步模型


图 1:同步模型

不管问题是与网络有关还是与应用程序有关,要确保可靠性都需要实现某种附加协议驱动的基础结构。在本次讨论中,我想着重讲述消息是如何在传输层上进行处理的。传输层是独立于应用程序的关键部分,使用它可以实现可靠性层,并将消息的最终处理过程分离出来。更具体一点来说,每一条消息(不管针对哪种应用程序)都需要从网络层上读取,并分配至适当的应用程序资源。我们可以在这里添加一个发送可靠性确认和执行持续存储的附加协议,这样应用程序资源就可以选择处理该消息的时间和方式。而且,这个新协议可以帮助我们分离或加快异步处理模型。下面将解释如何完成此过程。

在下面的异步模型中,某一请求被发送至 soap 服务器。服务器从网络层上读取该消息流,并立即向客户端返回 http 202 响应。此进程仅就向服务器发送消息的时间而言是同步的,这样可以减少与连接有关的问题。到达服务器后,消息将被传送到可靠性层,在这里进行检查以验证消息是否过期、重复和有序。然后,消息被持续存储(在关系数据库中),并向客户端发送有关其状态的确认。最后,消息将被分配至正确的应用程序功能。

异步模型


图 2:异步模型

在 http 环境中,您可以控制向客户端发送响应的时间。通过控制向客户端发送响应的时间,您可以将下行处理影响通信可靠性的风险降到最低。在 soap 中,这是通过单向消息传递实现的。它指示底层 soap 处理器立刻向客户端发送 http 202 响应,通知客户端已收到消息,并已成功地将消息分配给正确的资源进行处理。之后,处理器向客户端发送有关该消息状态的响应。本文稍后将对这种模型的优点进行详细介绍。

建立可靠性层
明确了上述要求之后,我们来讨论如何使用 .net 框架为 web 服务实现方案建立可靠性协议。根据上述要求,我建立了一个小型 api,以便提供可用的实现方案。

协议:ericrp
第一个问题是定义如何分解可靠性协议 (ericrp)。以下是该协议的关键之处:

该协议是用于教学的原型。
该协议主要是通过扩展 soap 消息处理层在 soap 处理层上执行的。
soap 标头用于对处理层所需信息进行编码。
该协议要求实现方案具有某种方式的持续存储,以便记录消息。本实现方案使用的是 microsoft sql server 2000。
注意:不管采取哪种方式在 soap 环境中实现可靠性层,除了 soap 分析器之外,都还需要其他基础结构。
该协议支持对话概念,也就是说可以对多条消息进行排序,从而保证有序的发送。
该协议的全部实现方案都由 ericrp 名称空间限定。
ericrp 基于两方对话方案,即两个服务可以通过 xml web services 体系结构(http、soap 和 wsdl)进行对话。
客户端负责消息的所有更正。(本文后面有详细论述)
服务器只负责基于特定标准发送确认。
服务器不记录收到的过期消息。
服务器不记录收到的无序消息。
服务器不记录收到的重复消息。
处理 api
在这个原型中,我建立了六个主要的类和一个小型数据库。我将类称为处理 api。web 服务客户端和服务器将使用这些类监控和更正使用 ericrp 可靠性协议的消息。所有的类都属于 ericrp 名称空间:

client.conversationmanager:由客户端使用,创建 web 服务消息关联和消息监控的对话环境。
client.rpclienttrace:由 web 服务客户端使用,这些客户端的方法对出站消息执行 ericrp 可靠性协议。
server.conversationmanager:由 web 服务服务器使用,记录并处理入站消息。
server.rpservertrace:由 web 服务服务器使用,这些服务器的方法对入站消息执行 ericrp 可靠性协议。
reliabilityinfo:具有双重作用。它可以由 client.conversationmanager 使用,为记录提供可靠性信息;也可以由 web 服务客户端代理使用,为出站消息创建必要的 soap 标头信息。
acknowledgment:由 server.conversationmanager 使用,向客户端发送确认。
ericrp 的工作原理
在查看代码之前,我想先从用户的角度说明该协议的工作原理。例如,我有一个简单的 web 服务代理类,通过它可以向 web 服务发送订单消息。打算使用 api 的客户端需要执行以下操作:

首先,创建 client.conversationmanager 类的实例并开始一个新对话。例如:

private void begin()
{
rpclient = new ericrp.client.conversationmanager();

rpclient.messagesent += _
   new ericrp.client.conversationmanager.messagesenteventhandler(process);

rpclient.conversationstarted += new _
   ericrp.client.conversationmanager.conversationstartedhandler(constarted);
   
rpclient.beginconversation();
}

rpclient 变量在类级别内有效,稍后会用到。我还设置了一些事件处理程序。

下一步,使用订单代理并配合 reliabilityinfo 类,发送一条可靠的信息。先创建 purchaseorderproxy 的实例,就象通常为 web 服务客户端所做的操作一样。再创建 reliabiltiyinfo 类的实例,将 conversationmanager 传送给构造函数,然后设置可靠性属性。需要特别注意的属性是 maxretry、expiredate 和 ackurl。maxretry 和 expiredate 用于限制消息的活动,防止它无限制地发送;web 服务将在向客户端发送接收确认时使用 ackurl。设置完这些属性后,即可设置代理的 reliableheader 属性并调用所需的方法。

private void sendmessage()
{
clientproxies.purchaseorderproxy po = new clientproxies.purchaseorderproxy();
         
   ericrp.reliabilityinfo rinfo = new ericrp.reliabilityinfo(rpclient);
   rinfo.status = reliabilityinfo.messagestatus.new;
   rinfo.senddate = system.datetime.now;
   rinfo.expiredate = system.datetime.now.addhours(4);
   rinfo.maxretry = 5;
   rinfo.ackurl = "http://localhost:8082/ericrpack/poack.asmx";
         
   po.reliableheader = rinfo;
   po.submitmessage("非常希望他们得到此订单!");
}

这是为了说明该功能而编写的一段客户端测试程序的屏幕快照。注意,我们一共发送了五条消息。第三条消息在到达目的地之前已过期,按照 ericrp 协议,这条消息将被丢弃,服务器不对其进行处理。第四条消息是无序消息,因为服务器并没有收到有效的第三条消息。在重新发送第三条消息之前,任何后续消息都是无序的。如果重新查询 client.conversationmanager,您将发现第五条消息也是无序的。



图 3:客户端测试程序

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表