我们有一个 Web 服务,它为较大的 MP3 文件的固定库存中的小片段、任意片段提供服务。MP3 文件由 python 应用程序即时生成。该模型是,向指定您想要的段的 URL 发出 GET 请求,并获得一个audio/mpeg
流作为响应。这是一个昂贵的过程。
我们使用 Nginx 作为前端请求处理程序。Nginx 负责缓存常见请求的响应。
我们最初尝试在后端使用 Tornado 来处理来自 Nginx 的请求。如您所料,阻塞的 MP3 操作使 Tornado 无法完成它的工作(异步 I/O)。所以,我们采用了多线程,这解决了阻塞问题,并且表现得很好。然而,它引入了一个微妙的竞争条件(在现实世界的负载下),我们还无法诊断或重现。竞争条件破坏了我们的 MP3 输出。
因此,我们决定将我们的应用程序设置为 Apache/mod_wsgi 后面的简单 WSGI 处理程序(仍然在前面使用 Nginx)。这消除了阻塞问题和竞争条件,但在现实世界条件下在服务器上创建了级联负载(即 Apache 创建了太多进程)。我们现在正在调整 Apache/mod_wsgi,但仍处于试错阶段。(更新:我们已经切换回 Tornado。见下文。)
最后,问题是:我们错过了什么吗?有没有更好的方法通过 HTTP 提供 CPU 昂贵的资源?
更新:感谢 Graham 的文章,我很确定这是一个 Apache 调优问题。与此同时,我们又回到了使用 Tornado 并试图解决数据损坏问题。
对于那些急于解决这个问题的人来说,Tornado 和一些多线程(尽管线程引入了数据完整性问题)可以在小型(单核)Amazon EC2 实例上可接受地处理负载。