提高 Web Service 数据传输效率的基本方法

原文地址: http://www.ibm.com/developerworks/cn/webservices/0710_wangyun/index.html?ca=drs-tp4607&S_TACT=105AGX52&S_CMP=techcsdn

如何提高 Web Service 的数据传输效率及其应用场景

提高 Web Service 数据传输效率的基本方法
developerWorks
提高 Web Service 数据传输效率的基本方法
提高 Web Service 数据传输效率的基本方法
文档选项
提高 Web Service 数据传输效率的基本方法 将打印机的版面设置成横向打印模式

打印本页

提高 Web Service 数据传输效率的基本方法 将此页作为电子邮件发送

将此页作为电子邮件发送


级别: 中级

王 云 ([email protected]), 软件工程师, IBM 中国研发中心

2007 年 11 月 15 日

本文介绍了在 Web Service 实施和开发过程中,提高系统效率的一些方法,实践证明,这些方法都是非常有效且易于实现的。针对各种方法的优缺点以及应用场景,文章也进行了相应的讨论。

背景

Web Service 现如今已经成为 SOA 实现标准之一。很多公司已经或者正在参与到 Web Service 项目的实现和部署中。Web Service 的优点在于松散的处理异构系统之间的通信和数据交换,可以随机应变的处理企业各个系统之间的整合问题。但是同时,Web Service 采用 XML 标准进行系统间的数据传输,加大了传输的数据量,尤其是在传输一些具有比较严格结构的数据时,会使得传输效率有所下降。所以,如何提高 Web Service 传输效率成为很多公司进行项目部署时非常关心的问题。

目的

本文介绍了在 Web Service 实施和开发过程中,提高系统效率的一些方法,实践证明,这些方法都是非常有效且易于实现的。不同的方法都有其应用领域和优缺点,我们会分别进行讨论。文章的主要目的在于,提供给读者多种方式的基本解决方案,使得读者在 Web Service 项目部署时,拥有更多的思路。

原因分析

Web Service 是采用 XML 标准进行数据传输的。XML 在传输过程中,会附带很多数据的相关信息,并以标签的形式表现出来。在传输过程中,一些情况下,这些标签会占用一半以上甚至更多的数据传输量,例如,要传输一个表格信息,如下(表格中的人名为虚构的):


表 1. 将要进行传输的表格示例
Name City Apartment
Air Wang Beijing Some Place

表 1 中的数据在传输过程中,有可能会生成下面的 XML 文件:
清单 1. 对应于表 1 数据所传输的 XML 文件示例


                        <Heading>

                        <column> Name</column>

                        <column>City</column>

                        <column>Apartment</column>

                        </Heading>

                        <Data Grid>

                        <row>

                        <column>Air Wang</column>

                        <column>Beijing</column>

                        <column>IBM CDL</column>

                        </row>

                        </Data Grid>

                        

如果上面的表格中还带有格式的信息(比如字体,背景颜色等等)的话,那么相应的 XML 就会更加复杂了。从上述 XML 中我们可以看出,除了数据之外,XML 会附加很多标签信息,这就使得传输的数据量增大,当所需要传输的数据比较多的时候,XML的标签就会带来比较大的效率问题。

解决方案一: 压缩与解压缩

Web Service 在网络中传输的是以 XML 为基础的消息的请求和响应。大量的数据传输会使网络成为瓶颈。一个最直接的解决方案就是对传输的消息进行压缩。对于不同规模的数据量,压缩应该有不同的解决方案,下面分别介绍如下:

1. 对于整个 XML 传输文件进行压缩
数据压缩已经发展了很多年,有很多成熟的技术,算法以及工具包。经常用于对数据压缩的 API 有 gzip 等方式。对文件进行压缩的做法非常简单,就是在发送 XML 之前对 XML 进行压缩,经过压缩以后,再在 XML 接收端对已经压缩的文件进行解压缩。
优点:
该方法的优点在于,使用了成熟的压缩和解压缩技术,当数据量比较大的时候,可以大大提高传输效率。对于纯文本的 XML,压缩可以减少其80%以上的体积。
缺点:
压缩和解压缩虽然可以使得 XML 的体积大大减少,但是其过程却是十分耗费系统资源的。压缩和解压缩往往会具有很大的 CPU 占有率以及内存占有率。对于配置不高的客户端甚至是服务器端,都会造成不小的压力。
应用场景:
该技术应用于网络瓶颈非常严重的情况或是主机配置比较高的情况。
举例:
正如本小节最开始已经介绍的,现在已经有很多成熟的压缩与解压缩的 API 提供给开发人员进行使用,我们选取其中最常用的 gzip 方式举例说明。一般来讲,系统请求 XML 的体积相对较小,没有必要使用压缩和解压缩的方法处理请求 XML。而对于系统响应 XML 来讲,一般都包含大量的数据,导致其体积庞大,需要进行压缩处理。对响应 XML 进行压缩的流程如下:
服务器端数据模型-->序列化操作-->利用 gzip 方式对序列化后的 XML 进行压缩-->返回到客户端-->以 gzip 方式进行解压缩-->对解压缩后的 XML 进行反序列化操作-->客户端数据模型
这里需要说明的一点是,客户端以及服务器端的数据模型需要实现 Serializable 接口。
清单 2. gzip 方式压缩部分实现代码示例(java 实现)


                        import java.io.*;

                        import java.util.zip.*;

                        public class Compress

                        {

                        public String gzip(OutputStream pStream)

                        {

                        …

                        try

                        {

                        GZIPOutputStream stream = new GZIPOutputStream(pStream);

                        return stream.toString();

                        }catch(IOException e){…}

                        …

                        return null;

                        }

                        …

                        }

                        

在程序将对象模型序列化成 XML 之前,可以使用上面的压缩方法,对数据流进行压缩。部分代码如下:
清单 3. 对象模型序列化后再进行压缩的实现代码示例


                        public class XMLSerializerHelper

                        {

                        …

                        public static String saveOBJtoString(Object inputOBJ) throws ConverException

                        {

                        ……

                        ByteArrayOutputStream outputStream = null;

                        try{

                        outputStream = new java.io.ByteArrayOutputStream();

                        m_serializer.save((IXMLSerializable) inputObject, outputStream);

                        return Compress.gzip(outputStream);

                        }catch(Exception e){…}

                        ……

                        }

                        …

                        }

                        

解压缩的过程也类似于上述代码。测试表明,采用 gzip 压缩可以减少60%以上的网络所带来的消耗。

2. 对于特定的数据进行特殊的处理
在企业日常的数据传输中,往往大量的数据具有很多共同的特点。数据和数据之间往往具有很多相同的地方,或者说,具有很多重复的地方。例如,在一个以 Web Service 为构架的报表处理系统中,报表往往会含有很多的空数据,或者相同属性和值域的数据,对于这样的情况,可以在代码中对特殊情况进行特殊的处理。我们同样以传输一个表格作为例子,如下:


表 2. 将要传输的含有多个空值的表格示例
Software sold Hardware sold System sold Others
120 - - -
- - 90 -
- 110 - -

可以看到,上述表格具有很多的空值,那么在 XML 中完全可以把空值的部分统一处理,这样就能大大减少网络传输的数量,其对应的部分 XML 如下:
清单 4. 对空值进行处理后的简化 XML 示例


                        ……

                        <NULL Value>(1,2),(1,3),(1,4),(2,1),(2,2),(2,4)(3,1),(3,3),(3,4)</NULL Value>

                        ……

                        

优点:
对于重复性的数据来说,该方法可以几十倍甚至上百倍的减少传输的数据量(这取决于数据重复的数量大小),相对于第一种压缩方式,由于只是对固定形式的数据进行处理,所以不会占用很大的 CPU 以及内存。
缺点:
数据的特点不容易把握,能够处理的情况比较简单和单一。对于空值或者某些值重复较多的情况,可以采用本方法。

解决方案二: 减少多次调用,尽量使用一次性的调用方式。

传统的 RPC 调用,在多次使用的时候会产生很大的效率问题。用户在进行每次远程调用的时候都要等待网络传输所耗费的时间。而对于 Web Service 来讲,很多用户仍然将其作为传统的 RPC 来进行调用。每次都调用 Web Service Provider 所提供的函数,造成了效率的极大浪费。Web Service 的一大特点在于,可以在本地进行一次性的设置,再把生成的 XML 统一的发送给服务的另外一端。对于用户来讲,所有的设置工作都是在本地进行的,用户完全感觉不到网络所带来的瓶颈,而在最后的数据传输过程中,多消耗一些时间也是值得的。
应用场景:
对于同用户交互的情况,尽可能使用这样的处理,即减少多次的远程调用,尽量使得程序仅需完成一次调用。举一个简单的例子来说明问题:在一个用户界面上(User Interface),需要进行很多的设置,而这些设置的每一步都是需要进行远程调用的,这样对于用户来说,就会在每一次的设置过程中都等待网络传输所耗费的时间。而对于 Web Service 而言,客户端所有的工作就是生成请求 XML,所有的设置工作都可以统一生成一份 XML 文件,然后将其传送给服务器端,这样一来,用户只用等待一次的数据传输时间(可能相对时间较长,但是用户只用等待一次,还是值得的),而其他的工作都在服务器端进行处理。
优点:
所有数据操作在本地进行,用户在处理数据时不会感到网络所带来的停顿。最终所有操作请求统一发送给服务器端,使得原本多次等待的远程操作只需要一次数据传输就能完成。
举例:
下面的两幅图(图 1 和图 2)是某数据导入向导中的两个步骤,用户通过界面设置数据库以及数据表的信息,从而得到目的数据。


图 1. 数据导入设置向导示例一
数据导入向导示例图

图 2. 数据导入设置向导示例二
数据导入向导示例图

很多初学者容易进入的一个误区是在数据库选择以后,在程序中直接连接数据库,通过用户提供的用户密码建立数据库连接,然后在后续的每一个步骤中(如图中的设定数据表条件)都进行远程函数调用,以至于用户每一次点击向导中的“下一步”按钮时都会感觉到网络带来的瓶颈,例如停顿感,或者更严重的程序一段时间的没有响应等等。事实上,对于 Web Service 来讲,每一步都可以对请求 XML 进行设置(这种设置是在本地进行的),当所有步骤都完成以后,再将 XML 统一发送给服务器端进行处理。这样一来,用户在每一步之间的操作都是在本地进行的,不会带来多余的网络响应等待时间,使得整个向导的设置工作能够很快的进行。而最后一步完成以后,用户对于网络的一次性等待是相对值得的。在这个例子中,请求XML的部分结构如下:
清单 5. 客户端进行数据导入设置的 XML 示例


                        ……

                        <Data Retrieving>

                        <Database>

                        <Type>Toolbox</Type>

                        <Pattern>TCP/IP</Pattern>

                        <UserName>Wang Yun</UserName>

                        </Password>

                        </Database>

                        <Table>

                        <Condition method=’more than’ value=’table’ >2500</Condition>

                        <Condition method=’equal to’ value=’table’>Wang Yun</Condition>

                        <Condition method=’less than’ value=’table’>10 days</Condition>

                        </Table>

                        <Data Retrieving>

                        ……

                        

系统客户端对 XML 进行设置的部分示例代码如下(将对象模型序列化的过程,仅列出 Database 节点):
清单 6. 对象模型序列化成 XML 示例


                        public class DataBaseLoginOBJ

                        {

                        …

                        public Element persistToXML(DataObject pOBJ)

                        {

                        …

                        Element dbElement = pOBJ.createElement(“Database”);

                        Element typeElement = pOBJ.createElement(“Type”);

                        Element patternElement = pOBJ.createElement(“Pattern”);

                        Element userElement = pOBJ.createElement(“UserName”);

                        Element pwdElement = pOBJ.createElement(“Password”);

                        dbElement.appendChild(typeElement);

                        dbElement.appendChild(patternElement);

                        dbElement.appendChild(userElement);

                        dbElement.appendChild(pwdElement);

                        …

                        }

                        …

                        }

                        

DataObject实现了org.w3c.dom.Document的接口, Element实现了org.w3c.dom.Element接口。在完成了整个请求XML的设置之后,就将其统一传输至服务器端进行处理。

解决方案三: XML 解析器的选择和优化

现在软件领域有很多种类的 XML 解析器,最基本的方式有两种:DOM 和 SAX。对于不同级别的XML文件,应该使用不同的解析器。有关 XML 解析器的介绍,请参考其他相关文档。下面列出他们使用的场景以及优缺点:


表 3. SAX 与 DOM 解析方式的基本比较
种类 优点 缺点 使用场景
DOM 1.XML树在内存中完整存储,因此可以直接修改其数据和结构。 2.可以通过该解析器随时访问XML树中的任何一个节点。 3.DOM解析器的API在使用上也相对比较简单。 如果XML文档体积比较大时,将文档读入内存是非常消耗系统资源的。 DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。DOM 是以层次结构组织的节点的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能进行任何工作。DOM是基于对象层次结构的。
SAX SAX 对内存的要求比较低,因为它让开发人员自己来决定所要处理的标签。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现。 用SAX方式进行XML解析时,需要顺序执行,所以很难访问到同一文档中的不同数据。此外,在基于该方式的解析编码过程也相对复杂。 对于含有数据量十分巨大,而又不用对文档的所有数据进行遍历或者分析的时候,使用该方法十分有效。该方法不用将整个文档读入内存,而只需读取到程序所需的文档标签处即可。

正确的选择XML解析器的种类,对于Web Service系统的效率会有很大的帮助。现在有很多厂家提供了基于这两种类型的很多XML解析器,在选择的时候,应该仔细阅读说明文档,慎重进行选择。另外,往往在一个系统中可以同时使用这两种方式,以达到解析的最高效率。一般来讲,对于请求XML可以采用DOM的解析方式进行解析,而对于响应XML可以使用SAX的方式进行解析。

解决方案四: 简化标签

我们知道,Web Service 解决方案在网络中传输 XML 具有比较复杂的结构。在传输过程中,不仅仅必要的数据被发送和接收,同时也会由于 XML 的结构过于冗杂而附加了更多的信息进行传输。举例如下:
系统客户端从服务器端得到的返回数据的响应 XML 结构如下:
清单 7. 在网络中传输的表格数据对应的 XML


                        <Cells>

                        <Heading Cells>

                        <Column>

                        <Row> Data </Row>

                        </Column>

                        <Column>

                        <Row/>

                        </Column>

                        …

                        </Heading Cells>

                        <DataGrid Cells>

                        …

                        </DataGrid Cells>

                        </Cells>

                        

由上面的 XML 我们可以看出,每一个返回数值,都至少有 <Column>, </Column>, <Row>, </Row> 来标识它,也就是说,如果我们要传输一个表格,那么表格中每一个数据都要伴随传输相应的这四个标签。假设表格中的每一个数据的字节数为8,那么标签所带来的附加字节就将近为数据的4倍。如果要传输的数据量十分巨大的话,效率自然会降低许多。所以我们可以采用一种十分简单的方式,有效的减少XML所带来的附加字节数,即简化XML标签。可以将上面所说的XML改写成下面的格式:
清单 8. 对应于清单 7 的简化后的 XML


                        <Cells>

                        <Heading Cells>

                        <C>

                        <R> Data </R>

                        </C>

                        <C>

                        <R/>

                        </C>

                        …

                        </Heading Cells>

                        <DataGrid Cells>

                        …

                        </DataGrid Cells>

                        </Cells>

                        

优点:
测试证明,采用这样的改进方式,可以使得整个系统的效率提高近一倍甚至更多。而且这样的处理方式简单易行,只是修改标签就可以了。
缺点:
使XML自身代表的意义变得不那么容易读懂,弥补的方式是一般会有一个对照表,来说明具体简化后的 XML 文件的含义。
举例:
该方法比较简单直观,这里列出对照表的一个例子如下:


表 4. 简化前后 XML 的对照表及其含义
简化前标签 简化后标签 含义
Row R 表示表格中的行
Column C 表示表格中的列
... ... ...

类似上面这样的声明表格应该作为文档提供给用户。

应用场景:
这里需要说明一点,XML 能够清晰的表示出整个数据结构,而很多软件开发人员往往希望利用 XML 来观察数据的情况,而标签就是协助他们更好的完成这样的工作。所以,一般来讲,标签需要尽可能的有意义,由于 C 和 R 可以比较明确的表示 Column 和 Row,并且他们在数据传输过程中是重复的最多的(占传输标签总数的80%),所以我们进行了上述的改动。但是对于像 Cells 这样的标签,由于其重复率不是很高,而且我们需要这个标签具有字面上的意义,所以,类似于这样的情况,我们给予保留。

解决方案五: 缓存机制

前面介绍的四种提高效率的方法都是基于 XML 传输的,也就是说,都是在如何提高 XML 传输效率上进行介绍的。而第五种机制对于任何的软件解决方案都适用,而对于 Web Service 解决方案来讲,更是具有锦上添花的作用。缓存机制最通用的一个思想是,将使用次数比较多的数据缓存起来,如果再有相同请求时,就将缓存中的数据返回。这样会减少数据逻辑处理所带来的时间。我们以用户的一次刷新数据的操作为例,介绍一种比较通用的缓存方式,如图:


图 3. 某数据刷新操作的缓存流程
某数据刷新操作的缓存流程

由图中可知,当用户进行刷新操作时,服务器端先检查请求 XML,取出要刷新数据源的 CUID。根据该 CUID,系统检查在缓存中是否存在该 CUID 对应的数据对象,如果有,则取出其刷新状态,并与对应该 CUID 的数据源的刷新状态进行比较。如果比较一致,则直接返回数据给客户端,如果比较不一致,则需要打开数据源进行重新刷新,并将刷新以后的结果集的对象保存在缓存中。如果缓存已经满了,则利用最近最少使用原则,清除缓存中的一部分数据对象。另外,缓存的大小设置是可以通过属性文件进行设置的,在程序中,对缓存进行初始化时,首先读取了属性文件来进行缓存大小的设定。缓存数据的好处在于,在对数据进行多次重复刷新时,系统不需要重新打开数据源(有时候连接并打开数据源是非常消耗时间的),从而提高了系统的效率。
优点:
对于多次的相同方式的数据操作,数据直接从缓存返回,可以很大程度的提高系统效率。
缺点:
编程的工作量比较大,需要测试的部分比较多。
应用场景:
一般的 Web Service 部署程序都可以采用缓存机制的处理。

其他解决方案

对于 Web Service 服务器,各个厂商都提供了很多服务器设置,以提高 Web Service 的性能和效率。具体请参考相关服务器的文档。

小结

对于提高 Web Service 的效率,本文给出了一些解决方案,从各个不同方面对 Web Service 效率的提高进行了讨论。对于不同的应用系统,应该酌情分析系统建立的环境以及系统的使用人群和范围,以最终决定采用何种解决方案。



参考资料



关于作者

提高 Web Service 数据传输效率的基本方法

本文作者: 王云

提高 Web Service 数据传输效率的基本方法

作者王云是 IBM DB2 for iSeries 项目组的软件工程师,他对 DB2, SOA 以及商务智能的解决方案有比较深入的理解。他的写作经历大多相关于商务智能以及 SOA 的解决方案


原文地址: http://www.ibm.com/developerworks/cn/webservices/0710_wangyun/index.html?ca=drs-tp4607&S_TACT=105AGX52&S_CMP=techcsdn

你可能感兴趣的:(web Service)