zoukankan      html  css  js  c++  java
  • 提高 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 效率的提高进行了讨论。对于不同的应用系统,应该酌情分析系统建立的环境以及系统的使用人群和范围,以最终决定采用何种解决方案。

  • 相关阅读:
    【C++】<bits/stdc++.h>
    【网易】被3整除
    【TCP/IP详解】UDP:用户数据报协议
    【网易】牛牛找工作
    【C++】<numeric>中iota函数:递增序列填充

    今天好像找到C语言延迟输出的原因了
    C语言第2
    c语言新知
    glade No package 'libxml-2.0' found
  • 原文地址:https://www.cnblogs.com/BlogNetSpace/p/1236880.html
Copyright © 2011-2022 走看看