uWSGI作为进程运行,但不作为守护进程。

17

为了我的当前Flask部署,我不得不设置一个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 [error] 743#0: *296 upstream prematurely closed connection while reading response header from upstream, client: xx.161.xx.228, server: myproject.com, request: "GET /show_records/2013/6 HTTP/1.1", upstream: "uwsgi://unix:///tmp/uwsgi.sock:", host: "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
@joe,就是Ubuntu 12.04 LTS。我刚在我的笔记本电脑上运行13.04测试了一下,出现了完全相同的问题。这很好,因为可以复制。 - Houman
听起来守护程序是在不同的用户下运行或者有访问不同配置文件的权限...这不是一个提示吗:https://dev59.com/CnRC5IYBdhLWcg3wJNqf - Paul
3个回答

21

经过近两天的努力,我终于解决了这个问题。我希望这个解决方案能够帮助到其他遇到类似问题的Flask/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,因为该文件是由root:root拥有的。这使得uwsgi默默地失败了。

我发现只需将日志文件指向我的/myproject,在那里守护进程可以保证作为www-data拥有访问权限。还要记得将整个项目都授予www-data访问权限,否则守护进程将因为内部服务器错误消息而失败。-->

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))

最奇怪的是,这段代码在开发环境中完美运行(!)。即使从命令行以root进程运行uwsgi也可以正常工作。但是当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天前以来,它已经在亚马逊Ec2(Ubuntu 12.04)上完美地作为uwsgi守护进程工作。希望这种经验可以帮助同样是Python开发人员的同行。

很高兴听到您已经解决了问题,但我建议使用以下方式:https://library.linode.com/web-servers/nginx/python-uwsgi/ubuntu-12.04-precise-pangolin。我在许多服务器上都使用过它。 - Joe

0
我放弃了,没有生成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版本的其他应用程序,它们都是mezzanine 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让我能够将服务器作为服务运行,当我在mezzanine中玩耍时,遇到了这个错误: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的内存占用很小,但难以设置。 - Houman
我现在已经修复了,但仍然打算使用gunicorn,因为它似乎引导我走上了解决问题的正确道路。对我来说问题是一个本地化问题,我必须在控制进程启动的任务(mez_server.sh)中设置这些变量:export LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8,LC_LANG=en_US.UTF-8。 - radtek
你说得对,uWSGI 占用了 0.7% 的内存(13-17MB),少于 1%,但是我将工作进程从 1 增加到 3 后,每个工作进程在 gunicorn 上约占 3-7% 的内存(20-40MB),而主任务则占用 2%。我非常喜欢同时使用它们两个,并没有发现一个比另一个更难配置。除非我真的需要减少内存占用,否则我会坚持使用 gunicorn。顺便说一下,对于 uwsgi,vacuum 参数对我不起作用,僵尸进程仍然会运行,解决方法是这个参数:die-on-term = true。 - radtek
经过很长时间,我正在为新服务器设置nginx和uwsgi。我现在遇到了您的上游问题。在转移到Gunicorn之前,您能解决它们吗? - Houman
我找到了原因。明天我会在我的回答中添加更多细节。 - Houman
当我切换回gunicorn时,它告诉我错误是什么,不记得是什么了,因为那是很久以前的事了。 - radtek

-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


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