python bottle使用多个端口(多个进程)提升并发数

我的程序是用python结合bottle框架写的,但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用,但其性能低下,在服务器负载不断增加的时候也许会是性能瓶颈, 一次只能响应一个请求)。为了提升程序的处理能力,首先要启用多线程,即在程序中使用gevent( 大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和进程 (fork)比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。gevent 模块添加了 greenlet 的支持。 greenlet 和传统的线程类似,但其创建只需消耗很少的资源。基于 gevent 的服务器可以生成成千上万的 greenlet,为每个连接分配一个 greenlet 也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。)。只需要在run中加上 server=‘gevent‘,如下:

import gevent
from gevent import  monkey.patch_all()
      代码段……
run(host=‘0.0.0.0‘, port=8080, server=‘gevent‘)

尽管使用了多线程模式,但这些线程都是跑在一个进程里,所以需要开启多个进程来进一步提升并发处理能力,因此在启用脚本的时候,在run(port=)里,端口号不能写死,应该使用变量来传递,如下代码(在脚本执行时,在需带一个参数,这个参数是大于1024的整数,否则报错停止脚本):

import gevent,sys
from gevent import  monkey.patch_all()
#获取端口号
try:
    portnum = int(sys.argv[1])
except Exception,e:
    print "请带上整数类型的端口号启动此程序"
    logging.error("请带上整数类型的端口号启动此程序")
    sys.exit(1)
if portnum <= 1024:
    print "端口号请大于1024!"
    logging.error("端口号请大于1024!")
    sys.exit(1)
      代码段……
run(host=‘0.0.0.0‘, port=portnum , server=‘gevent‘)

执行方式如下(osyw.py是我python程序名):

python osyw.py 1124

如果纯靠手动操作这些,在生产上,很不方便,所以我写了个shell来管理,这个shell定义了多个端口号,然后去循环启用或停止python进程,脚本大概如下(是用httpd改写的):

 
#!/bin/bash
#
# osyw        Startup script for the osyw HTTP Server
#
# chkconfig: - 88 18
# description: osyw
# processname: osyw
# config: 
# config: /home/bottle/osyw/
# pidfile: /var/run/osyw.pid
#
### BEGIN INIT INFO
# Provides: osyw
# Short-Description: start and stop osyw HTTP Server
# Description: The osyw HTTP Server is an extensible server 
#  implementing the current HTTP standards.
### END INIT INFO
# Source function library.
. /etc/rc.d/init.d/functions
# Path to the apachectl script, server binary, and short-form for messages.
port_list=(8811 8812 8813)     #设置了3个端口
#pidfile=‘/var/run/osyw.pid‘
pro_path=‘/var/www/osyw/osyw.py‘    #程序路径
log_path=‘/var/www/osyw/log/access.log‘    #访问日志路径
RETVAL=0
start() {
        for i in ${port_list[*]}
        do
                p=`/usr/sbin/lsof -i :${i} |wc -l`
                if [ ${p} -ge 2 ]
                then
                        action "osyw ${i} already exists !" /bin/false
                else
                        /usr/bin/python ${pro_path} ${i} &>> ${log_path}
                RETVAL=$?
                        if [ ${RETVAL} == 0 ]
                        then
                                action "osyw ${i} start ..." /bin/true
                        else
                                action "osyw ${i} start ..." /bin/false
                        fi
                fi
        done
    return $RETVAL
}
stop() {
        for i in ${port_list[*]}
        do
                pidfile="/var/run/osyw_${i}.pid"
                if [ -f ${pidfile} ]
                then
                        pid=`cat ${pidfile}`
                        kill -9 ${pid}
                        RETVAL=$?
                        if [ ${RETVAL} == 0 ]
                    then
                    action  "osyw ${i} stop ..." /bin/true
                    else
                    action  "osyw ${i} stop ..." /bin/false
                        fi
                        rm -f ${pidfile}
                else
                        action  "osyw ${i} Has stopped !" /bin/false
                fi
        done
}
# See how we were called.
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status -p ${pidfile} ‘osyw‘
        RETVAL=$?
        ;;
  restart)
        stop
        sleep 2
        start
        ;;
  condrestart|try-restart)
        if status -p ${pidfile} ‘osyw‘ >&/dev/null; then
                stop
                start
        fi
        ;;
  force-reload|reload)
        reload
        ;;
  *)
        echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}"
        RETVAL=2
esac
exit $RETVAL

效果图:

本人的代码是用svn管理的,所以上传代码后,SVN钩子会调用shell脚本来重启这些程序,以下是SVN钩子代码:

export LANG=en_US.UTF-8
/usr/bin/svn update --username xxxx --password xxxxxxxx /var/bottle
/bin/bash /etc/init.d/osyw restart

当然,为了结合shell,python程序里也要做一些处理,如自动把程序转为后台守护进程,然后把进程ID写入文件,以下是关键的python代码:

#定义PID路径  
pid_path = ‘/var/run/osyw_%s.pid‘ % portnum    
  
def daemonize():  
    """把本脚本转为守护进程"""  
    try:  
        pid=os.fork()  
        if pid>0:  
            sys.exit(0)  
    except Exception,e:  
        logging.error(e)  
        sys.exit(1)  
  
    os.chdir(‘/‘)  
    os.umask(0)  
    os.setsid()  
  
    try:  
        pid=os.fork()  
        if pid>0:  
            sys.exit(0)  
    except Exception,e:  
        logging.error(e)  
        sys.exit(1)  
  
    PID = str(os.getpid())  
    with open(pid_path,‘w‘) as f:  
        f.write(PID)  
  
其它代码段……  
  
if __name__ == ‘__main__‘:  
    try:  
        from oscore import setting    #导入配置文件
        if setting.status == ‘online‘:    #如果配置中是线上的,则程序转入后台运行
            daemonize()  
    except Exception:  
        pass  
  
    app = default_app()  
    app = SessionMiddleware(app, session_opts)      #sessionMiddleware是session插件
    run(app=app,host=‘0.0.0.0‘, port=portnum,server=‘gevent‘)

最好,用nginx代理来负载这些端口,我nginx和python程序是安装在同一台服务器上的:

以上是nginx反向代理的部分代码:

upstream myweb {
#ip_hash;
server 192.168.1.240:8811 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.1.240:8812 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.1.240:8813 weight=4 max_fails=2 fail_timeout=30s;
}
server {
    listen       80;
        server_name  192.168.1.240;
    location /
        {
        proxy_pass http://myweb;
        proxy_set_header Host  $host;
        proxy_set_header X-Forwarded-For  $remote_addr;
        proxy_cache_key $host$uri$is_args$args;
        }
        access_log  off;
        }

做完这些后,当访问80端口时,nginx就会平均轮洵分配到每个端口上去,实现了多进程,多线程的运行模式,更有效的提升了并发处理能力

时间: 2024-10-25 01:53:24

python bottle使用多个端口(多个进程)提升并发数的相关文章

python bottle使用多个端口(多个进程)提高并发

我的程序是用python结合bottle框架写的,但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面.这个单线程的 HTTP 服务器在开发的时候特别有用,但其性能低下,在服务器负载不断增加的时候也许会是性能瓶颈, 一次只能响应一个请求).为了提升程序的处理能力,首先要启用多线程,即在程序中使用gevent( 大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价.尽管和进程 (fork)比起来,线程还是挺便宜的.但

让python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求

这两天在用python的bottle框架开发后台管理系统,接口约定使用RESTful风格请求,前端使用jquery ajax与接口进行交互,使用POST与GET请求时都正常,而Request Method使用PUT或DELETE请求时,直接爆“HTTP Error 405: Method Not Allowed”错误.而ajax提交的Request Method值DELETE也变成了OPTIONS了. 度娘了好多答案,要么说是浏览器不支持,要么说自己重新封装jquery,还有其他的一些方法...

python bottle框架(WEB开发、运维开发)教程

教程目录 一:python基础(略,基础还是自己看书学吧) 二:bottle基础 python bottle web框架简介 python bottle 框架环境安装 python bottle 框架基础教程:路由(url定义) python bottle 框架基础教程:HTTP 请求方法 python bottle 框架基础教程:模板使用 python bottle 框架基础教程:模板语法 python bottle 框架基础教程:模板继承 python bottle 框架基础教程:静态资源

根据端口查找占用进程——API方法

转自http://blog.csdn.net/tht2009/article/details/40458425 在开发联网应用时,常常需要申请.绑定端口,这时就需判断哪些端口可用或指定端口是否被占用.在命令行窗口下,输入"netstat -ano"命令可以显示查看当前端口占用情况.如何在程序代码中实现这个功能呢? 当然也可以执行cmd命令,通过分析返回文本来判断.其实,Windows已经提供了获取当前网络连接状态的API,这些API都位于动态库Iphlpapi.dll中.跟查看端口情况

netstat--查看服务器[有效]连接数--统计端口并发数--access.log分析

简介 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等. 输出信息含义 执行netstat后,其输出结果为 ? ? Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 2 210.

Python自动化开发从浅入深-进阶(进程)

今天的作业涉及到了进程,那么就用作业来说明进程的用法: 这里我们定义了2个函数 getParamikoCmd 和 batchCmd,用于批量向远程服务器发送ssh命令,并返回执行结果. 执行batchCmd进行一些用户交互和参数获取(这里是一组服务器分组信息),循环发起进程批量执行ssh命令,每个进程调用getParamikoCmd 函数进行ssh命令执行. 进程之间是相互独立的,数据不会相互共享,这样可独立完成其任务而不会相互影响. def getParamikoCmd(groupName,s

老男孩教育每日一题-第101天-如何通过端口查找出进程所在目录?

参考答案: 第一步-找到端口对应的进程的号 [[email protected] ~]# ss -lntup |grep :22 tcp    LISTEN     0      128                   :::22                   :::*      users:(("sshd",1467,4)) tcp    LISTEN     0      128                    *:22                    *:*

Windows - 杀死占用某个端口号的进程

Windows不像Linux,Unix那样,ps -ef 查出端口和进程号,然后根据进程号直接kill进程. Windows根据端口号杀死进程要分三步: 第一步 根据 端口号 寻找 进程号 C:\>netstat -aon|findstr "9050" TCP 127.0.0.1:9050 0.0.0.0:0 LISTENING 2056 看到了吗,端口被进程号为2056的进程占用,继续执行下面命令: 第二步 根据 进程号 寻找 进程名称 C:\>tasklist|find

如何关闭指定端口占用的进程

1.查找对应的端口占用的进程,找到占用端口对应的程序的PID号: netstat  -aon|findstr  "9001" 2.根据PID号找到对应的程序 ,找到对应的程序名: tasklist|findstr "6676" 3.结束该进程: taskkill /f /t /im java.exe