`
Janne
  • 浏览: 44717 次
  • 性别: Icon_minigender_2
  • 来自: 成都
社区版块
存档分类
最新评论

Java的webservice优化

阅读更多

感觉http://www.ibm.com/developerworks/cn/webservices/1212_sunzg_java/1212_sunzg_java.html不错

 

做大数据库的B2C平台的webservice接口客户端(系统安装部署时会将数据库服务放在一台IBM服务器上,webservice接口客户端放在另一台IBM服务器上面。 )的问题及性能优化

 1.你要弄清楚你一个订单的数据量有多大,就是几M,几k这种概念。
 2.你两边的接口是局域网还是外网,网络质量怎么样?
 3.如果发送测试发现慢的话,你要知道你的瓶颈在哪。如是读慢,还是写慢?还是网络传输入的问题。

如果不是网络传输慢,是读写慢的话,就要用concurrent包的队列,用专门的读写线程就行了。就是从数据库不断抓数据放队列,然后线程不断取包发。

(使用WEBSERVICE那么你的WEBSERVICE接口要尽可能地简单,处理任务时间要短,当然要考虑WEBSERVICE的集群。
如果你不使用WEBSERVICE那么建议你使用长连接模式(你会用WEBSERVICE一般访问用户会比较固定)。WEBSERVICE的开销在于创建连接,其传输消耗并不会太大。)
 4.把一个批次的订单数据、文件(xml)先压缩后再传。根据我以前的经验,不管是文件,还是字符串都可 以压缩并进行base64,然后放到一个xml文件里。一个批次传一定量的订单,如1000个订单,而不要每次一条。(根据你一个订单的数据量定一个合理值)
 5.如果还不行,加大硬件力度。
 6.还是不行,就是webservice本身的问题了。直接ftp吧。

    7.可以采用异步模式,客户端发送消息过去即认为成功,减少调用方法等待时间。但需要服务端支持才可以。

 

Java Web 服务性能分析

从以上实例我们可以看到,Web 服务的调用与传统的 RPC 还是有较大差异的。最大的特点是调用双方使用 XML 格式的 SOAP 规范消息进行传输,这样以文本进行传输的好处是抛弃了私有协议,无论调用双方是何种平台,只要能够构造以及解析 XML 文本,并且存在双方都支持的传输协议,那么调用就成为了可能。而 XML 的日益规范以及 HTTP 协议的普及更是给这两个必要条件提供了坚强的后盾,Web 服务成为未来通用的服务提供标准已是不争的事实。

但是相信使用过 Web 服务的人都曾经经受过其性能不佳的窘境,原因为何我们结合刚才的实例可以分析出以下几点:

  • SOAP 文本消息转化导致效率低下

    从刚才的 TCP/IP Monitor 监测到的 request 以及 response 的消息我们可以看到,在发送消息时,我们传入了 Author 对象,在实际的调用发生时,这个 Author 对象会被转化成 XML 格式的 SOAP 消息,此消息在到达 Server 端会被解析并重新构造成 Server 端的 Author 对象。Response 也是同理,Books List 也会经历 XML 序列化和反序列化的过程。最糟糕的是,这种过程会在每一次调用的时候都会发生,这种构造以及解析的过程都会极大地消耗 CPU,造成资源的消耗。

  • SOAP 文本消息传输导致传输内容膨胀

    以 request 参数 Author 为例,必要的信息仅仅是"Bruce Eckel”这几个字节,但转化成 XML 消息后,可以从 SOAP 消息看到,多了很多 SOAP 规范的标签,这些信息会导致需要传输的内容急剧增大,几个字节很可能会变成几千字节。当调用频度和参数内容增多的时候,这种传输内容的膨胀将不是一个可以忽略的影响,它不但会吃掉网络的带宽,还会给 Server 的数据吞吐能力造成负担,后果可想而知。

  • 同步阻塞调用在某些情况下导致性能低下

    同步阻塞调用是指客户端在调用 Web 服务发送 request 后一直处于阻塞状态,客户端线程就会挂起,一直处于等待状态,不能进行其他任务的处理。这样就会造成线程的浪费,如果相应线程占用了一些资源,也不能够及时释放。

这个问题在纯客户端访问 Server 端的情况下并不明显,但如果是两个 Server 端之间进行 Web 服务调用的话,阻塞模式就会成为调用 Server 端的性能瓶颈。


Web 服务性能优化实践

使用异步方式调用 web 服务

先需要强调一点的是,这里的异步方式指的是客户端的异步,无论客户端是同步还是异步,都对服务端没有任何影响。我们期望的理想结果是:当客户端发送了调用请求后不必阻塞等待 server 端的返回结果。最新的 JAX-WS 标准中增加了这一异步调用的特性,更好的消息是,RSA 工具中也对 JAX-WS 的这一特性进行了支持,这样就极大地方便了我们进行异步调用客户端的创建。

其实讲客户端配置为异步模式极其简单,只要在 RSA 生成 Client 端代码时将‘ Enable asynchronous invocation for generated client ’ 选中即可 , 如下图 :

图 9. 异步客户端创建选项

图 9 异步客户端创建选项

这样在生成的客户端的 BookStoreSrvBeanService 中就会多了 qryBooksByAuthorAsync 的异步方法。既然是异步方法,回调 (Call Back) 就是必不可少的,在下面的异步客户端测试代码中可以看到匿名内部类作为回调 handler 的具体使用方法 :

图 10. 异步客户端调用示例代码

图 10 异步客户端调用示例代码

测试代码的输出结果如下:

图 11. 异步调用控制台输出

图 11 异步调用控制台输出

可以看到,当 Web 服务没有返回时,客户端仍然有机会做自己的输出 :“not done yet, can do something else...”。有些人可能会认为作为客户端此处的输出并无实际意义,但试想如果一个 server 作为客户端去访问一个 Web 服务,如果在服务等待期间能够有机会脱离阻塞状态执行自己需要的代码,甚至可以使用 wait 等方法释放被当前线程占用的资源,那么对于此 server 来说这将是一个对性能提升起到本质作用的因素。

使 web 服务支持批处理模式

  • 批处理模式简介

    批处理顾名思义是采用一次性处理多条事务的方式来取代一次一条事务的传统处理方式。Java Database Connectivty (JDBC) 中提供了大量的批处理 API 用于优化数据库操作性能,例如 Statement.executeBatch() 可以一次性接收并执行多条 SQL 语句。批处理思想可以方便的移植到 Web 服务调用场景以达到优化 Web 服务调用响应的目的。通过实际 Web 服务调用时间戳分析不难看出网络通讯是 Web 服务性能的瓶颈之一,因此通过减少网络通讯开销来优化 Web 服务性能,批处理模式是其中较为直接的一种实现方式。

  • 批处理模式适应性

    批处理模式虽然作用显著,但是也不适合所有场景。使用批处理模式处理 Web 服务请求时需要考虑一下几点:

    1. 不同 Web 服务执行时间差异性

      不同 Web 服务执行时间不尽相同,因此在同时处理多 Web 服务请求时需要考虑这种时间差异性。一般情况下是等待最长处理时间的 Web 服务执行完毕后汇总所有 Web 服务执行结果从而返回到客户端,因此存在批处理多 Web 服务反而比顺序单次调用 Web 服务消耗更长时间可能性。需要在采用批处理模式前对 Web 服务性能有清晰的了解,尽可能将性能参数相似的 Web 服务纳入批处理,而分别处理执行时间差异较大的 Web 服务。一般建议将性能差异在 30% 以内的多 Web 服务可以考虑纳入批处理。比方说 AccountWebService 中有一个获取用户账户列表的 Web 服务 getUserAccounts,这个 Web 服务执行需要 15 秒,另外 UserWebService 中有一个获取用户目前 pending 的待处理通知 getUserPendingNotifications,这个 Web 服务执行需要 2 秒时间,我们可以看到这两个 Web 服务执行时间差异较大,因此在这种情况下我们不建议将这两个 Web 服务纳入批处理。而 AccountWebService 中有一个增加第三方用户账号的 Web 服务 addThirdPartyNonHostAccount,该 Web 服务执行需要 3 秒,此时就就可以考虑能将 getUserPendingNotifications Web 服务和 addThirdPartyNonHostAccount 放在一个批处理中一次性调用处理。

    2. 不同 Web 服务业务相关性

      一般情况下建议考虑将存在业务相关性的多 Web 服务放入批处理中,只有业务存在相关性的多 Web 服务才会涉及到减少调用次数以提高应用系统性能的需求。比方说用户在增加第三方账号 addThirdPartyNonHostAccount 以后会默认自动发送一条 pending 的 notification 给用户用以提示用户来激活增加的账号,因此这种场景下可以完美的将 addThirdPartyNonHostAccount Web 服务和 getUserPendingNotifications Web 服务放入一个批处理中,在用户增加完三方账号后系统自动刷新 pending notification 区域以提示用户激活账号。UserWebService 中有一个获取用户主账号的 Web 服务 getUserHostAccounts 和获取用户三方账号的 Web 服务 getUserNonHostAccounts,MetaDataService 中有一个获取国家金融机构假期数据的 Web 服务 getFinacialAgencyHolidays,该 Web 服务明显和 getUserHostAccounts,getUserNonHostAccounts 不存在业务上相关性,因此不应该将它们纳入批处理。

    3. 尽量避免将存在依赖关系的多 Web 服务放入同一个批处理中

      将多个存在依赖关系的多 Web 服务放入同一批处理中需要专门考虑、处理多 Web 服务彼此间的依赖关系,进而无法将方便的这些 Web 服务并发执行而不得不串行执行有依赖关系的 Web 服务,最悲观情况下批处理响应时间将是批处理中所有 Web 服务串行执行时间和。原则上即使批处理中 Web 服务间存在依赖关系,通过动态指定依赖关系也可以实现多 Web 服务的批处理调用。但是这样将大大增加批处理实现的技术复杂性,因此不建议如此操作。

    4. 多线程方式处理批处理 Web 服务请求

      批处理模式在服务实现端一般通过多线程处理方法来并发处理多个 Web 服务调用请求。通过集中的解析器解析批处理模式请求,之后针对每一个 Web 服务调用会启动一个单独的线程来处理此 Web 请求,同时会有一个总的线程管理器来调度不同 Web 服务执行线程,监控线程执行进度等。在所有线程执行完成后汇总 Web 服务执行结果返回客户端。

  • 批处理实现方式

    批处理实现方式一般有两种:静态批处理模式,动态批处理模式:

    静态批处理模式实现较为简单,但是相对缺乏灵活性。静态批处理的核心思想就是在已有 Web 服务的基础上通过组合封装的方式来得到批处理的目的。举例来说将系统中已有的 Web 服务请求结构组合成一个新的数据对象模型作为 Web 服务批处理请求结构,在客户端进行批处理调用时通过初始化批处理请求数据对象,并将特定的 Web 服务请求对象赋值给批处理请求对象属性的方式。同理在服务实现端在生成批处理响应数据对象时也是通过将具体 Web 服务的响应组合起来生成并返回客户端。

    动态批处理模式实现较为复杂,但也能提供更大的操作灵活性。动态批处理模式一般需要应用采用 Java 反射 API 开发具有容器功能的批处理实现框架。客户端可以动态的向容器中增加 Web 服务调用请求,比方说客户端可以动态的将 addThirdPartyNonHostAccount,getUserPendingNotifications 两个 Web 服务加入到这个容器中然后发起一个框架提供的批处理 Web 服务调用请求。该批处理 Web 服务在实现端将解析容器并将其中的各个 Web 服务请求抽取解析并启动独立的线程来处理。

压缩 SOAP

当 Web Service SOAP 消息体比较大的时候,我们可以通过压缩 soap 来提高网络传输性能。通过 GZIP 压缩 SOAP 消息,得到二进制数据,然后把二进制数据作为附件传输。以前常规方法是把二进制数据 Base64 编码,但是 Base64 编码后的大小是二进制数据的 1.33 倍。辛苦压缩的,被 Base64 给抵消差不多了。是否可以直接传输二进制数据呢? JAX-WS 的 MTOM 是可以的,通过 HTTP 的 MIME 规范, SOAP message 可以字符,二进制混合。我们在 client 和 server 端各注册一个 handler 来处理压缩和解压。 由于压缩后的 SOAP 消息附件与消息体中的部分不是基于 MTOM 自动关联的,需要单独处理附件。在生成 client 端和 server 端代码的时候需要 enable MTOM。 Handler 具体代码在本文代码附件中, test.TestClientHanlder, test.TestServerHanlder。 写好了 handler 了之后还要为 service 注册 handler。

客户端 handler 样例代码如下:

客户端代码
 public boolean handleMessage(MessageContext arg0) { 
        SOAPMessageContext ct = (SOAPMessageContext) arg0; 
        boolean isRequestFlag = (Boolean) arg0 
                .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
        SOAPMessage msg = ct.getMessage(); 
        if (isRequestFlag) { 
            try { 
                SOAPBody body = msg.getSOAPBody(); 
                Node port = body.getChildNodes().item(0); 
                String portContent = port.toString(); 
                NodeList list = port.getChildNodes(); 
                for (int i = 0; i < list.getLength(); i++) { 
                    port.removeChild(list.item(i)); 
                } 
                ByteArrayOutputStream outArr = new ByteArrayOutputStream(); 
                GZIPOutputStream zip = new GZIPOutputStream(outArr); 
                zip.write(portContent.getBytes()); 
                zip.flush(); 
                zip.close(); 
                byte[] arr = outArr.toByteArray(); 
                TestDataSource ds = new TestDataSource(arr); 
                AttachmentPart attPart = msg.createAttachmentPart(); 
                attPart.setDataHandler(new DataHandler(ds)); 
                msg.addAttachmentPart(attPart); 
            } catch (SOAPException e) { 
                e.printStackTrace(); 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } 
        } 
        return true; 
    }

Web 服务端 handler 样例代码如下:

服务端代码
 public boolean handleMessage(MessageContext arg0) { 
        SOAPMessageContext ct = (SOAPMessageContext) arg0; 
        boolean isRequestFlag = (Boolean) arg0 
                .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); 
        SOAPMessage msg = ct.getMessage(); 
        if (!isRequestFlag) { 
            try { 
                Object obj = ct.get("Attachments"); 
                Attachments atts = (Attachments) obj; 
                List list = atts.getContentIDList(); 
                for (int i = 1; i < list.size(); i++) { 
                    String id = (String) list.get(i); 
                    DataHandler d = atts.getDataHandler(id); 
                    InputStream in = d.getInputStream(); 
                    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
                    GZIPInputStream zip = new GZIPInputStream(in); 
                    byte[] arr = new byte[1024]; 
                    int n = 0; 
                    while ((n = zip.read(arr)) > 0) { 
                        out.write(arr, 0, n); 
                    } 
                    Document doc = DocumentBuilderFactory.newInstance() 
                            .newDocumentBuilder() 
                            .parse(new ByteArrayInputStream(out.toByteArray())); 
                    SOAPBody body = msg.getSOAPBody(); 
                    Node port = body.getChildNodes().item(0); 
                    port.appendChild(doc.getFirstChild().getFirstChild()); 
                } 
            } catch (SOAPException e) { 
                e.printStackTrace(); 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } catch (SAXException e) { 
                e.printStackTrace(); 
            } catch (ParserConfigurationException e) { 
                e.printStackTrace(); 
            } 
        } 
        return true; 
    }

在 web.xml 中 service-ref 部分添加 handler. Server 端 handler 也是同样添加。

配置代码
     <handler-chains> 
            <handler-chain> 
                <handler> 
                    <handler-name>TestClientHandler</handler-name> 
                    <handler-class>test.TestClientHandler 
 </handler-class> 
                </handler> 
            </handler-chain> 
        </handler-chains>

结束语

以上三种解决方案是根据笔者的经验和分析,针对 Web 服务当前所面临的性能瓶颈进行提出的。并且,这几种解决方案在实际项目使用中都取得了比较好的效果。 综上所述, 在实际项目中,根据不同的需求采用上述方法中一个或者多个组合,可以使 Web 服务性能更加优化。

分享到:
评论

相关推荐

    c#调用Java webService的专题(一)

    本文将深入探讨如何使用C#调用Java WebService,这是实现.NET与Java平台间互操作性的一个重要方式。我们将首先理解WebService的基本概念,然后详细讲解C#中如何通过.NET Framework的SOAP客户端代理类来调用Java ...

    Java webservice cxf客户端调用demo和服务端

    Java WebService CXF客户端调用和服务端的实现是企业级应用程序中常见的通信方式,它基于标准的SOAP(Simple Object Access Protocol)协议,提供了一种在分布式环境中交换信息的方法。CXF是一个开源框架,它简化了...

    java版WebService生成客户端和服务端的实例

    在Java世界中,WebService是一种基于XML的开放标准技术,它允许不同系统间的应用程序进行通信,跨越不同的操作系统和编程语言。本实例将详细讲解如何使用Apache Axis1.4工具来生成Java版的WebService服务端和客户端...

    Java WebService大讲堂(1-10集,完整版)

    8. "异步调用WebService":介绍如何实现Web服务的异步调用,提高系统的并发处理能力,优化性能。 9. "编写Axis2模块(Module)":模块在Axis2中起着扩展作用,本集指导如何编写自定义模块,以增强Web服务的功能和定制...

    C#调用JavaWebService(客户端)

    - **调用服务方法**:通过代理类的对象调用JavaWebService中的公开方法,传入参数并接收返回值。 3. **处理数据类型**: C#和Java的数据类型可能会有所不同,比如Java的`Date`在C#中可能是`DateTime`。为了解决...

    myeclipse开发Java WebService.zip

    在IT行业中,开发Java WebService是一项常见的任务,用于构建可跨平台、跨应用程序的数据交换机制。MyEclipse作为一款强大的集成开发环境(IDE),为Java WebService的开发提供了便利。以下将详细介绍使用MyEclipse...

    Java Webservice Axis2 Client(含soapheader验证)

    总之,Java Webservice Axis2 Client的开发涉及到生成客户端代码、设置SOAP Header、调用服务和处理响应等多个步骤。了解这些概念和API对于构建安全、可靠的Web服务客户端至关重要。在实际项目中,确保遵循最佳实践...

    Java webservice服务动态配置

    Java WebService服务动态配置是Java开发中的一项重要技术,它允许开发者在运行时更改服务的行为,而无需重新编译或部署整个应用。这种灵活性对于应对不断变化的业务需求和优化服务性能至关重要。在这个主题中,我们...

    java+webService+tomcat+实例

    Java WebService与Tomcat是开发和部署Web服务的常用组合。WebService是一种基于标准的、平台无关的通信方式,允许不同的应用程序之间交换数据。Tomcat是一款轻量级的Java应用服务器,广泛用于部署Java Web应用程序,...

    JAVA webservice and android端

    【JAVA WebService与Android端交互】 在移动应用开发中,尤其是Android平台,与服务器进行数据交换是必不可少的。Java WebService,特别是基于RESTful架构的Web服务,为客户端(如Android应用程序)提供了灵活、轻量...

    javaWebService 关于讲解java调用webservice的知识

    Java WebService 是一种基于开放标准(如SOAP、WSDL和UDDI)的通信协议,用于构建分布式系统中的互操作性。它允许不同平台、语言和技术的系统之间交换数据和服务,实现了服务导向架构(SOA)的核心理念。在这个Java ...

    java+soap+webservice 调用模拟

    通过阅读提供的"java-soap-webservice"文档,你可以进一步了解具体的实现步骤,包括如何设置项目、配置JAX-WS、生成客户端代码、编写调用服务的代码,以及如何解析响应。实践中,不断动手操作和调试是掌握这一技术的...

    java webservice调试工具

    Java WebService调试工具是开发和测试基于Web Service应用程序的重要辅助工具。这些工具使得开发者能够方便地发现、调用和测试Web Service接口,从而确保服务的正确性和效率。在本文中,我们将深入探讨Web Service的...

    java android 调用webservice

    本篇将详细讲解如何在Android应用中使用Java调用Webservice。 一、理解Web服务 Web服务是一种基于互联网的、标准化的服务交互方式,它允许不同系统之间的应用程序共享数据和功能。常见的Web服务有SOAP(Simple ...

    Java写WebService客户端

    ### Java编写WebService客户端详解 #### 一、概述 在现代软件开发中,Web服务作为一种重要的技术手段被广泛应用于系统间的数据交互与通信。其中,基于Java的WebService客户端开发更是占据了重要地位。本文将通过...

    java调用C++ webservice

    本话题主要探讨如何使用Java调用由C++实现的Web服务(Webservice)。在给出的描述中,提到了通过WSDL(Web Services Description Language)文件来实现这一目标。以下是关于这个主题的详细知识点: 1. **Web服务...

    java的webservice服务端程序

    Java WebService服务端程序是一种基于Java技术实现的网络通信服务,它允许不同系统间的应用程序通过互联网进行交互。在本文中,我们将深入探讨Java WebService的核心概念、开发过程以及相关技术。 1. **WebService...

    java webService开发指南

    ### Java WebService开发指南知识点概览 #### 一、WebService简介 WebService是一种跨语言、跨平台的应用程序间通信协议。它允许运行在一个环境中的应用程序与运行在另一个完全不同的环境中的其他应用程序进行通信...

    SOA Using Java in Webservice

    【标题】"SOA Using Java in Webservice" 指的是使用Java技术在Web服务中实现面向服务架构(Service-Oriented Architecture, SOA)的一种方法。SOA是一种设计原则,它强调通过独立、可重用的服务来构建分布式系统,...

    javaWebservice代码与客户端

    Java WebService是一种基于标准的、平台无关的通信方式,它允许不同系统间的应用程序进行交互。在Java中,WebService主要通过SOAP(Simple Object Access Protocol)协议进行数据交换,使用WSDL(Web Services ...

Global site tag (gtag.js) - Google Analytics