Django / Comet(推送):最小的邪恶?

54

我已经阅读了所有关于Django和HTTP Push的问题和答案,但没有一个提供清晰、简洁、从头到尾的解决方案来实现所谓的"彗星"功能的基本"hello world"。

第一个问题(1):HTTP根本不适用于这个问题,在某种程度上说是不是所有潜在的解决方案都是hack?

2)目前最好的解决方案是什么?

  • Orbited?
  • 其他基于Twisted的解决方案?
  • Tornado?
  • node.JS?
  • XMPP w/ BOSH?

其他解决方案?

3) nginx推送模块在这个讨论中起什么作用?

4) 这些解决方案中哪些需要替换typical mod_wsgi / nginx(或apache)部署模型?为什么它们需要这样做?在任何情况下,这是一个有利的过渡吗?

5) 使用已经在Python中的解决方案的优势有多大?

Alex Gaynor在2010年PyCon的演讲非常惊人和信息量很大,但对于Django中HTTP Push的当前状态并不是非常具体。他说的一件事给了我一些信心,那就是:Orbited很好地抽象和模拟了网络套接字的概念。因此,当WebSocket实际上可用时,我们将处于一个良好的转换位置。

6)HTML5 Websockets与当前解决方案有什么不同?Gaynor对从Orbited过渡的轻松程度的评估是否准确?


只是顺便提一下,你看过新的mongrel2 web服务器吗?它使用ZeroMQ作为基本构建块,因此您可以进行各种长轮询,因为这是内置通信方式。 - knutin
1
大家一起来帮我解决这个问题吧,这是一个非常重要的问题。 - jMyles
mod_wsgi是一个Apache扩展。 - skywalker
4个回答

24
如果你只需要comet,建议你看看evserver(http://code.google.com/p/evserver/)。它“支持鲜为人知的异步WSGI扩展”,并且建立在libevent之上。虽然实际处理程序代码有点丑陋,但它确实是异步io,可以很好地扩展,并支持django。我曾经使用过evserver,现在正在转向cyclone(基于twisted的tornado),因为我需要比evserver提供的更多一点。我需要真正的双向io(想想socket.io(http://socket.io/)),虽然evserver也可以支持它,但我认为在cyclone中重新实现tornado's socket.io更容易(我选择了cyclone而不是tornado,因为cyclone基于twisted构建,因此允许使用twisted中未实现的更多传输(即zeromq))。Socket.io支持websockets、comet样式的轮询以及更有趣的是基于flash的websockets。我认为,在大多数实际情况下,websockets + 基于flash的websockets足以支持网站访问者的99%(根据Adobe Flash的数据,Flash渗透率约为99%(http://www.adobe.com/products/player_census/flashplayer/version_penetration.html)),只有不使用Flash的人需要回退到socket.io的其中一个备用传输(性能较差且占用资源)。但请注意,websockets不是http传输,因此将它们放在基于http的代理(例如haproxy的http模式)后面会中断连接。最好在备用IP或端口上提供它们,以便您可以在tcp模式下进行代理(例如haproxy的tcp模式)。
回答您的问题: (1)如果您不需要双向传输的长轮询解决方案已经足够好了(它们所做的就是保持连接打开)。当您需要连接是有状态的或者您需要能够发送和接收数据时,情况会变得棘手。在后一种情况下,socket.io 有所帮助。然而,WebSockets 是为这种情况而设计的,并且借助 flash 的支持,可用于大多数网站访问者(通过 socket.io 或独立使用,但是 socket.io 具有备份传输的附加好处,以供那些不想安装 flash 的人使用)
(2)如果您只需要推送,evserver 是您最好的选择。它在客户端使用与 orbited 相同的 JavaScript。否则,请查看 socket.io(这也需要支持服务器,唯一可用的 Python 服务器是 tornado。)
(3)这只是另一个服务器实现。如果我理解正确,它仅限于推送。将数据推送到客户端是通过从应用程序向 nginx 服务器发出 http 请求来完成的。(nginx 然后负责使其到达客户端)。如果您对此感兴趣,请查看 mongrel2(http://mongrel2.org/home),它不仅具有长轮询处理程序,还具有 WebSockets 处理程序。(这次您使用 zeromq 处理程序将数据传输到 mongrel 服务器,而不是向 mongrel 发送 http 请求)(请注意开发人员对 WebSockets 和基于 flash 的 WebSockets 缺乏热情。特别是考虑到 WebSocket 协议往往会发展,您可能需要重新编写 mongrel2 的 WebSocket 支持,以保持对 WebSocket 的支持)

(4) 除了evserver之外,所有解决方案都用其他东西替换了wsgi。尽管大多数服务器在这个“其他东西”之上也有一些wsgi支持。无论你选择什么解决方案,都要小心一个cpu密集型或其他io阻塞的请求不会阻塞服务器。(你需要多个实例或线程)。

(5) 没有太大的区别。所有解决方案都依赖于一些自定义处理程序来将数据推送(如果适用,则接收)到客户端。我提到的所有解决方案都允许使用python编写这些处理程序。如果你想使用完全不同的框架(如node.js),那么你必须权衡node.js的易用性(它被认为很容易,但它也相当实验性,并且我发现很少有库实际上是稳定的),并考虑使用现有代码库和可用库的便利性(例如,如果你的应用程序需要博客,则有很多django博客可以插入,但没有node.js的博客)。此外,不要盯着性能统计数据看。除非你打算向客户端推送愚蠢的预定义数据(所有基准测试都这样做),否则你会发现实际数据处理比最差的异步io实现增加了更多的开销。(但如果你打算有许多同时在线的客户端,仍然需要使用基于异步io的服务器,线程根本不适用于保持数千个连接处于活动状态)。

(6) WebSockets提供双向通信,长轮询/Comet只能推送数据而不能接受写入。 (Socket.io通过使用两个HTTP请求(一个用于长轮询,一个用于发送数据)来模拟此双向支持。它通过在两个请求的查询字符串中使用(会话)ID来跟踪它们的相互依赖关系)。基于Flash的WebSockets与真正的WebSockets类似(不同之处在于它们的实现在SWF中,而不是在您的浏览器中)。此外,WebSockets协议不遵循HTTP协议;长轮询/Comet协议则遵循HTTP协议(技术上,WebSocket客户端向WebSocket服务器发送升级请求,升级后的协议不再是HTTP)。


"Tornado的socket.io"链接已失效。 - Pang

7

django-websocket 的 WebSockets 支持,但不幸的是,在让它工作方面存在重大问题;以下是该页面的摘录:

免责声明(使用 django-websocket 时应了解的内容)

BIG FAT DISCLAIMER - 目前技术上无法以任何方式使用 WSGI 进行 WebSocket。这是一个已知问题,但由于在编写 WSGI 标准时做出了一些设计决策,无法以清洁的方式解决。当时像 Websockets 等事物并不存在且不可预测。

...

但不仅 WSGI 是限制因素。Django 本身是围绕着简单的请求-响应场景设计的,没有考虑到 Websockets。这也意味着目前无法为 Django 提供符合标准的 WebSocket 实现。然而,以不太美观的方式可以使其工作。因此,请注意在使用 django-websocket 时可能会对 tcp sockets 造成压力。

目前来看,WSGI:不行;Django:即使使用django-websockets也几乎不行;还可以参考作者在原始公告中的评论:

我不能说这看起来是一个好主意。你正在以一种需要线程的方式进行长期连接。django-websocket需要设置线程,并且如果你有进程(因为你将有太多进程),它将无法工作,但同时线程也无法扩展到大量同时连接,因此它只是一种虚假的安全性。对于长期存在的事物,您需要一个异步平台,我通过在Django中运行我的应用程序并在Node.js中运行我的comet和websocket来实现。

个人而言,如果要使用WebSockets(我预计会在明年),我会首先尝试TwistedCyclone的组合。它们专门设计用于处理WebSockets,并且具有良好的可扩展性。如果您正确编写代码以消除Django上不必要的依赖项,则应该能够在基于Twisted的系统中使用大部分代码。这是与使用Node.js或Comet或其他语言中的任何系统相比的非常明显的优势。您还可以创建一个简单的推送。
最后,您也可以决定使用外部服务来提供推送支持,因为这太难了。然后,这就成为向其服务器发送一个简单的JSON请求的问题,而不必担心如何建立连接以及并发性将如何工作等问题。当然,您需要为此付费(尽管目前可能在Beta测试期间免费),但您不需要担心实现细节;但这种方式下您将无法获得WebSockets的全部功能,只能获得推送支持。

1
即使WSGI规范在某种程度上允许它在WebSockets上工作,这也不会对您有太大帮助。真正的问题是,大多数托管接口使用的底层Web服务器和代理协议都不允许它。因此,您将无法使用FASTCGI、SCGI、AJP、CGI、mod_wsgi、uWSGI等等。基本上,任何假设应用程序在发送响应之前读取完整请求内容的东西都不行。因此,您需要WebSocket的支持与Web服务器更紧密地交织在一起,这通常意味着专用的异步服务器。 - Graham Dumpleton

2

我简直不敢相信已经过去了六年,自己提出了这个问题。

对于Django的异步操作(以及相关的网络流量,例如WebSockets),我们社区中的许多人都有需求。在过去的几年里,我除了其他事情外,一直在解决这个问题。

hendrix

hendrix是一个运行在Twisted上的WSGI/ASGI容器。它是由5位爱好者驱动的项目,得到了一些有远见的组织的帮助和资助。目前在数十家公司投入生产使用。

我将让你阅读文档来了解为什么它是解决这个问题的最佳方案,但是以下是一些快速亮点:

  • 它基于Twisted,不需要了解或使用Twisted内部知识,但所有这些都是可用的。
  • 它“只需工作”,也就是说,您不需要任何特殊的服务器或进程配置即可从Django(或Pyramid、Flask)应用程序中进行异步和套接字流量操作。
  • 它很可能与ASGI、Django Channels标准保持向前兼容,并且在某些方面是第一个ASGI容器。
  • 它提供了简单的API,可以维护您的视图逻辑的流程,并且易于进行单元测试。

请参阅我在Django-NYC(在Buzzfeed办公室)所做的演讲,以获取有关为什么我认为这是解决这个问题的最佳答案的更多信息。


1
关于第二个问题,最近我参观了一个使用Comet技术的Django应用程序的内部结构,他们选择了Orbited作为解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接