【问题标题】:uWSGI works as process but not as daemonuWSGI 作为进程而不是守护进程工作
【发布时间】:2013-06-10 13:11:29
【问题描述】:

对于我当前的烧瓶部署,我必须设置一个 uwsgi 服务器。 这就是我创建 uwsgi 守护进程的方式:

sudo vim /etc/init/uwsgi.conf

# file: /etc/init/uwsgi.conf
description "uWSGI server"

start on runlevel [2345]
stop on runlevel [!2345]
respawn

exec /myproject/myproject-env/bin/uwsgi --uid www-data --gid www-data --home /myproject/myproject-env/site/F11/Engineering/  --socket /tmp/uwsgi.sock --chmod-socket --module F11 --callable app --pythonpath /myproject/myproject-env/site/F11/Engineering/ -H /myproject/myproject-env

但是在成功运行之后:sudo start uwsgi

uwsgi start/running, process 1286

并尝试通过浏览器访问应用程序:

我得到一个 502 Bad Gateway

和 nginx error.log 中的错误条目:

2013/06/13 23:47:28 [错误] 743#0: *296 上游过早关闭 从上游读取响应标头时连接,客户端: xx.161.xx.228,服务器:myproject.com,请求:“GET /show_records/2013/6 HTTP/1.1”,上游: “uwsgi://unix:///tmp/uwsgi.sock:”,主机:“myproject.com”

但是sock文件有它需要的权限:

srw-rw-rw- 1 www-data www-data 0 Jun 13 23:46 /tmp/uwsgi.sock

如果我在命令行中从上面运行exec 命令作为一个进程,它工作得非常好。请问为什么守护进程不能正常工作?

顺便说一句,Nginx 运行为 vim /etc/nginx/nginx.conf

user www-data;

和vim /etc/nginx/sites-available/default

location / {
                uwsgi_pass   unix:///tmp/uwsgi.sock;
                include        uwsgi_params;
        }

它以sudo service nginx start开始

我在 Ubuntu 12.04 LTS 上运行这个。

我希望我已经提供了所有必要的数据,希望有人能引导我走向正确的方向。谢谢。

【问题讨论】:

  • 你用的是debian还是ubuntu?
  • @joe,Ubuntu 12.04 LTS。我刚刚在运行 13.04 的笔记本电脑上对其进行了测试,问题完全相同。这很好,因此可以复制。
  • 听起来守护进程在不同的用户下运行或可以访问不同的配置...这不是提示吗:stackoverflow.com/questions/394984/…

标签: flask ubuntu-12.04 uwsgi


【解决方案1】:

使用 daemon true 命令运行的单行是

gunicorn  app.wsgi:application -b 127.0.0.1:8000 --daemon

将您的应用与 127.0.0.1:8000 绑定并 --deamon 强制它作为守护进程运行

但定义一个 gunicorn_config.cfg 文件并使用 -c 标志运行是一个好习惯

更多:

https://gunicorn-docs.readthedocs.org/en/develop/configure.html

【讨论】:

    【解决方案2】:

    我放弃了,没有生成uwsgi.log,nginx就一直在抱怨:

    2014/03/06 01:06:28 [error] 23175#0: *22 upstream prematurely closed connection while reading response header from upstream, client: client.IP, server: my.server.IP, request: "GET / HTTP/1.1", upstream: "uwsgi://unix:/var/web/the_gelatospot/uwsgi.sock:", host: "host.ip"
    

    对于每一个请求。这只发生在将 uwsgi 作为服务运行时,作为一个进程,它在任何用户下都可以正常启动。所以这可以从命令行工作(页面响应):

    $exec /var/web/the_gelatospot/mez_server.sh
    

    这没有(/etc/init/site_service.conf):

    description "mez sites virtualenv and uwsgi_django" start on runlevel
    [2345] stop on runlevel [06] respawn respawn limit 10 5 exec
    /var/web/the_gelatospot/mez_server.sh
    

    进程将启动,但在每次请求时,nginx 都会抱怨连接已关闭。奇怪的是,对于使用相同 nginx 版本和相同 uwsgi 版本的其他 2 个应用程序,我有同样的配置工作得很好,而且这两个应用程序都是夹层 CMS 应用程序。我尝试了所有我能想到的和建议的。最后我切换到了很好用的 gunicorn:

    #!/bin/bash
    
    NAME="the_gelatospot"                                          # Name of the application
    DJANGODIR=/var/web/the_gelatospot              # Django project directory
    SOCKFILE=/var/web/the_gelatospot/gunicorn.sock     # we will communicte using this unix socket
    USER=ec2-user
    GROUP=ec2-user                                             # the user to run as, the group to run as
    NUM_WORKERS=3                                     # how many worker processes should Gunicorn spawn
    DJANGO_SETTINGS_MODULE=settings
    #DJANGO_SETTINGS_MODULE=the_gelatospot.settings             # which settings file should Django use
    #DJANGO_WSGI_MODULE=the_gelatospot.wsgi                   # WSGI module name
    DJANGO_WSGI_MODULE=wsgi
    
    echo "Starting $NAME as `the_gelatospot`"
    
    # Activate the virtual environment
    cd $DJANGODIR
    source ../mez_env/bin/activate
    export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
    export PYTHONPATH=$DJANGODIR:$PYTHONPATH
    
    # Create the run directory if it doesn't exist
    RUNDIR=$(dirname $SOCKFILE)
    test -d $RUNDIR || mkdir -p $RUNDIR
    cd ..
    # Start your Django GUnicorn
    # Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
    exec gunicorn -k eventlet ${DJANGO_WSGI_MODULE}:application \
      --name $NAME \
      --workers $NUM_WORKERS \
      --log-level=debug \
      --bind=unix:$SOCKFILE
    

    这是一个不能作为服务工作的服务(nginx 抱怨连接过早关闭并且没有应用程序日志数据通过)。

    #!/bin/bash
    
    DJANGODIR=/var/web/the_gelatospot/                # Django project directory
    cd $DJANGODIR
    source ../mez_env/bin/activate
    uwsgi --ini uwsgi.ini
    

    还有 uwsgi.ini:

    [uwsgi]
    uid = 222
    gid = 500
    socket = /var/web/the_gelatospot/uwsgi.sock
    virtualenv = /var/web/mez_env
    chdir = /var/web/the_gelatospot/
    wsgi-file = /var/web/the_gelatospot/wsgi.py
    pythonpath = ..
    env = DJANGO_SETTINGS_MODULE=the_gelatospot.settings
    die-on-term = true
    master = true
    chmod-socket = 666
    ;experiment using uwsgitop
    worker = 1
    ;gevent = 100
    processes = 1
    daemonize = /var/log/nginx/uwsgi.log
    logto = /var/log/nginx/uwsgi.logi
    log-maxsize = 10000000
    enable-threads = true
    

    我去年从 gunicorn 转到 uWSGI,直到现在我都没有遇到任何问题,它似乎也比 gunicorn 快一点。现在我正在考虑坚持gunicorn。它变得越来越好,安装了 eventlet 后提供了更好的数字,并且更易于配置。

    希望此解决方法有所帮助。我仍然想知道 uWSGI 和 nginx 的问题,但我很难过。

    更新: 因此,使用 gunicorn 可以让我将服务器作为服务运行,并且在玩夹层时遇到了这个错误:FileSystemEncodingChanged

    为了解决这个问题,我在这里找到了解决方案: https://groups.google.com/forum/#!msg/mezzanine-users/bdln_Y99zQw/9HrhNSKFyZsJ

    我不得不稍微修改一下,因为我不使用 supervisord,我只使用 upstart 和一个 shell 脚本。我在我的 mez_server.sh 文件中执行 gunicorn 之前添加了这个:

    export LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8
    exec gunicorn -k eventlet ${DJANGO_WSGI_MODULE}:application \
      --name $NAME \
      --workers $NUM_WORKERS \
      --log-level=debug \
      --bind=unix:$SOCKFILE
    

    我也尝试过使用 uWSGI 进行此修复(比使用 uwsgi.ini 短很多):

    export LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8
    exec uwsgi --ini uwsgi.ini
    

    我仍然坚持使用 gunicorn,因为它仍然可以解决问题并引导我朝着正确的方向解决问题。即使使用这些参数,uWSGI 也没有在日志文件中提供任何输出,我感到非常失望,我只看到了服务器启动过程,仅此而已:

    daemonize = /var/log/nginx/uwsgi.log
    logto = /var/log/nginx/uwsgi.logi
    

    当 nginx 不断抛出断开连接错误时,uWSGI 就像什么都没发生一样坐在那里。

    【讨论】:

    • 很抱歉我上面的解决方案没有帮助到你。我也挣扎了一个多星期。这可能非常令人沮丧。一定是缺少某些目录的权限,这不容易找到。 Gunicorn 更容易设置,但也需要 150 MB 内存。 uWSGI 的内存占用很小,但很难设置。
    • 我现在修复了它,但仍然要使用 gunicorn,它似乎引导我走上了解决问题的正确道路。对我来说问题是语言环境问题,我必须在控制进程启动的任务 (mez_server.sh) 中设置这些变量:export LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF -8
    • 你是对的,uWSGI 占用了 0.7% 的内存(13-17MB),不到 1%,对于相同的任务,但我将工人从 1 增加到 3,每个工人都在gunicorn 大约是 3-7% (20-40MB),加上 master task 是 2%。我真的很喜欢同时使用两者,并且没有发现 1 比另一个更难配置。除非我真的需要减少内存占用,否则我会坚持使用 gunicorn。 PS。 uwsgi 的真空参数对我不起作用,僵尸进程保持运行,修复它的是这个参数:die-on-term = true
    • 经过很长时间我在新服务器上设置了nginx和uwsgi。我现在得到你的上行问题。在搬到 Gunicorn 之前你能解决这些问题吗?
    • 我找到了原因。我明天会在我的答案中添加更多细节。
    【解决方案3】:

    经过近 2 天的工作,我终于解决了这个问题。我希望这个解决方案能帮助其他遇到类似问题的烧瓶/uwsgi 用户。

    我有两个主要问题导致了这种情况。

    1) 发现守护进程问题的最佳方法显然是日志文件和更简洁的结构。

    sudo vim /etc/init/uwsgi.conf

    将守护程序脚本更改为以下内容:

    # file: /etc/init/uwsgi.conf
    description "uWSGI server"
    
    start on runlevel [2345]
    stop on runlevel [!2345]
    respawn
    exec /home/ubuntu/uwsgi-1.9.12/uwsgi -c /myproject/uwsgi.ini
    

    vim /myproject/uwsgi.ini

    [uwsgi]
    socket = /tmp/uwsgi.sock
    master = true
    enable-threads = true
    processes = 5
    chdir= /myproject/F11/Engineering
    module=F11:app
    virtualenv = /myproject/myproject-env/
    uid =  www-data
    gid = www-data
    logto = /myproject/error.log
    

    这是设置守护程序的更简洁的方法。还要注意最后一行如何设置日志文件。最初我将日志文件设置为/var/log/uwsgi/error.log。经过大量的汗水和泪水,我意识到守护进程以www-data 运行,因此无法访问/var/log/uwsgi/error.log,因为error.log 归root:root 所有。这使得 uwsgi 静默失败。

    我发现将日志文件指向我自己的/myproject 效率更高,其中守护程序保证以www-data 访问。并且不要忘记让www-data 可以访问整个项目,否则守护程序将失败并显示Internal Server error message。 -->

    sudo chown www-data:www-data -R /myproject/
    

    重启uwsgi守护进程:

    sudo service uwsgi restart
    

    2) 现在您需要注意三个日志文件:

    • tail -f /var/log/upstart/uwsgi.log --> 在启动时显示您的守护进程存在问题

    • tail -f /var/log/nginx/error.log --> 当 wsgi 访问被拒绝时显示权限问题,通常是因为 /tmp/uwsgi.sock 文件归 root 而不是 www-data 所有。在这种情况下,只需删除 sock 文件 sudo rm /tmp/uwsgi.sock

    • tail -f /myproject/error.log --> 显示应用程序中 uwsgi 抛出的错误

    这种日志文件组合帮助我发现在我的 Flask 应用程序中使用 Flask-Babel 进行了错误的导入。从这个意义上说很糟糕,我使用库的方式是回退到系统的语言环境来确定日期时间格式。

    File "/myproject/F11/Engineering/f11_app/templates/show_records.html", line 25, in block "body"
        <td>{{ record.record_date|format_date }}</td>
      File "./f11_app/filters.py", line 7, in format_date
        day = babel_dates.format_date(value, "EE")
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 459, in format_date
        return pattern.apply(date, locale)
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 702, in apply
        return self % DateTimeFormat(datetime, locale)
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 699, in __mod__
        return self.format % other
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 734, in __getitem__
        return self.format_weekday(char, num)
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 821, in format_weekday
        return get_day_names(width, context, self.locale)[weekday]
      File "/myproject/myproject-env/local/lib/python2.7/site-packages/babel/dates.py", line 69, in get_day_names
        return Locale.parse(locale).days[context][width]
    AttributeError: 'NoneType' object has no attribute 'days'
    

    这是我使用 Flask 过滤器的方式:

    import babel.dates as babel_dates
    
    @app.template_filter('format_date')
    def format_date(value):
        day = babel_dates.format_date(value, "EE")
        return '{0} {1}'.format(day.upper(), affix(value.day))
    

    最奇怪的是,这段代码在开发环境中运行良好(!)。从命令行将 uwsgi 作为 root 进程运行时,它甚至可以正常工作。但是当由 www-data 守护进程运行时它会失败。这一定与语言环境的设置方式有关,而 Flask-Babel 正试图回退到该语言环境。

    当我像这样更改导入时,它终于与守护进程一起工作了:

    from flask.ext.babel import format_date  
    
    @app.template_filter('format_date1')
    def format_date1(value):
        day = format_date(value, "EE")
        return '{0} {1}'.format(day.upper(), affix(value.day))
    

    因此,在使用 Eclipse/Aptana Studio 时要小心,因为它试图为代码中的类选择正确的命名空间。真的会变丑。

    自从 2 天以来,它现在作为 Amazon Ec2 (Ubuntu 12.04) 上的 uwsgi 守护程序工作得非常好。我希望这个经验可以帮助到 Python 开发者。

    【讨论】:

    猜你喜欢
    • 2016-10-07
    • 2023-03-02
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 2013-06-25
    • 1970-01-01
    • 2013-02-04
    相关资源
    最近更新 更多