Author:放翁(文初)
Date: 2010/4/14
Email:fangweng@taobao.com
缘起
早在两年前做开放平台的时候,由于平台的特质,就开始寻求对于Web请求异步的解决方案,当时Jetty和Tomcat都在最新的版本中集成类似于Comet和Asyn Process的功能,但经过测试,效果不佳,因此也没有再深入去了解其中的一些设计理念。时隔两年,依然在做开放平台,但当研究twitter和facebook api的时候,发现已经有了Streaming 模式的Web请求处理模式,由此又再次的去了解今天,在Servlet3规范已经逐渐成熟的情况下,容器,开源项目对于Web请求的异步化是否已经有了很大的提高。在我看来,传统的Web Container要改造成为异步模式要解决内在和外在两方面问题,内在需要将那么多年的成熟体系打破,以分阶段,异步化的方式来利用现有的功能(异步化很大问题就是复杂了流程,包括对多任务多线程的协调,对资源的分配和回收等等),外在就是要让用户如何能够在最小的代价下移植到异步模式的场景(如果代价很大,那么就很难在已有系统上推广,同时使用的学习曲线也是推动新技术的一项很重要的指标)。闲话不多说,后续会从概念,到具体的概念实现,最后到实际测试,给一个完整的评估。目标很明确,最基本要学会设计中的一些好的思想,如果能够找到使用场景就尝试使用,最终在具体场景下改造现有系统比对效果。
Comet & Async Request Process
概念
Comet和Async Request Process的技术已经不算是什么新鲜事物了,但是真正在后台业务体系中大量使用其实还不多,主要原因还是现在成熟的Web容器都是基于servlet 2.5实现,遵循的也是标准的Http无状态应答式请求处理模式。但随着互联网应用不断发展,时刻都以人为本的情况下,如何让用户体验不断提升,就要求能够在很多场景尽量减少交互延时,尽量多的有人性化的展现(更多的数据交互)。因此,Comet和Async Request Process的应用场景就诞生了,这里我只是说应用场景诞生了,也表明其实传统的应答式请求处理模式在很多场景还是有他的优势。
Comet中文如果直译叫做彗星,其实是比较形象的一种说法。Comet在某些场景下也被叫做Http Streaming。Comet作为一种技术手段,其实是指在客户端和服务端建立连接后,可以由服务端主动发起请求将数据推送给客户端,而客户端根据推送的数据增量迭代的更新展示。因此服务端的数据推送就好比彗星一样不定时的传送到了客户端。
Async Request Process也可以被叫做long polling,表示异步请求处理。Async Request Process和传统的Http请求的差别就和BIO与NIO差别类似。Web容器或者传统的Socket应用在处理请求的时候,通常都是One Connection One Thread来处理,申请资源的回收速度根据业务处理来决定,如果后端处理的慢,那么在连接输入和输出部分的资源就会闲置而导致浪费(input buffer 和 output buffer),通过Selector和事件模型可以将流程切割成为更细的任务阶段,提高资源利用率。
优缺点及应用场景
在Servlet3规范中已经将Comet和ARP(Async Request Process)都作为基本内容涵盖在内,很多支持servlet3的容器也都已经支持了这些特性,后面会具体的谈到。但是这些特性其实也是在一些特定场景下才会体现出其价值,同时也存在着自身的不足之处。
Comet与传统的处理模式最大的特点就在于http通道的长连接和服务端主动推送,基于事件模型。对于客户端频繁要去获取状态数据或者消息数据的场景下,通过传统的请求方式来轮询会极大消耗服务端的资源(带宽和业务处理能力),同时反复建立数据连接也会造成服务端和客户端性能的消耗。但另一方面,其实这两个特点也会成为缺点,保持长连接会导致大量的连接资源消耗(如果没有数据传输的话),另一方面服务端如果数据推送过于频繁,会导致客户端崩溃。
对于Comet和传统Http请求处理的取舍,需要考虑这些因素:
1. 是否是单个客户端反复需要请求服务端获取数据或者状态的场景。是则继续2的判断,否则考虑使用传统的方式。
2. 客户端数目多少。如果客户端数目不多,则直接采用Comet,否则考虑第三点。
3. 单个客户端对于服务端请求的频度。(主要是由服务端数据状态变化的频度来决定),频度高,则考虑才用Comet,因为如果频度高,那么长连接的利用率就会高,则长连接带来的消耗就可以忽略。
对于服务端数据推送过多导致客户端崩溃,可以通过在服务端做数据合并或者在客户端丢弃数据的方式来提升性能。(建议在服务端处理,减少带宽和两方的性能消耗)
最后就是Comet的编程模型基于事件模式和Http长连接,那么首先需要选择新版本的容器,例如Tomcat7或者jetty6以上或者glassfish的新版本,其次服务端开发需要符合事件模型驱动的设计,客户端也需要支持长连接的数据增量推送处理和展示。另一方面确保你的网络方面在做LB的时候不会由于Http长连接过多导致LB性能大幅度下降,同时客户端网络如果质量不好也会间接导致服务端Load上升。
Async Request Process的特点在于长连接和类似于NIO的设计理念,将服务请求处理过程更加细化,基于事件模型驱动和Selector的方式,提高了高并发下的服务处理能力,同时也在资源管理方面提供了更多的优化空间。ARP在不同的容器中或者开源项目中实现的细节都有可能不同,特别是对于请求的挂起,唤醒,终止,对于资源的分配,回收,都有自己的优化和设计思路,后续再介绍Jetty的Continuation会谈到它的一些设计理念。在一定程度上Comet设计是包含了ARP的,ARP只负责一次请求的交互。ARP的优势就在于能够最大限度优化容器或者Socket连接处理能力,优化资源分配,提高并发处理能力。劣势在于编程习惯不符合常规的模式,对框架的要求高(异步协同,线程和资源管理等,由此带来的复杂度会导致可用性会受到影响)。
对于ARP和传统Http请求处理的取舍,需要考虑这些因素:
1. 是否是高并发应用。不是则选择传统方式,是则考虑第二点。
2. 服务处理时间较长或者不确定。如果处理时间很短,业务逻辑极为简单,则选择传统方式,否则考虑第三点。
3. 瓶颈是否在后端,优化前端处理能力是否会产生反效果。如果后端处理能力强,前端是瓶颈,则选择ARP,如果后端已经到了无可优化的地步,则考虑采用传统方式。
今天很多人没有去使用ARP方式,一方面是容器的不成熟,其次也是因为当前前端不是瓶颈,而且靠堆机器很容易解决问题,而后端例如数据库,存储成为了瓶颈,因此前端优化反而会将水流放的更多,导致后端在没有优化或者无法优化的情况下瓶颈劣势显示的更加突出。因此优化系统不是对局部的优化,而是对整个系统自下而上的优化,任何一个关键路径成为瓶颈,那么其他的优化都失去意义。
这里也实际的举两个例子来说明TOP在那些实现中需要用到Comet和ARP。
ARP的两个应用场景:
TOP最大的一个难点就是服务的隔离问题,所有的淘宝服务无差别的被集成在TOP的服务集群中,TOP的一个基本功能就是Proxy,由于不同服务的处理能力不同,响应时间也是不同,对于图片上传类服务处理速度可能平均要到300ms,而对于普通的请求可能就只需要几ms,而对于容器连接资源的申请却都是一样的,一个Request对应一个Thread去处理,当后端某个服务出现问题或者响应较慢的时候,那么会导致容器的连接资源被大量hold,最后影响到其他服务的正常中转。这里回顾我刚才谈到使用ARP的几个判断点,首先需要处理大并发的情况(当前每天3亿多次api的服务call,到年底估计会有10亿左右的call),其次后端服务处理时间是不定的,有些长有些短,有些根据服务当前所处压力而不同,最后平台的服务由于单个问题而影响全部,其实表明后端服务能力其实不是瓶颈(当然对于出现问题的服务会采取降级和保护的措施,在没有实施保护的时候需要能够继续提供对于其他正常服务的中转)。
TOP的请求处理流程其实可以分成很多个Pipe,有安全的Pipe,有业务预处理Pipe,有业务转发Pipe,有业务后处理Pipe等等,其中参数的解析和处理及业务转发等待回应是最消耗的两个Pipe,参数解析当前通过lazy读取stream来减少错误请求对于内存的消耗(这同jetty的一个设计类似),对于业务中转及等待回应的过程其实可以作为一个异步的事件交由服务框架处理,而将请求接收处理线程挂起,释放掉必要的资源(输入输出缓冲),提高整体处理能力。
Comet的应用场景:
对于很多大商家需要能够比较及时的了解当前的交易处理状况和订单情况,因此需要有API能够支持这样的场景。最初采用类似于notify的方式去实现,但是在实施的过程中发现,外部服务notify的成本过高(服务回调地址的接收能力及可用性较差,服务端的资源大量消耗),最后修改成为客户端有限制的定期轮询获取增量数据。其实,现在外部宣称很多对外的http方式的notify都不是很靠谱,也有类似于pubsubhubbub的方式,但其实这也增加了一层订阅关系的中转和维护的成本。如果采用Comet的方式,一来可以节省大量轮询带来的开销,同时复用长连接可以减少外部连接产生的通信消耗,在加上对数据推送的优化合并,在一定程度上可以实现外部数据推送的场景。
同样还有在产品推广的业务上,当很多外部店铺推广一款商品时候,如果商品发生了变化需要能够告知推广的应用插件,如果靠轮询会给TOP带来不小的压力,因此通过修改事件触发Comet事件来更新商品推广信息。
外部开源实现
外部有很多项目实现了Comet和ARP,这里就举出其中一部分:
Web容器:
Jetty 6以上的版本(Continuation),Tomcat 6以上,JBoss配置resteasy,glassfish(glassfish的grizzly容器内核天然支持)
开源项目:
asyncWeb(基于mina)和xsocket
具体的使用可以参看这些项目的技术文档,我这里只是给出一些设计的特点说明,在异步模式下的Web请求(实践篇)中结合详细改造和测试来说明具体的实施效果及在改造过程中需要注意的内容。
Jetty
我个人比较喜欢的一个内嵌式容器,现在像GAE和Hadoop都在用它,它也是最早支持Comet和ARP的容器。在我过去的基于SCA规范的服务框架中,发布REST的内嵌容器就采用的是Jetty,处理能力还是比较强,在业务协议方面也支持比较广(同时支持ajp协议,ssl等)。^_^有点打广告了…
Jetty中的异步处理叫做Continuation,这里不是基于事件驱动模型的,而是通过Continuation这个对象来suspend/resume请求处理线程,同时它的suspend/resume也不是和传统的wait/notify一样,在阻塞的地方直接挂起或者被唤醒。它的resume其实又再次模拟了请求,会二次进入服务处理流程,同时第一次和第二次请求数据是不共享的(可以通过attachment来传递数据)。就这么看来,其实在suspend的时候所有的资源都被释放了,仅仅只是保存了请求来源信息在队列中,在后续被唤醒的时候再次模拟请求,由业务代码在实现中判断是否是第一次进入,并且在不同进入时请求处理过程做差异化实现,最终将不同的逻辑通过不同阶段的重入判断来分阶段处理。
Jetty有两个技术优化点:
1.split buffers。jetty6 采用split buffer架构和动态buffer分配架构。一个idle的connection没有buffers分配给他,一旦请求收到,则会有小的请求头buffer会被分配。大部分都是小请求,则只需要分配消息头buffer,当发现有大数据内容的时候则分配大buffer.当在等待回写数据到response的时候,输出缓存不会被分配。只有当servlet开始写入数据到response的时候,输出缓存才被分配,只有当response被提交的时候,response的消息头缓存才被分配,并且写出到输出缓存,有效的执行写操作。总的来说分配缓存只有在他们需要的时候,而且是根据需求分配
2.延时分发。支持用异步io读取内容,延时分发请求到处理器,减少在处理器等待的时间。(简单来说就是等到read了才去调用服务处理,避免无谓的资源等待浪费)
TOMCAT
Tomcat采用的与Jetty不同的设计方式,它的Comet是事件驱动的。每一个传统的Servlet需要实现CometProcessor接口,这个接口就需要实现类似于原来servlet的service的event方法,event方法会在各种事件发生的时候被激发,event当前主要包含了整个处理的生命周期(begin,close,error,read)。
需要注意的是在Tomcat配置connector的时候必须选择apr或者nio的connector,否则是不生效的。可以看到,就和NIO一样,对于连接建立,数据可读,都是基于事件触发,将业务和具体的连接分开,提高在业务处理较慢的情况下,服务器的吞吐能力。这种设计是比较贴近于NIO的设计思想的。
上面介绍的都是服务端的异步处理,在客户端其实也需要实现异步化的处理模式,通常情况况下都是基于事件模型实现的。服务端和客户端如何在异步的情况下理解消息的来源,一种是通过默认消息发送和接收保持顺序一致的方式,另一种就是通过颁发消息会话号来实现。
到此为止都是对于技术的介绍,没有实质性的使用,后续会根据TOP的实际应用场景去尝试改造(主要采用jetty或者Tomcat来实施),并作压力测试,最终得出实际的使用结果,来判断技术的成熟度。
分享到:
相关推荐
而在异步模式下,客户端发送请求后可以立即返回,无需等待响应,服务器处理完成后会通过某种机制通知客户端结果。 2. 事件驱动:异步Web服务通常基于事件驱动模型,即服务器在完成任务后触发一个事件,客户端通过...
在传统的同步编程模式下,程序执行会按照代码顺序逐行进行,如果某一步骤需要等待(例如I/O操作),那么整个程序都会阻塞,直到这个操作完成。异步编程则不同,它允许程序在等待某些操作(如网络请求或数据库查询)...
2. **异步处理**:在异步模式下,我们使用回调函数、Promise或async/await语法来处理响应。这样,当请求发送后,程序不会阻塞,而是继续执行其他任务。例如,在JavaScript中,我们可以使用`fetch` API或`...
相比之下,异步请求,通常与Ajax(Asynchronous JavaScript and XML)技术一起使用,提供了非阻塞的交互体验。在异步请求中,浏览器可以发送一个请求给服务器,然后立即继续处理其他任务,而不必等待服务器的响应。...
Ajax 模式在异步交互 Web 环境中的应用 Ajax 模式是一种基于异步交互的 Web 应用程序开发模式,它的核心概念是将客户端的页面表现和应用逻辑进行“拆分”,使应用逻辑部件按照需求,独立地与服务器实现信息交互,...
在本文中,我们将深入探讨如何将Ajax技术与Struts2框架结合,实现异步请求数据。这种方式能够提高用户体验,因为它允许后台处理数据而无需刷新整个页面。以下是对关键知识点的详细说明: 1. **Ajax(Asynchronous ...
总的来说,Servlet3异步请求是提升Web应用性能的关键技术之一,它通过非阻塞的方式优化了服务器资源利用,降低了等待时间,提高了用户体验。理解和熟练掌握这一特性,对于Java Web开发者来说至关重要。
在异步模式下,服务端需要能保存请求上下文并能够在适当的时候通知客户端。 4. **HelloWorldImpl.java** 和 **IHelloWorld.java**:这两份文件可能是服务接口和其实现。`IHelloWorld.java`定义了服务接口,而`...
总结起来,这个"一个实用了spring mvc和ajax异步请求的例子"涵盖了Web开发中的重要概念,包括Spring MVC的Controller设计、RESTful API的实现以及Ajax的异步数据交互。这样的组合使得Web应用更加动态,用户体验更佳...
### Ajax页面局部异步刷新技术 ...此外,还需要注意编码、请求方式、同步/异步模式的选择等因素对请求的影响。在实际开发中,开发者可以根据具体需求灵活运用这些知识点,构建高效、流畅的Web应用。
**AJAX 技术总结与设计模式** ...总结来说,AJAX 是一种强大的技术,通过设计模式的运用,可以构建高效、可维护的异步交互应用。了解并熟练掌握 AJAX 及其设计模式,对于提升 web 应用的性能和用户体验至关重要。
【标题解析】:“web IM 用异步实现的IM”这一标题主要指的是一种基于Web技术构建的即时通讯(Instant Messaging, IM)系统,它利用异步处理技术来提高性能和用户体验。在Web环境中,由于浏览器与服务器之间的交互受...
在实际应用中,ZMQ的请求/响应模式可用于构建可扩展的服务,例如Web服务、数据库查询、微服务架构等。通过这种方式,客户端可以向服务器发送请求,而服务器可以处理请求并返回结果,所有这些都在一个安全和高效的...
在传统的Web框架中,服务器通常采用同步I/O处理模式,即每个请求都会阻塞一个线程,直到响应完成。这种方式在面对高并发场景时,可能会导致大量线程被创建,消耗过多系统资源,性能瓶颈明显。而异步Web框架则解决了...
在Web2.0设计模式下,利用Ajax技术实现网页数据动态更新,主要表现在以下几个方面: - 实时数据更新:比如社交媒体的实时消息更新,股票市场的实时数据更新等。 - 搜索结果动态显示:在进行搜索时,无需刷新页面...
在Web开发中,Ajax(Asynchronous JavaScript and XML)是一种创建动态网页的技术,允许在不刷新整个页面的情况下与服务器交换数据并更新部分网页内容。本文将深入探讨如何在MVC架构的项目中,利用Ajax实现异步请求...
本文介绍了Ajax技术的原理和实现,并分析了Ajax技术在Web异步通信系统中的应用。Ajax技术可以实现异步通信,提高用户体验和服务器性能,减少服务器的负载。因此,Ajax技术在Web开发中有着非常重要的应用前景。
### Tomcat与Java Web开发技术详解 #### 一、Tomcat简介 Tomcat是一款开源的Servlet容器,由Apache软件基金会下属的Jakarta项目开发。它实现了对Servlet和JavaServer Pages (JSP)的支持,可以作为独立的应用服务器...