理解Web服务的服务质量
理解Web服务的服务质量
--改善Web服务的性能
Anbazhagan Mani(manbazha@in.ibm.com),软件工程师,IBM Software
Labs,印度
Arun Nagarajan(anagaraj@in.ibm.com),软件工程师,IBM Global
Services,印度
2002 年 1 月
随着 Web 服务的广泛扩展,服务质量(quality of
service,QoS)将变成一个判定服务提供者是否成功的重要因素。QoS 决定服务的可用性和实用性,而这两方面都会影响到服务的普及。在本文中,我们将看一看各种
Web 服务 QoS 需求、影响 Web 服务性能的瓶颈、提高服务质量的方法、事务性服务以及一种使用服务代理测量 Web
服务响应时间的简单方法。
动态电子商务的前景要求在因特网上无缝集成业务流程、应用程序和 Web
服务。由于因特网的动态性和不可预知性,在因特网上提供 QoS
是一个至关重要且意义重大的挑战。特征和需求极其不同的应用程序都争用不足的网络资源。通信模式的变化、拒绝服务攻击、基础构造失效的影响、Web 协议的低性能以及
Web 上的安全性问题这些因素产生了对因特网 QoS 标准的需求。通常,未解决的 QoS 问题会导致重要的事务性应用程序遭受无法接受的性能下降。
随着 SOAP、UDDI 和 WSDL 之类的标准被所有主要的 Web 服务从事者采用,Web 服务的整个领域 — 包括金融服务、高科技和媒体以及娱乐领域目前都正在开发。由于大多数 Web 服务将需要建立并遵守标准,QoS 将变成这些服务的重要卖点和区分点。
QoS 涉及到一整套技术,这些技术根据可用的网络资源使服务请求者的需要与服务提供者的需要达成一致。谈到 QoS,我们指的是 Web 服务的非功能性属性,如性能、可靠性、可用性和安全性。
Web 服务的 QoS 需求
支持 Web 服务中的 QoS 的主要需求如下:
可用性:可用性是质量的一个方面,指 Web
服务是否存在或是否已就绪可供立即使用。可用性表示服务可用的可能性。较大的值表示服务一直可供使用,而较小的值表示无法预知在某个特定时刻服务是否可用。与可用性有关的还有修复时间(time-to-repair,TTR)。TTR
表示修复已经失效的服务要花费的时间。理想情况下,较小的 TTR 值是合乎需要的。
可访问性:可访问性是服务质量的一个方面,表示能够为 Web
服务请求提供服务的程度。它可以表示为一种可能性尺度,用来表示在某个时间点上成功地实例化服务的成功率或机会。Web
服务可用但却无法访问这种情形是可能存在的。可以通过构建一个可高度伸缩的系统使 Web
服务得到很高的可访问性。可伸缩性是指不管请求量如何变化,都能够始终如一地为请求服务的能力。
完整性:完整性是质量的一个方面,指 Web
服务如何维护交互相对于最初情况的正确性。 适当地执行 Web
服务事务会实现正确的交互。一个事务是指一系列将被当作单个工作单元的活动。要使事务成功,必须完成所有的活动。如果一个事务未完成,那么所做的全部更改都被回滚。
性能:性能是 Web 服务质量的一个方面,可以根据吞吐量和延迟对其进行测量。吞吐量的值较大且延迟的值较小表示 Web
服务性能良好。吞吐量表示在给定时间段内被服务的 Web 服务请求数。延迟是发送请求和接收响应之间的往返时间。
可靠性:可靠性是 Web
服务质量的一个方面,表示能够维护服务和服务质量的程度。每月或每年的失效次数是衡量 Web
服务可靠性的尺度。在另一种意义上,可靠性是指服务请求者和服务提供者发送和接收的消息的有保证和有序的传送。
常规性: 常规性是质量的一个方面,指
Web 服务与规则、法律一致,遵循标准和已建立的服务级别协议。Web 服务使用许多标准,例如 SOAP、UDDI 和
WSDL。要正确调用服务请求者请求的服务,就必须严格遵守服务提供者所提供的正确版本的标准(例如,SOAP 版本 1.2)。
安全性:安全性是 Web
服务质量的一个方面,通过验证涉及到的各方、对消息加密以及提供访问控制来提供机密性和不可抵赖性。由于 Web
服务调用是发生在公共的因特网上,安全性的重要性已经有所增加。根据服务请求者的不同,服务提供者可以用不同的方法来提供安全性,所提供的安全性也可以有不同的级别。
启用
QoS 的 Web 服务
接口定义(WSDL)为服务指定了语法说明,但在语义和非功能性方面没做任何指定。启用 QoS 的 Web
服务需要面向 Web 服务的一种独立的 QoS 语言来回答下列问题:
什么是预期的延迟?
什么是可接受的往返时间?
程序员在开发调用 Web 服务的应用程序时要能够理解
Web 服务的 QoS 特征。
理想情况下,启用 QoS 的 Web 服务平台应该能够支持许多种不同类型的应用程序:
有不同的 QoS 需求
使用不同类型的通信和计算资源
在考虑有
QoS 意识的 Web 服务时,我们假设使用关于 QoS
的语句扩展了接口规范,这些语句可以被关联到整个接口,也可关联到个别操作和属性。对于服务请求者来说,这些语句描述了所要求的 QoS,该 QoS
与客户所要求的服务有关,而从服务提供者的角度来说,这些语句描述了所提供的 QoS,该 QoS 与服务器对象所提供的服务有关。
IBM 设计出的 Web 服务体系结构包含一个名为“端点描述”的独立的层,来向服务描述添加额外的语义,如 QoS 属性。
QoS 协商与绑定的建立
在使用启用 QoS 的 Web
服务平台建立绑定期间,应该执行下列步骤:
服务请求者通过指定对 Web 服务接口的引用请求建立绑定。该请求还包含所要求的 QoS。
QoS 中介者在
UDDI 中搜索服务提供者。
QoS 中介者象下面描述的那样进行 QoS 协商。
Web 服务 QoS 中介者将所提供的 QoS
与所要求的 QoS 进行比较并使用其内部信息来确定一个约定的 QoS。这个过程被称为 QoS 协商。
如果 QoS
协商已经成功,则通知服务请求者和服务提供者协商已经成功,并且已经建立了一个绑定。从这个时刻起,这些对象就可以通过绑定进行交互了。
Web 服务的性能瓶颈
由于底层消息传递和传输协议的局限性,Web
服务会遇到性能瓶颈。然而,对公众普遍接受的协议(例如 HTTP 和 SOAP)的依赖却使它们成了必须承担的永久的负担。因此,理解这些局限性的工作方式就很重要。
HTTP
HTTP
是一种尽力而为的传输服务。它是一个无状态的数据转发机制,往往会产生两个主要问题:
不保证数据包会被传输到目的地。
不保证数据包到达的顺序。
如果无可用的带宽,那么数据包就会被简单地废弃。随着运行在网络上的用户和数据量的增加,带宽显然是一个瓶颈。习惯上,许多应用程序都假设零延迟和无限带宽。而且,习惯上应用程序使用同步消息传递。当您在自己的计算机上运行应用程序时,同步的消息传递是没什么问题的;组件通信的延迟以几毫秒计。但是,对于 Web 服务来说,它们是通过因特网进行通信,这意味着延迟要以几十、几百甚至几千微秒计。
虽然可以使用新设计的协议如“可靠 HTTP”(Reliable HTTP,HTTPR)、“块可扩展交换协议”(Blocks Extensible Exchange Protocol,BEEP)和“直接因特网消息封装”(Direct Internet Message Encapsulation,DIME),但这些用于 Web 服务传输的新协议(如 HTTPR 和 BEEP)的广泛采用还需要一些时间。因此,使用 Web 服务的应用程序设计人员在设计他们的系统时应该理解 Web 服务的性能问题,比如延迟和可用性。下面给出了一些改善 Web 服务性能的方法。
使用异步消息队列
依赖远程 Web
服务的应用程序可以使用消息排队来改善可靠性,但要以响应时间为代价。 一个企业内的应用程序和 Web 服务可以使用消息排队如“Java 消息传递服务”(Java
Messaging Service,JMS)或 IBM MQSeries 进行 Web
服务调用。企业消息传递为整个企业内的关键数据异步交换提供可靠、灵活的服务。 消息队列有两个主要优势:
它是异步的:一个消息传递服务提供者可以在消息到达时向请求者传递消息,请求者不必为接收消息而请求消息。
它是可靠的:消息传递服务可以确保一条消息被传递一次,且仅传递一次。
将来,因特网上的发布和订阅消息传递系统如 alphaWorks 上的 Utility Services 包可以用于 Web 服务调用(请参阅参考资料)。
专用 WAN 和 Web 服务网络
对于依赖对其任务关键的 Web
服务的企业来说,使用专用 WAN/企业外部网和 Web
服务网络是一个合适的选择。这些专用网提供较短的网络延迟、较少的拥塞、可靠传递和不可抵赖性。但是,对某些企业来说,拥有一个专用网是很昂贵的。
SOAP 和性能
SOAP 是 Web 服务实际上的有线协议。SOAP
性能由于以下原因而降低:
从 SOAP 数据包抽取 SOAP 信封(envelope)比较耗时。
使用 XML 解析器分析 SOAP
信封内包含的 XML 信息也很耗时。
XML 数据的优化可能性不太大。
SOAP 编码规则强制在所有发送和接收的 SOAP
消息中包含类型指定信息。
以 XML
可接受的格式对二进制数据进行编码会导致因编码而增加的额外字节的开销,还有执行编码/解码的处理器开销。
必须加载、实例化 XML 处理器,并为其提供 XML 数据。接下来必须发现方法调用参数信息。随着 XML 处理器为了支持更多的 XML 功能而发展,这会包括很多开销。
SOAP 性能中 XML 解析器的角色
大多数现有的 XML
解析器从代码规模、处理时间和内存占用来说都开销太大,因为这些解析器必须支持许多功能,如类型检查和转换、格式良好检查或者歧义解决。所有这些使得 XML
解析器需要更多的计算资源。一些应用程序可以考虑使用 XML 解析器的精简版,精简版的代码规模和内存占用都比较小。
另外,目前的大多数 SOAP 实现都是基于“文档对象模型”(Document Object Model,DOM)的。DOM 解析器分析消息的速度本来就慢。可以使用基于 SAX 的 SOAP 实现来增加吞吐量、减少内存开销并改善可伸缩性。
压缩 XML
SOAP 使用 XML 作为它的有效负载。如果我们考虑到数千条
SOAP 消息正在 Web 上传送, 那么网络带宽已经达到了极限。按 XML 的方法显示数据,数据大小通常会比以二进制格式显示相同的数据大得多,前者平均是后者的
400%。当必须快速传送消息时,消息大小的这种增长会产生一个很严重的问题,即它会导致数据传送时间的显著增加。一些应用程序设计应该考虑压缩的和高效的表示法。达到这一目标的其中一个方法是压缩
XML — 特别是当压缩所需要的 CPU 开销小于网络延迟时。
影响 Web 服务性能的其它因素
还有其它因素会影响 Web
服务性能,这些因素是 Web 服务应用程序无法控制的,比如:
Web 服务器的响应时间和可用性。
应用程序的最初执行时间,如 Web 应用程序服务器中 EJB/Servlet
的最初执行时 间。
后端数据库或旧系统的性能。
提供主动 Web 服务 QoS
的方法
通过使用各种不同的常见方法,如服务请求的高速缓存和负载平衡,服务提供者可以主动向服务请求者提供很高的 QoS。在 Web
服务器级别上和 Web 应用程序服务器级别上都可以完成高速缓存和负载平衡。负载平衡区分各种类型通信的优先次序,并确保适当地按照每个请求所表现出的商业价值对待它。
Web 服务提供者可以执行容量建模来创建一个请求流量、当前容量利用和结果 QoS 的自上而下的模型。服务提供者还可以根据通信量、不同应用程序服务类别的通信和来自不同来源的通信对 Web 服务通信进行分类。这将有助于理解为大量服务需求和将来的计划如对 Web 应用程序服务器和/或 Web 服务器进行负载平衡的容量和类型(例如,建立一个群集服务器站所需的服务器数目)提供好的 QoS 所需要的容量。
服务提供者可以通过使用容量模型来确定不同的客户和服务类型所需的容量以及通过确保不同应用程序和顾客的正确 QoS 级别来提供区别服务。例如,一个多媒体 Web 服务可能要求好的吞吐量,但一个银行 Web 服务可能要求安全性和事务性 QoS。
事务性 QoS
事务性 QoS 是指执行事务的可靠性和一致性级别。事务性 QoS
对于维护 Web
服务的完整性至关重要。事务对于业务流程保证一组相关的活动被当作一个工作单元并完成来说非常重要。如果执行事务时发生异常,就必须把事务恢复到一个一致的状态。这个属性被称为事务的“原子性”。除了原子性之外,从更严格的意义上来说,事务还应该满足一致性、孤立性和持久性等属性
。所有这四个属性被统称为“ACID”属性(请参阅旁注)。
事务的 ACID 属性
原子性(Atomicity):一个事务是处理过程的一个原子单元;要么执行整个事务,要么一点也不执行。
一致性(Consistency):事务的正确执行必须是使系统从一个一致的状态到另一个一致的状态。
孤立性(Isolation):在事务被提交之前,它的更新对其它事务应该是不可见的。也就是说,它应该自己运行,就象没有其它事务在运行一样。
持久性(Durability):一个事务一旦提交,所提交的更改必须在任何故障事件下都永不丢失。
提供事务性 QoS
的方法有下面几种。最流行的方法是“两阶段提交”,这种方法传统上用在 Web 应用程序体系结构中。“两阶段提交”提供了一个事务协调器,它根据这样一种思想来控制事务
— 不允许提交任何成分事务,除非它们能够全部提交。“Java 事务服务”(Java Transactional Service,JTS)、CORBA OTS
和大多数数据库管理系统中都使用这种使用事务协调器来确保原子性的方法。
但在我们考虑涉及到 Web 服务的事务时,还有一些新的复杂之处。特定的应用程序或 Web 服务所使用的 Web 服务不仅归不同的各方所有,还常在 Web 上被远程分发。考虑到事务协调器不具备对全部资源的完全控制能力,在 Web 服务环境中拥有一个中央事务协调器(它可以指定规则并执行提交和回滚)实现起来是非常乏味的。另外,“两阶段提交”协议还包括一种或其它形式的资源锁定。较长时间地锁定资源会导致严重的可伸缩性问题。因此,即使有可能使用,也要特别注意确保资源未被长时间锁定。
OASIS Business Transactions 技术委员会已经发布了“业务交易协议”(Business Transaction Protocol,BTP),该协议扩展了“两阶段提交”事务管理方法以满足使用 XML 在 Web 上交换数据的完全不同的贸易伙伴的需要。BTP 允许跨越多个企业的长期持久事务是正常 ACID 事务和非 ACID 事务(术语上称为“聚合”)。
另一种被称为“补偿”的方法是基于这样一种思想 — 一直允许提交事务,但在提交后可以取消它的影响和活动。例如,预定一次发货,如果还没开始所要求的发货流程,就可以取消这次发货。取消发货是补偿事务的一个示例;它补偿预定发货的最初事务。在补偿事务中,每个“真正的”事务都有一个相关联的“补偿”事务。 这个“补偿”事务元素描述了一种方法,这种方法是还原“真正的”事务造成的变化并返回到先前一致的状态。如果任何事务异常终止,调用者都会为先前提交的所有事务执行相应的补偿事务。与补偿事务相关的两个主要问题是:
与两阶段提交不同,补偿事务可能无法总是满足全部四个“ACID”属性 —
这意味着一直有失效的可能。
必须重新设计以前设计的两阶段提交事务来提供补偿方法。
Web Services ToolKit proxygen
“服务代理生成器”(Service Proxy Generator)工具可以用于创建可与 Web
服务交互的客户机代理。这个工具检查 WSDL 文档并生成可用于调用 Web 服务的 Java 编程语言类。这个工具是 WSDL 工具箱的一个部分。可以使用
proxygen 命令运行该工具。这个命令位于 WSTK_HOME/bin 目录中。这个命令有一个必需的输入参数。这个参数是 WSDL
服务描述文档的文件名。
测量 Web
服务响应时间的一个简单方法
通过在服务代理中添加一点额外的功能就可以开发一种测量 Web 服务性能特征的简单方法。Web
服务中的服务代理与 Java RMI 中的存根相似。它们包含特定于服务接口中的绑定的代码,从而对客户机隐藏了复杂的网络通信细节。例如,如果该绑定是一个 SOAP
绑定,那么服务代理将包含特定于 SOAP 的代码,这些代码可被客户机用来调用服务。
开发一个能够测量响应时间的代理包括如下步骤:
根据 WSDL 服务定义文件生成服务代理。
修改生成的服务代理,添加计时代码(请参阅清单
2)。
重新编译修改过的服务代理。
开发一个客户机程序来创建一个服务代理对象并调用必需的方法。
第一步:根据服务定义生成一个服务代理
一般情况下,服务代理不是由程序员写的。可以很容易地根据
WSDL 文件生成服务代理。Web Service Toolkit(包含 alphaWorks WSTK)提供生成服务代理的工具(请参阅旁注)。清单 1
中给出了 EchoService 的一个样本 WSDL 服务定义。这是一个简单的 Web 服务,它回显在末尾附加了一个“Hello”的原始字符串。
清单 1:一个简单 EchoService 的 WSDL 文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions
name="EchoService"
targetNamespace="http://www.echoserviceservice.com/EchoService-interface"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.echoserviceservice.com/EchoService"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<message name="InechoRequest">
<part
name="meth1_inType1" type="xsd:string"/>
</message>
<message
name="OutechoResponse">
<part name="meth1_outType"
type="xsd:string"/>
</message>
<portType
name="EchoService">
<operation
name="echo">
<input
message="InechoRequest"/>
<output
message="OutechoResponse"/>
</operation>
</portType>
<binding name="EchoServiceBinding"
type="EchoService">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="echo">
<soap:operation
soapAction="urn:echoservice-service"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:echoservice-service"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:echoservice-service" use="encoded"/>
</output>
</operation>
</binding>
<service
name="EchoService">
<documentation>IBM WSTK 2.0 generated
service definition file</documentation>
<port
binding="EchoServiceBinding" name="EchoServicePort">
<soap:address location="http://localhost:8080/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>
第 2
步:修改已生成的服务代理
即使机器生成的“服务代理”代码不应编辑,我们也不必太严格服从这个规则,可以添加几行代码。
这些添加的代码行实例化一个 Timer 对象以测量绑定到服务器和调用方法的时间。清单 2 中给出的样本代码对此进行了演示。
清单 2:修改过的服务代理(修改过的代码以红色显示)
import
java.net.*;
import java.util.*;
import org.apache.soap.*;
import
org.apache.soap.encoding.*;
import org.apache.soap.rpc.*;
import
org.apache.soap.util.xml.*;
import mytimer.Timer;
public class
EchoServiceProxy
{
private Call call = new Call();
private URL url = null;
private String SOAPActionURI = "";
private SOAPMappingRegistry smr = call.getSOAPMappingRegistry();
public EchoServiceProxy() throws MalformedURLException
{
call.setTargetObjectURI("urn:echoservice-service");
call.setEncodingStyleURI("http://schemas.xmlsoap.org/soap/encoding/");
this.url = new URL("http://localhost:8080/soap/servlet/rpcrouter");
this.SOAPActionURI =
"urn:echoservice-service";
}
public synchronized void
setEndPoint(URL url)
{
this.url = url;
}
public synchronized URL getEndPoint()
{
return url;
}
public synchronized
java.lang.String echo
(java.lang.String meth1_inType1)
throws SOAPException
{
if (url ==
null)
{
throw new
SOAPException(Constants.FAULT_CODE_CLIENT,
"A
URL must be specified via " +
"EchoServiceProxy.setEndPoint(URL).");
}
call.setMethodName("echo");
Vector
params = new Vector();
Parameter meth1_inType1Param = new
Parameter("meth1_inType1",
java.lang.String.class, meth1_inType1, null);
params.addElement(meth1_inType1Param);
call.setParams(params);
// Start a Timer
Timer
timer = new Timer();
timer.start();
Response resp = call.invoke(url, SOAPActionURI);
// Stop the Timer
timer.stop();
// Print the response time by calculating
the difference
System.out.println("Response Time = " +
timer.getDifference());
// Check the response.
if (resp.generatedFault())
{
Fault fault =
resp.getFault();
throw new
SOAPException(fault.getFaultCode(),
fault.getFaultString());
}
else
{
Parameter
retValue = resp.getReturnValue();
return
(java.lang.String)retValue.getValue();
}
}
}
第 3
步:重新编译修改过的服务代理
必须重新编译修改过的服务代理源文件,只要使用 javac 命令或其它任何编译器即可。
第 4
步:开发一个客户机程序
开发一个客户机应用程序,该应用程序可以使用服务代理来调用 Web 服务。它可以是一个简单的 Java
程序或一个基于 AWT/Swing 的 Java GUI 应用程序。
结束语
服务质量是企业对企业交易的一个重要条件,因此也是 Web
服务中的一个必需元素。 在 Web 服务应用程序的实现中需要满足各种 QoS 属性,比如可用性、可访问性、完整性、性能、可靠性、常规性和安全性。当您向 Web
服务加入事务性特征的需要时,属性会变得更加复杂。诸如 HTTP 和 SOAP 之类协议的一些局限性可能会阻碍 QoS 的实现,但有许多方法可以在 Web
服务中提供主动的 QoS。
参考资料
- 请参与本文的讨论论坛。
- “可靠 HTTP”(HTTPR)为 HTTP 实现了原子性。
- “块可扩展交换协议”(BEEP)还可将 Web 服务数据打包以便传送。
- 请阅读“直接因特网消息封装”(DIME)规范以理解 Web 服务中的数据编码。
- 了解更多关于 IBM Web 服务概念性体系结构的知识。
- 从 alphaWorks 下载 Web Services ToolKit。
- 了解更多关于“Java
消息传递服务”的知识。
- 了解更多关于 OASIS 组织的“业务交易协议”(BTP)的知识。
- 了解更多关于消息排队和 IBM MQSeries 的知识。
- 看一看 IBM 的出版物并订阅消息传递实用服务。
Anbazhagan Mani 是位于印度的 IBM Software Labs 的软件工程师。他有 WebSphere 系列工具、XML、Java 技术、BPM、工作流和对象技术这些方面的工作经验。最近,他一直致力于 Web 服务 QoS、P2P 计算和“业务流程集成”(Business Process Integration)。可以通过 manbazha@in.ibm.com 与他联系。
Arun Nagarajan 是位于印度的 IBM Global
Services 的软件工程师。他以前曾从事 XML 和 Java 技术如 JavaBeans、J2EE 和
WebSphere。目前,他一直在从事不同的 Web 服务技术如 SOAP、WSDL、UDDI 等等。可以通过 anagaraj@in.ibm.com 与他联系。
- 1Consuming a Web Service from a Win Form Application
- 2ITToolBox KM(by AMT整理)
- 3面向服务的应用集成——EAI和Web服务
- 4Web服务内幕,第10部分:深入主题:可靠性和事务
- 5面向21世纪的知识发展战略
- 6不同视角看石家庄OA信息化技术(by AMT 夏敬华)
- 7知识的经济学性质
- 8柴油机故障诊断专家系统知识库设计
- 9InterOP Stack新一代平台互操作技术:InterOP Stack技术概览
- 10XML Web Services Security
- 11OA办公系统的信息发布与管理门户介绍
- 12知识的过程管理
- 13TIBCO Web Service为OSS/BSS搭建强大平台
- 142008协同软件冰火之年:概念褪去 普及延伸
- 15A Web Services Primer
- 16Web服务的(革)创新,第4部分
- 17万宝:中国首个石家庄OA信息化的畅饮者
- 18关于资料收集的一些心得(by AMT 罗赞)
- 19理解Web服务的服务质量
- 20Web服务设计师,第6部分:基于付费的Web服务的催化剂
- 21知识地图在项目型组织中的应用
- 22Web服务的“租用”本质
- 23Web服务内幕,第6部分:承担责任--实现WSFL中的角色
- 24泛普软件石家庄OA信息化系统实施9大推进步骤
- 25IBM为Web服务安全 发布一系列有争议的API
- 26组织学习的五个子系统
- 27微软展示新版互联网服务MSN 8.0
- 28破解OA项目实施难题:建立项目实施与交付体系
- 29利用FrontPage来使用XML Web Service
- 30中国特色生态文明建设的理论创新和实践
成都公司:成都市成华区建设南路160号1层9号
重庆公司:重庆市江北区红旗河沟华创商务大厦18楼