部署项目Nginx+Tornado+Supervisor
Tornado
Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。
Tornado 由于内置了支持epoll/kqueue 等高效网络库,而具备了处理高并发的能力。
import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web import tornado.httpclient from tornado.options import define, options define("port", default=8001, help="run on the given port ", type=int) define("log_path", default='/tmp', help="log path ", type=str) class IndexHandler(tornado.web.RequestHandler): def get(self): # 接受GET的请求 headers = self.request.headers for k, v in headers.items(): print k, v greeting = self.get_argument('greeting', 'Hello') self.write('%s , friendly user! %s ' % (greeting, headers)) def write_error(self, status_code, **kwargs): self.write('Holly Shit Error %s' % status_code) if __name__=="__main__": # 启动tornado实例 tornado.options.parse_command_line() app = tornado.web.Application(handlers=[(r"/", IndexHandler)]) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
执行,这样就运行了Tornado服务器, 可以等待访问了
$ python hello.py --port=8000 $ curl http://localhost:8000/ Hello, friendly user!
Tornado简易项目就搭建完毕
使用Nginx作为反向代理
一个代理服务器是一台中转客户端资源请求到适当的服务器的机器。一些网络安装使用代理服务器过滤或缓存本地网络机器到Internet的HTTP请求。因为我们将运行一些在不同TCP端口上的Tornado实例,因此我们将使用反向代理服务器:客户端通过Internet连接一个反向代理服务器,然后反向代理服务器发送请求到代理后端的Tornado服务器池中的任何一个主机。代理服务器被设置为对客户端透明的,但它会向上游的Tornado节点传递一些有用信息,比如原始客户端IP地址和TCP格式。
我们的服务器配置如图8-1所示。反向代理接收所有传入的HTTP请求,然后把它们分配给独立的Tornado实例。
upstream tornados{ server 127.0.0.1:8020; server 127.0.0.1:8021; server 127.0.0.1:8022; } proxy_next_upstream error; server { listen 80; server_name www.tornado.cc; # 静态文件直接由Nginx处理 location /static/{ alias /data/web/advance_python/tornado_asyn/img/; expires 24h; } location /{ proxy_pass_header Server; proxy_set_header Host $http_host; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; # 把请求方向代理传给tornado服务器,负载均衡 proxy_pass http://tornados; } }
使用Supervisor监控Tornado进程
Supervisord是用Python实现的一款非常实用的进程管理工具,
-
安装 配置
sudo apt-get install supervisor
创建配置文件
echo_supervisord_conf > /etc/supervisord.conf -
Supervisor 配置文件 /etc/supervisor/conf.d
#vim /etc/supervisor/conf.d/project_name.conf # 为了方便管理,增加一个tornado组 [group:tornados] programs=tornado-0,tornado-1,tornado-2 # 分别定义三个tornado的进程配置 [program:tornado-0] # 进程要执行的命令 command=python /data/web/advance_python/tornado_asyn/hello.py --port=8020 directory=/data/web/advance_python/tornado_asyn/ user=www-data # 自动重启 autorestart=true redirect_stderr=true # 日志路径 stdout_logfile=/home/lidongwei/log/supervisor/tornado/tornado0.log loglevel=info [program:tornado-1] command=python /data/web/advance_python/tornado_asyn/hello.py --port=8021 directory=/data/web/advance_python/tornado_asyn/ user=www-data autorestart=true redirect_stderr=true stdout_logfile=/home/lidongwei/log/supervisor/tornado/tornado1.log loglevel=info [program:tornado-2] command=python /data/web/advance_python/tornado_asyn/hello.py --port=8022 directory=/data/web/advance_python/tornado_asyn/ autostart=true autorestart=true stopasgroup=true priority=20 user=website redirect_stderr=true stdout_logfile=/var/situation/%(program_name)s.std stdout_logfile_maxbytes=50MB stdout_logfile_backups=1 loglevel=info environment=WINGS_WORKER_ID=%(process_num)s,WINGS_PROG_NAME="webcgi",PYTHON_EGG_CACHE=/tmp/.python-eggs
supervisor常用命令
supervisorctl tail programname stdout # 查看动态日志输出 # 启动supervisord supervisord # 使用默认的配置文件 /etc/supervisord.conf supervisord -c /etc/supervisord.conf # 明确指定配置文件 supervisord -u user # 使用user用户启动supervisord supervisorctl update # 更新新的配置到supervisord supervisorctl reload # 重新启动配置中的所有程序 supervisorctl start program_name # 启动某个进程(program_name=你配置中写的程序名称) supervisorctl # 查看正在守候的进程 supervisorctl stop program_name # 停止某一进程 (program_name=你配置中写的程序名称) supervisorctl restart program_name # 重启某一进程 (program_name=你配置中写的程序名称) supervisorctl stop all # 停止全部进程 注意:显示用stop停止掉的进程,用reload或者update都不会自动重启 sudo service supervisor restart # 重启supervisor
关闭supervisor 方式二
# 关闭supervisor启动脚本 supervisorctl stop all # 关闭supervisord服务 ps -aux | grep supervisor kill pid
查看、操作进程状态
[/etc/supervisor/conf.d]$ sudo supervisorctl
[sudo] password for lidongwei:
tornados:tornado-0 RUNNING pid 10012, uptime 1:22:04
tornados:tornado-1 RUNNING pid 10011, uptime 1:22:04
tornados:tornado-2 RUNNING pid 10013, uptime 1:22:04
# 停止运行tornado-1服务器进程
supervisor> stop tornados:tornado-1
tornados:tornado-1: stopped
supervisor> status
tornados:tornado-0 RUNNING pid 10012, uptime 1:23:19
tornados:tornado-1 STOPPED Mar 12 06:46 PM
tornados:tornado-2 RUNNING pid 10013, uptime 1:23:19
# 停止运行整个tornado服务器进程组
supervisor> stop tornados:
tornado-0: stopped
tornado-2: stopped
supervisor> status
tornados:tornado-0 STOPPED Mar 12 06:50 PM
tornados:tornado-1 STOPPED Mar 12 06:46 PM
tornados:tornado-2 STOPPED Mar 12 06:50 PM
supervisorctl 命令介绍
停止某一个进程,program_name 为 [program:x] 里的 x
supervisorctl stop program_name
启动某个进程
supervisorctl start program_name
重启某个进程
supervisorctl restart program_name
结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)
supervisorctl stop groupworker:
结束 groupworker:name1 这个进程 (start,restart 同理)
supervisorctl stop groupworker:name1
停止全部进程,注:start、restart、stop 都不会载入最新的配置文件
supervisorctl stop all
载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl reload
根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl update
总结
Supervisor和你系统的初始化进程一起工作,并且它应该在系统启动时自动注册守护进程。当supervisor启动后,程序组会自动在线。默认情况下,Supervisor会监控子进程,并在任何程序意外终止时重生。如果你想不管错误码,重启被管理的进程,你可以设置autorestart为true。
Supervisor不只可以使管理多个Tornado实例更容易,还能让你在Tornado服务器遇到意外的服务中断后重新上线时泰然处之。
三个tornado进程都正常运行,并且比逐个管理方便的多
问题汇总
Error: Another program is already listening on a port that one of our HTTP servers is configured to use. Shut this program down first before starting supervisord.
解决方法:
supercisorctl stop all unlink /var/run/supervisor.sock
unix:///var/run/supervisor/supervisor.sock no such file
解决方法:
chmod 777 /run
IOError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
解决方法:
sudo chmod 777 /var/log/supervisor/supervisord.log
Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)
解决方法:
sudo chmod 777 /run
Unlinking stale socket /var/run/supervisor.sock
解决方法:
unlink /var/run/supervisor.sock
supervisor stop 进程时,服务的子进程未退出/python 多进程 监听信号 实现所有进程同时退出
使用 supervisor 管理进程,如果被管理的项目是多进程模式,就需要注意一下:
- 程序内是否有接收处理 kill -15 signal。
- python 程序无法监听 kill -9 信号(其他编程语言没有了解,但按理说应该是一样的),也无法拒绝(kill -9 是立马强制结束进程),所以不要随便使用 kill -9 结束一个进程(kil params[pid], 会允许程序延迟退出,所以程序内可以监听 kill -15 signal),如果使用 kill -9 结束了一个主进程,那么它的子进程就会成为孤儿进程,使用 kill -9 结束某个子进程,就会有可能导致其成为僵尸进程。
- 如果确实有需要强制结束某个进程,为了安全起见,可以使用 kill -9 -params[gpid] 代替, 如 kill -9 -7634,强制立马结束 7634 进程组内的所有进程,正常情况下,主进程的 pid 和该进程组的 gpid 相同,但意义不一样。
- kill -15 (默认)和 kill -9 是两种不同的信号,python 程序可以监听 kill -15(也就理所当然的可以拒绝kill -15),但是无法监听 kill -9(也就无法拒绝)
如果程序没有监听并处理 kill signal 就需要到相应服务的 supervisor 管理配置文件声明:stop 服务时,允许 supervisor stop 该进程组下的所有进程:
killasgroup=true # 允许杀死该进程组内的所有进程 stopasgroup=true # 允许停止该进程组内的所有进程
Supervisor捕获不到python的Print
但是查看xxx.log一直都是空文件,是什么原因可能导致这种情况呢?如何才能记录日志到文件呢?
示例代码参见 https://github.com/surfly/gevent/blob/master/examples/echoserver.py
可以试试用python -u xxx.py启动代码,这样没有缓冲
-u : force the binary I/O layers of stdout and stderr to be unbuffered; stdin is always buffered; text I/O layer will be line-buffered; also PYTHONUNBUFFERED=x
试试
sys.stdout.flush()
或者
command = /usr/bin/python -u /opt/xxx/xxx.py
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/tornado/web.py", line 1592, in _execute
result = yield result
File "/usr/local/lib/python3.6/dist-packages/tornado/gen.py", line 1133, in run
value = future.result()
concurrent.futures._base.CancelledError
本次错误是数据库配置错误,连接不上,导致超时,表现有
supervisor: couldn't chdir to /home/Server: EACCES
supervisor: child process was not spawned
python3: can't open file '/home/server.py': [Errno 13] Permission denied
open failed: EACCES (Permission denied),把用户改为root
[program:tornado-2] command=python /data/web/advance_python/tornado_asyn/hello.py --port=8022 directory=/data/web/advance_python/tornado_asyn/ user=root autorestart=true redirect_stderr=true stdout_logfile=/home/lidongwei/log/supervisor/tornado/tornado2.log loglevel=info
方法二:权限不够
sudo supervisorctl start all
pkg_resources.DistributionNotFound: The 'supervisor==3.1.3' distribution was not found and is required by the application
关于python3.x上supervisor安装问题?: 知乎:https://www.zhihu.com/question/55325792
参考地址「randomparty」 原文链接:https://blog.csdn.net/RandomParty/article/details/81184568
sudo apt-get install supervisor
通过这种方式安装的supurvisor只能安装在python2中,但可以运行python3的项目
基本上所有的 Linux 都同时预装了 Python 2.x 和 Python 3.x 版本,并且调用 python 命令时默认运行的 Python 2,运行 Python 3 只需要 调用 python3 即可。
卸载supervisor
sudo apt-get purge supervisor sudo pip3 uninstall supervisor
1、使用python2安装supervisor
sudo pip2 install supervisor -i https://pypi.tuna.tsinghua.edu.cn/simple/ sudo sh -c 'echo_supervisord_conf > /etc/supervisord.conf' sudo mkdir /etc/supervisor.d
vim /etc/supervisord.conf
[include] ;files = relative/directory/*.ini files = supervisor.d/*.conf
启动supervisor
sudo supervisord -c /etc/supervisord.conf
2、安装支持python3的supervisor
github : https://github.com/Supervisor/supervisor/tree/master/supervisor
步骤:setup.py
- 先下载你要安装的包,并解压到磁盘下;
- 进入到该文件的setup.py 目录下 ,打开cmd,并切换到该目录下;
- 先执行 python setup.py build
- 然后执行 python setup.py install

浙公网安备 33010602011771号