理解mod_proxy和Apache 2用于编写comet服务器

8

我目前正在尝试实现一个简单的HTTP服务器,用于某种彗星技术(长轮询XHR请求)。由于JavaScript在跨域请求方面非常严格,因此我有一些问题:

  1. 据我所知,任何一个Apache工作进程在提供请求时都会被阻塞,因此将“脚本”编写为通常的网站将阻塞Apache,当所有工作进程都有请求要处理时。-->不起作用!
  2. 我想到了一个主意,编写一个简单的HTTP服务器,专门用于提供这些长轮询请求。这个服务器不应该是阻塞的,因此每个工作进程可以同时处理多个请求。由于我的网站还包含内容/图像等,而我的服务器不需要提供内容,所以我将它启动在与80不同的端口上。现在的问题是,由于一些跨域限制,我无法在我的Apache中交互JavaScript和运行在不同端口上的comet-server。-->不起作用!
  3. 然后我想到使用mod_proxy将我的服务器映射到一个新的子域。我真的不知道mod_proxy如何工作,但我可以想象我现在拥有与我的第一种方法相同的效果?

创建这种经典网站和这些长轮询XHR请求的最佳方法是什么?我需要自己实现服务器上的内容传递吗?

5个回答

3
我很确定使用mod_proxy会在请求被处理时阻塞工作进程。如果您可以使用2个IP,有一个相当简单的解决方案。假设IP A是1.1.1.1,IP B是2.2.2.2,您的域名是example.com,则操作如下:将Apache配置为仅在IP A上侦听端口80;启动另一个服务器在IP B上的端口80;将XHR请求配置为您的域的子域名,但具有相同的端口。因此跨域限制不会阻止它们。例如,您的站点是example.com,XHR请求转到xhr.example.com;配置DNS使example.com解析为IP A,xhr.example.com解析为IP B;完成以上步骤即可。如果您有2个服务器且每个服务器都有自己的IP,则此解决方案将起作用;如果您有一个带有2个IP的服务器,那么它也将起作用。如果您不能使用2个IP,则我可能有另一个解决方案,我正在检查它是否适用于您的情况。

我对只使用一个IP的想法很感兴趣。 - TheHippo
1
我认为浏览器安全模型不允许从example.com加载的代码向xhr.example.com发送XHRs。你必须使用document.domain和IFrames来玩游戏,但这样做并不可移植。--http://www.fettig.net/weblog/2005/11/28/how-to-make-xmlhttprequest-connections-to-another-server-in-your-domain/ - Tim Sylvester

3
这是一个棘手的问题。即使您已经解决了安全问题,您最终仍需为每个当前查看网页的客户端保持一个TCP连接开放。您将无法创建线程来处理每个连接,并且无法从单个线程中“选择”所有连接。我之前做过这件事,我可以告诉您这并不容易。您可能需要研究一下libevent,它与memcached类似。

到一定程度上,您可能可以通过设置长时间超时并允许Apache拥有大量工作进程(其中大部分时间都处于空闲状态)来应对。精心选择和配置Apache worker模块将使其扩展到数千个并发用户。然而,在某些时候,它将无法再扩展。
我不知道您的基础设施是什么样子的,但我们在网络机架上有负载平衡盒子称为F5。它们提供单个外部域,但根据响应时间、请求头中的cookie等将流量重定向到多个内部服务器。它们可以配置为将虚拟域内某个路径的请求发送到特定服务器。因此,您可以将example.com/xhr/foo请求映射到特定服务器以处理这些comet请求。不幸的是,这不是一个软件解决方案,而是一个相当昂贵的硬件解决方案。
无论如何,您可能需要一些负载平衡系统(或者您可能已经有一个),也许它可以被配置为比Apache更好地处理这种情况。
多年前我遇到了一个问题,我希望使用专有二进制协议的客户端-服务器系统能够通过80端口访问我们的服务器,因为他们在使用系统的自定义端口时不断遇到防火墙问题。我需要的是一个代理,它将驻留在80端口,并根据来自客户端的前几个字节将流量定向到Apache或应用程序服务器。我寻找解决方案,但没有找到合适的。我考虑编写Apache模块、DeleGate插件等,但最终编写了自己的自定义内容感知代理服务。我认为这是您试图做的最糟糕的情况。

0

对于第二点:你可以通过使用JSONP绕过跨域限制。


0

种选择:

  1. 使用nginx。这意味着您运行3个服务器:nginx,Apache和您自己的服务器。
  2. 在独立端口上运行您的服务器
  3. 使用Apache mod_proxy_http(作为您自己的建议)。

我已确认mod_proxy_http(Apache 2.2.16)可以代理运行在GlassFish 3.1.1中的Comet应用程序(由Atmosphere 0.7.1提供支持)。

我的测试应用程序及其完整源代码在此处:https://github.com/ceefour/jsfajaxpush


0
针对有关mod-proxy的具体问题,您可以设置mod_proxy以提供由服务器(或服务)生成的内容,该服务器(或服务)不向公众开放(即仅通过内部地址或本地主机可用)。
我已在生产环境中这样做,并且非常成功。 Apache通过AJP工作进程将一些请求转发到Tomcat,而通过mod代理将其他请求转发到GIS应用服务器。正如其他人指出的,跨站点安全性可能会阻止您在子域上工作,但没有理由不能代理对mydomain.com/application的请求。
谈到你的具体问题 - 我认为你真正卡住了,看待问题时太过于关注“长时间请求”- 即假设当你发起其中一个请求时,整个过程都需要停止。似乎你试图通过对系统架构进行更改来解决应用程序架构的问题。事实上,你需要将这些后台请求视为这样的请求,并进行多线程处理:
  • 客户端向远程服务发出请求:“使用数据A、B和C执行任务X”
  • 您的服务接收到请求:将其传递给调度程序,该调度程序为请求发出唯一的票据/令牌。然后,服务将此令牌返回给客户端:“谢谢,您的任务在运行令牌Z下的队列中”
  • 然后,客户端保留此令牌,显示“正在加载/请稍候”框,并设置定时器,例如每秒触发一次
  • 当定时器触发时,客户端向远程服务发出另一个请求:“我的任务结果,令牌Z是否已经准备好了?”
  • 您的后台服务可以检查您的调度程序,并可能返回空文档“尚未完成”或结果
  • 当客户端收到结果时,它可以简单地清除定时器并显示结果。

只要您对线程有足够的掌握(如果您已经表示您正在考虑编写自己的HTTP服务器,那么您必须具备这方面的知识),这不应该太复杂 - 在http监听器部分之上:

  • 调度器对象 - 单例对象,实际上只是包装了一个“先进先出”堆栈。新任务放在堆栈的末尾,作业可以从开头取出:只需确保发出作业的代码是线程安全的(以免两个工作同时从堆栈中取出相同的作业)。
  • 工作线程可以非常简单 - 获取对调度程序的访问权限,请求下一个作业:如果有一个作业,则执行工作并发送结果,否则只需休眠一段时间,重新开始。

这样,您永远不会阻塞Apache的时间超过必要的时间,因为您所做的所有操作都是发出“执行x”或“给我x的结果”的请求。您可能需要在几个点上构建一些安全功能 - 例如处理失败的任务,并确保客户端端口上有超时,以便它不会无限期地等待。


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