在Ajax应用程序中实现实时数据推送(上)

日期: 2010-08-10 作者:Sandeep Malik 来源:TechTarget中国 英文

  全新的高级用户界面(UI)应用程序需要某些 “服务器推送” 方面的特性,使得客户端能够在服务器端发生更改时立即得到通知。遗憾的是,HTTP规范并未解决任何服务器端发起的通信的问题,因而服务器推送一直以来都是通过客户端轮询实现的。这种技术可能会生成大量不必要的流量和非最优化的应用程序。幸运的是,某些富Internet应用程序(RIA)技术确实允许打开专用套接字通道,由后端服务器为Asynchronous JavaScript and XML(Ajax) 应用程序提供进入其API并实现服务器推送的机会。这篇文章以多种方式探讨了这项技术,帮助您充分理解,以便着手开始进行自己的实现工作。

  简介

  Ajax技术已经存在了一段时间,开发的动力已经真正开始得到了人们的认可。越来越多的Web站点正在考虑使用Ajax进行设计,开发人员也开始将Ajax的能力发挥到极限。随着社交网络和协作式报告等现象的出现,一组全新的要求浮现出来。如果有其他用户更改了某位用户正在观察的任何活动,则用户希望得到通知。如果一个Web站点显示动态数据,如股价等,那么所有用户都必须立即得到关于变更的通知。

  这些场景本身属于一类称为 “服务器推送” 的问题。通常,服务器是中心实体,服务器将首先获得关于所发生的任何更改的通知,服务器负责将此类更改通知所有连接的客户端。但遗憾的是,HTTP是客户端-服务器通信的标准协议,它是无状态的,而且在某种意义上来说,也是一种单向的协议。HTTP场景中的所有通信都必须由客户端发起,至服务器结束,然而我们所提到的场景的需求则完全相反。对于服务器推送来说,需要由服务器发起通信,并向客户端发送数据。HTTP协议并无相关配置,Web站点应用程序开发人员使用独创的方法来绕过这些问题,例如轮询,客户端会以固定(或可配置)的时间间隔与服务器联系,查找是否有新更新可用。在大多数时候,这些轮询纯粹是浪费,因而服务器没有任何更新。这种方法不是没有代价的,它有两大主要问题。

  这种方法极度浪费网络资源。每一个轮询请求通常都会创建一个TCP套接字连接(除非HTTP 1.1将自己的keepAlive设置为true,此时将使用之前创建的套接字)。套接字连接本身代价极高。除此之外,每一次请求都要在网络上传输一些数据,如果请求未在服务器上发现任何更新,那么这样的数据传输就是浪费资源。如果在客户端机器上还运行着其他应用程序,那么这些轮询会减少传输数据可用的带宽。

  即便是请求成功,确实为客户端传回了更新,考虑到轮询的频率,这样的更新也不是实时的。例如,假设轮询配置为每 20 秒一次,就在一次请求刚刚从服务器返回时,发生了更新。那么这次更新将在 20 秒后的下一次请求到来时才能返回客户端。因而,服务器上准备好供客户端使用的更新必须等待一段时间,才能真正地为客户端所用。对于需要以尽可能实时的方式运行的应用程序来说,这样的等待是不可接受的。
考虑到这样两个问题,对于需要关键、实时的服务器端更新的企业应用程序而言,轮询并不是最理想的方法。在这篇文章中,我将介绍多种可以替代轮询的方法。每一种替代方法在某些场景中都有自己的突出之处。我将说明这些场景,并展示需要实时服务器推送的一组 UI。

  Ajax应用程序中的服务器更新技术

  让我们来具体看看用于更新来自服务器的信息的一些常用技术,这些技术模拟了服务器推送。

  短轮询

  短轮询也称为高频轮询,就是我在本文开头处介绍的技术。这种方法在以下情况中表现最好:

  有足够的带宽可用。

  根据统计数据,大多数时候,请求都能获得更新。例如,股市数据就总是有可用更新。

  使用HTTP 1.1协议。设置keepAlive=true,因而,同一个套接字连接始终保持活动状态,并可重用。

  长轮询

  长轮询是用于更新服务器数据的另外一种方法。这种方法的理念就是客户端建立连接,服务器阻塞连接(通过使请求线程在某些条件下处于等待状态),有数据可用时,服务器将通过阻塞的连接发送数据,随后关闭连接。客户端在接收到更新后,立即重新建立连接,服务器重复上述过程,以此实现近于实时的通信。然而,长轮询具有以下缺陷:

  一般的浏览器默认允许每台服务器具有两个连接。在这种情况下,一个连接始终是繁忙状态。因而,UI只有一个连接(也就是说,能力减半)可用于为用户请求提供服务。这可能会导致某些操作的性能降低。
 
  仍然需要打开和关闭HTTP连接,如果采用的是非持久连接模式(keepAlive=false),那么这种方法的代价可能极高。
这种方法近于实时,但并非真正的实时。(当然,某些外部因素总是不可控的,比如网络延时,在任何方法中都会存在这些因素。)

  流通道

  流通道(streaming channel)与长轮询大致相同,差别在于服务器不会关闭响应流。而是特意保持其处于打开状态,使浏览器认为还有更多数据即将到来。但是,流通道也有着自己的缺陷:

  最大的问题就是数据刷新(flushing)。过去,Web服务器会缓存响应数据,仅在接受到足够的字节数或块数后才会发送出去。在这种情况下,即便应用程序刷新数据,也仍然会由服务器缓存,以实现优化。更糟的是,如果在客户端和服务器之间存在代理服务器,那么代理也可能会为自身之便缓存数据。
 
  如果发现套接字将打开较长的时间,某些浏览器实现可能会自行决定关闭套接字。在这种情况下,通道需要重新建立。
通常,第一个问题可通过为每个流响应附加垃圾有效载荷来解决,使响应数据足以填满缓冲区。第二个问题可通过 “保持活动” 或按固定间隔 “同步” 消息来欺瞒浏览器,使浏览器认为数据是以较慢的速率传入的。

  这些解决方案适用的用例范围狭窄。所有这些方法都已经在Internet上的某些解决方案中得到了应用。然而,这些解决方案都遭遇了相同的问题:缺乏可伸缩性。典型情况下,要阻塞一个请求,您需要阻塞处理请求的线程,因为如今几乎所有应用服务器都会执行阻塞 I/O。即便不是这样,Java™ 2 Platform, Enterprise Edition (J2EE) 也未提供为 HTTP 请求和响应执行非阻塞I/O的标准。(Servlets 3.0 API可解决这一问题,因为这些API中包含Comet Servlet。)

  至此,您需要具备非阻塞I/O(NIO)服务器,客户端应用程序通过它进行连接。由于此类套接字是纯TCP二进制套接字,因而将实现以下目标:

  由于服务器端具有NIO,因而可实现更高的可伸缩性。
 
  响应缓存的问题不复存在,因为这个套接字直接受应用程序的控制。

  基于上述说明,有必要指出这种方法的四个缺点:

  由于使用的是二进制TCP套接字,因而应用程序无法真正地利用HTTPS层提供的SSL安全性。所以,要求数据安全性的应用程序可能需要提供自己的加密工具。

  通常情况下,服务器套接字将在80以外的端口上运行,如果防火墙仅允许来自端口80的流量,将出现问题。因而,可能需要进行一些端口配置。

  Ajax客户端无法通过后端打开TCP套接字连接。

  即便Ajax客户端能够执行open函数,也无法理解二进制内容,这是因为Ajax使用的是XML或JSON(基于文本)格式。

  在这篇文章中,我要强调的是如何真正地绕开第三个和第四个问题。如果您能够处理安全性和防火墙问题,那么其他问题也能得到处理。这种做法的获益极为显著。

  您可为应用程序实现最大程度的实时服务器推送行为(不考虑网络延时等外部因素),您将获得高度可伸缩的解决方案(以同时连接的客户端数量为准)。

  在《在Ajax 应用程序中实现实时数据推送(下)》中,我们将开始探索如何解决上述的第三个和第四个问题。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐

  • 八个超实用的jQuery技巧攻略

    jQuery是JavaScript最好的库之一,主要用于制作动画、事件处理,支持Ajax及HTML脚本客户端。文中分享了8个超实用的jQuery代码技巧攻略,希望你会喜欢。

  • HTML5强大功能背后的安全陷阱

    尽管HTML5使网站的功能更为强大,但开发人员需充分利用其新的技术特征来提高网站的安全性,使用不当会带安全问题,你知道吗?

  • 前端页面开发之Node.js初学者指南

    Node.js是刚刚兴起的一个概念,你对它的了解有多少?Node.js的意义是什么,它是怎么发展起来的?Node.js的作用是怎样的呢?

  • JavaScript解析:让搜索引擎看到更真实的网页

    我们都知道期的搜索引擎没有相应的处理能力,会导致很多问题。引入JavaScript解析的目的,可以使搜索引擎可以更为清晰的了解用户实际打开该网页时看到的效果。