Django / Comet (Push): 万恶之最?
Posted
技术标签:
【中文标题】Django / Comet (Push): 万恶之最?【英文标题】:Django / Comet (Push): Least of all evils? 【发布时间】:2011-05-17 16:16:48 【问题描述】:我已经阅读了所有我能找到的关于 Django 和 HTTP Push 的问题和答案。然而,对于如何完成所谓的“彗星”功能的基本“hello world”,没有一个提供清晰、简洁、从头到尾的解决方案。
第一个问题 (1):在多大程度上 HTTP 根本不是(至少到目前为止)为此而生的?所有潜在的解决方案本质上都是黑客攻击吗?
2) 目前最好的解决方案是什么?
轨道? 其他一些基于 Twisted 的解决方案? 龙卷风? node.JS? 带 BOSH 的 XMPP?其他解决方案?
3) nginx push 模块如何参与本次讨论?
4) 这些解决方案中的哪些需要替换典型的 mod_wsgi / nginx(或 apache)部署模型?他们为什么需要这个?无论如何,这是一个有利的过渡吗?
5) 使用 Python 中已有的解决方案的优势有多大?
我刚刚在 blip.tv 上观看的 PyCon 2010 上的 Alex Gaynor 演示非常精彩且内容丰富,但对 Django 中 HTTP 推送的当前状态并没有特别具体。他说的一件事给了我一些信心:Orbited 在抽象和模拟网络套接字的概念方面做得很好。因此,当 WebSockets 真正落地时,我们将处于一个过渡的好地方。
6) html5 Websockets 与当前解决方案有何不同? Gaynor 对从 Orbited 轻松过渡的评估准确吗?
【问题讨论】:
顺便说一句,您看过新的 mongrel2 网络服务器了吗?它使用 ZeroMQ 作为基本构建块,因此您可以进行各种长轮询,因为它是内置的通信方式。 来吧,帮我解决这个问题 - 这是一个非常大的问题。 mod_wsgi 是一个 apache 扩展 【参考方案1】:如果您只需要彗星,我会看看 evserver (http://code.google.com/p/evserver/)。
它“支持 [the] 鲜为人知的异步 WSGI 扩展”并且是围绕 libevent 构建的。像魅力一样工作并支持 django。实际的处理程序代码有点难看,但它的扩展性很好,因为它确实是异步 io。
我已经使用了 evserver,并且我目前正在转向旋风(扭曲的龙卷风),因为我需要的不仅仅是 evserver offsers。我需要真正的双向 io(想想 socket.io (http://socket.io/)),虽然 evserver 可以支持它,但我认为在旋风分离器中重新实现 tornado's socket.io 更容易(我选择旋风分离器而不是龙卷风,因为旋风分离器是建立在 twisted 之上,因此允许在 twisted (ic zeromq) 中未实现的更多传输)Socket.io 支持 websockets、comet 样式轮询,以及更有趣的基于 flash 的 websockets。我认为在大多数实际情况下,基于 websockets + flash 的 websockets 足以支持 99%(根据 adobe flash 渗透率约为 99% (http://www.adobe.com/products/player_census/flashplayer/version_penetration.html))的网站访问者(只有不使用 flash 的人需要回退到 socket.io 的其中一个(较少性能和资源占用)备份传输)
请注意,尽管 websockets 不是 http 传输,因此将它们放在基于 http 的代理之后(例如 http 模式下的 haproxy)会中断连接。最好在备用 ip 或端口上为它们提供服务,以便您可以在 tcp 模式下代理(例如 tcp 模式下的 haproxy)。
回答您的问题: (1) 如果您不需要双向传输,基于 longpolling 的解决方案就足够了(它们所做的只是保持连接打开)。当你需要你的连接是有状态的或者你需要能够发送和接收数据时,事情确实会变得不确定。在后一种情况下,socket.io 会有所帮助。然而,websockets 是为这种情况而设计的,并且在 flash 的支持下,大多数网站访问者都可以使用它(通过 socket.io 或独立,但是 socket.io 为那些不想安装 flash 的人提供了备份传输的额外好处)
(2) 如果您只需要推送,那么 evserver 是您最好的选择。它在客户端使用与轨道相同的 javascript。再看看socket.io(这也需要一个支持服务器,唯一可用的python是tornado。)
(3) 这只是另一种服务器实现。如果我正确阅读它,它只是推动。将数据推送到客户端是通过从您的应用程序向 nginx 服务器发出 http 请求来完成的。 (nginx 然后照顾他们到达客户端)。如果您对此感兴趣,请查看 mongrel2 (http://mongrel2.org/home) 它不仅有用于 longpolling 的处理程序,还有用于 websockets 的处理程序。(这次您使用 zeromq 处理程序而不是向 mongrel 发出 http 请求将数据传输到您的 mongrel 服务器)(请注意开发人员对 websocket 和基于 flash 的 websocket 缺乏热情。特别是考虑到 websocket 协议趋于发展,在某些时候,您可能需要自己重新编码 mongrel2 的 websocket 支持支持 websockets)
(4) 除 evserver 之外的所有解决方案都将 wsgi 替换为其他解决方案。尽管大多数服务器在这个“其他东西”之上也有一些 wsgi 支持。无论您选择哪种解决方案,都要小心一个 cpu 密集型或其他 io 阻塞请求不会阻塞服务器。 (您需要多个实例或线程)。
(5) 不是很重要。所有解决方案都依赖于一些自定义处理程序来向客户端推送(并且,如果适用的话,接收)数据。我提到的所有解决方案都允许这些处理程序用 python 编写。如果你想使用一个完全不同的框架(node.js),那么你必须权衡 node.js 的易用性(它被认为很容易,但它也是相当实验性的,我发现很少有库实际上是稳定的)反对使用现有代码库和可用库的便利性(例如,如果您的应用程序需要一个博客,那么您可以插入大量 django 博客,但对于 node.js 则没有) 另外不要对性能统计数据视而不见。除非您计划将愚蠢的预定义数据(所有基准测试所做的)推送到客户端,否则您会发现数据的实际处理会比最糟糕的异步 io 实现增加多更多的开销。 (但是,如果您计划同时拥有许多客户端,您仍然希望使用基于异步 io 的服务器,线程并不意味着保持数千个连接处于活动状态)
(6) websockets 提供双向通信,长轮询/彗星只推送数据但不接受写入。 (Socket.io 通过使用两个 http 请求来模拟这种双向支持,一个用于长轮询,一个用于发送数据。它通过作为两个请求查询字符串的一部分的(会话)id 来跟踪它们的相互依赖性)。基于 flash 的 websocket 类似于真正的 websocket(不同之处在于它们的实现是在 swf 中,而不是在您的浏览器中)。另外 websockets 协议不遵循 http 协议; longpolling/comet 的东西(从技术上讲,websocket 客户端向 websocket 服务器发送升级请求,升级后的协议不再是 http)
【讨论】:
答案中指向“tornado's socket.io”的链接已失效。【参考方案2】:django-websocket 支持 WebSockets,但不幸的是,它的工作存在重大问题;这是该页面的引述:
Disclaimer (what you should know when using django-websocket)
BIG FAT DISCLAIMER - 目前在技术上不可能以任何方式将 websocket 与 WSGI 一起使用。这是一个已知问题,但由于在编写 WSGI 标准时做出了一些设计决策,因此无法以干净的方式解决。此时,Websockets 等东西不存在,也无法预测。
...
但不仅是 WSGI 是限制因素。 Django 本身是围绕一个简单的请求响应场景设计的,没有考虑到 Websockets。这也意味着 django 目前无法提供符合标准的 websocket 实现。然而,它以一种不那么漂亮的方式工作。所以请注意,使用 django-websocket 时 tcp 套接字可能会受到折磨。
所以目前,WSGI:不行; Django:几乎没有,即使使用 django-websockets;另见作者original announcement中的评论:
我不能说这看起来是个好主意。您正在以需要线程的方式进行长期连接。 django-websocket 需要线程设置,如果你有进程(因为你有太多进程)将无法工作,但线程也不会同时扩展很多连接,所以它只是虚假的安全。你需要一个异步平台来处理长期存在的事情,我通过在 Django 中编写我的应用程序以及在 Node.js 中编写我的 comet 和 websocket 来做到这一点
就个人而言,如果尝试使用 WebSockets(我预计明年会使用),我会首先尝试 Twisted 和 Cyclone 的组合。它们旨在应对 WebSockets,并且可以很好地扩展。如果您正确编写代码以删除对 Django 的不必要依赖,您应该能够在基于 Twisted 的系统中使用您的大部分代码。与使用 Node.js 或 Comet 或任何其他语言的系统相比,这是一个非常明显的优势。你也可以做一个简单的推送
最后,您也可以认为这太难了,并使用外部服务来提供推送支持。然后就变成了向他们的服务器发送一个简单的 JSON 请求的问题,而不是担心如何建立连接以及并发如何工作等等。当然,您需要为此付费(尽管目前它在 Beta 版中可能是免费的),但您不必担心实施细节;但是,您不会以这种方式获得 WebSockets 的全部功能 - 只需推送支持即可。
【讨论】:
即使 WSGI 规范允许它在 WebSockets 上工作,也不会对你有太大帮助。真正的问题是托管接口使用的大多数底层 Web 服务器和代理协议都不允许这样做。因此,您将无法使用 FASTCGI、SCGI、AJP、CGI、mod_wsgi、uWSGI 等。基本上任何假设应用程序将在发送响应之前读取完整请求内容的东西。因此,您需要 WebSocket 的支持与 Web 服务器更紧密地交织在一起,这通常意味着专用异步服务器。【参考方案3】:我不敢相信我问这个问题已经六年多了。
与 Django 的异步(以及相关的网络流量,例如 websockets)一直是我们社区中许多人的烦恼。在过去的几年里,我一直在抓挠这种痒。
hendrix
hendrix 是一个在 Twisted 上运行的 WSGI/ASGI 容器。这是一个主要由 5 位爱好者推动的项目,并得到了一些有远见的组织的帮助和资助。今天有几十家但不是数百家公司正在生产它。
我将留给您阅读文档,了解为什么它是解决此问题的最佳解决方案,但有几个要点:
它基于 Twisted,不需要任何知识或使用 Twisted 内部,但它们都可用 它“正常工作”,因为您不需要任何特殊的服务器或进程配置来从 Django(或 Pyramid 或 Flask)应用程序中执行异步和套接字流量 它很可能与 Django Channels 标准 ASGI 向前兼容,并且在某些方面是第一个 ASGI 容器 它附带简单的 API,可维护您的视图逻辑流程并且易于进行单元测试。请参阅我在 Django-NYC(在 Buzzfeed 办公室)提供的 this talk,了解为什么我认为这是这个问题的最佳答案。
【讨论】:
【参考方案4】:关于问题 #2,我最近参观了一个大量使用 Comet 的 Django 应用程序的内部结构,而 Orbited 是他们选择的解决方案。
【讨论】:
以上是关于Django / Comet (Push): 万恶之最?的主要内容,如果未能解决你的问题,请参考以下文章
Java/Tomcat 服务器的最佳 Comet/Push 技术?