如何让Apache可靠地服务于大量端口?

时间:2013-09-29 21:27:33

标签: web-services apache wsgi

我有一个使用Apache的专用服务器来监听通过SSL提供API服务的九个非标准端口(8xxx)。端口80和443用于提供静态内容和“覆盖”服务,用于指示其他服务的状态。

几天后,服务开始失败,因为似乎Apache正在将服务请求定向到覆盖服务而不是预期的服务。重新启动Apache修复此问题,直到它再次发生。

服务使用wsgi实现。

传统的金字塔API服务配置如下:

WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
WSGIDaemonProcess pyramid user=ubuntu group=ubuntu threads=4 \
   python-path=/home/ubuntu/ev_mis/lib/python2.7/site-packages
WSGIScriptAlias /mis /home/ubuntu/ev_mis/mis.wsgi

<Directory /home/ubuntu/ev_mis>
  WSGIProcessGroup pyramid
  Order allow,deny
  Allow from all
</Directory>

其他八个API服务使用Django,配置如下:

# Built automatically on Wed Sep 25 13:59:51 2013
Listen 8325
<VirtualHost _default_:8325>
    DocumentRoot /usr/local/services/h/rb/mis/mis_site/mis_site
    Alias /media /usr/local/services/h/rb/mis/mis_site/mis_site/media
    Alias /static /usr/local/services/h/rb/mis/mis_site/mis_site/assets

    <Directory /usr/local/services/h/rb/mis/mis_site/mis_site>
        Order allow,deny
        Allow from all
    </Directory>

    SetEnv DJANGO_SETTINGS_MODULE mis_site.settings.h
    WSGIScriptAlias / /usr/local/orb_services/h/rb/mis/mis_site/mis_site/mis_site/wsgi.py
    SSLEngine On
    SSLCertificateFile    /etc/apache2/ssl/domain.crt
    SSLCertificateKeyFile /etc/apache2/ssl/domain.key
    SSLCertificateChainFile /etc/apache2/ssl/chain.crt
    SSLOptions +StrictRequire
</VirtualHost>

最后是覆盖服务配置:

<VirtualHost *:80>

DocumentRoot /var/www
Alias /static /var/www/static
<Directory /var/www/>
    Order allow,deny
    Allow from all
</Directory>

Alias /thumbnails /var/www/thumbnails
<Directory /var/www/thumbnails>
    Order allow,deny
    Allow from all
</Directory>

WSGIScriptAlias / /var/www/overwatch/overwatch/wsgi.py

ErrorLog ${APACHE_LOG_DIR}/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn

CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

这是一个示例wsgi.py文件:

import os
from os.path import abspath, dirname
from sys import path
from os import environ

SITE_ROOT = dirname(dirname(abspath(__file__)))
path.append(SITE_ROOT)

from django.core.wsgi import get_wsgi_application
def application(req_environ, start_response):
    environ["DJANGO_SETTINGS_MODULE"] = req_environ.get("DJANGO_SETTINGS_MODULE",
                                                        environ.get("DJANGO_SETTINGS_MODULE",
                                                                    None))
    return get_wsgi_application()(req_environ, start_response)

例如:https://example.com/生成覆盖状态表,https://example.com:8123/data/生成其中一个服务的服务数据。

分析显示,apache错误地将调用指向了覆盖服务。例如,https://example.com:8123/data/现在产生未找到的页面,调试跟踪显示它已由overwatch wsgi服务提供。

一旦发生这种情况,它会一直发生,直到我重新启动apache服务。然后一切都很好,直到它再次发生。 Apache没有报告任何配置问题,并且启动/重启很好。

目前服务器只是经历了非常轻的测试流量,但它计划很快上线,我不知道如何解决这个问题...当我重新配置整个事情时,可能会咬紧牙关并推迟发射使用nginx / gunicorn代替apache,感觉就像一个警察。

1 个答案:

答案 0 :(得分:1)

一些评论。

  • 您不应将DocumentRoot设置为项目代码所在的目录。如果您无意中注释掉了WSGIScriptAlias,那么您的所有项目代码(包括带有数据库密码的设置文件)都可以由他人下载。
  • 您不能在Apache中使用'SetEnv DJANGO_SETTINGS_MODULE mis_site.settings.h'来指定Django设置模块的位置。它需要在wsgi.py文件中设置。
  • 你为什么不为你的Django网站使用mod_wsgi的守护进程模式?您将在一个进程的子解释器中运行多个实例,如果您没有正确配置Django,则可能导致请求由错误的应用程序处理。请参阅http://blog.dscpl.com.au/2012/10/requests-running-in-wrong-django.html

更新1

而不是使用:

from django.core.wsgi import get_wsgi_application
def application(req_environ, start_response):
    environ["DJANGO_SETTINGS_MODULE"] = req_environ.get(
            "DJANGO_SETTINGS_MODULE". environ.get("DJANGO_SETTINGS_MODULE", None))
    return get_wsgi_application()(req_environ, start_response)

您应该使用:

from django.core.wsgi import get_wsgi_application
_application = get_wsgi_application()

def application(req_environ, start_response):
    environ["DJANGO_SETTINGS_MODULE"] = req_environ.get(
            "DJANGO_SETTINGS_MODULE", environ.get("DJANGO_SETTINGS_MODULE", None))
    return _application(req_environ, start_response)

你在每个请求上调用get_wsgi_application(),这是一个坏主意。它导致在每个请求上创建WSGI处理程序的新实例,这不是必需的。这样做也会搞砸New Relic等监控工具的操作。