设为首页 收藏本站
查看: 1363|回复: 0

[经验分享] python bottle使用多个端口(多个进程)提升并发数

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-5-21 08:51:56 | 显示全部楼层 |阅读模式
我的程序是用python结合bottle框架写的,但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用,但其性能低下,在服务器负载不断增加的时候也许会是性能瓶颈, 一次只能响应一个请求)。为了提升程序的处理能力,首先要启用多线程,即在程序中使用gevent( 大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和进程 (fork)比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。gevent 模块添加了 greenlet 的支持。 greenlet 和传统的线程类似,但其创建只需消耗很少的资源。基于 gevent 的服务器可以生成成千上万的 greenlet,为每个连接分配一个 greenlet 也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。)。只需要在run中加上 server='gevent',如下:
1
2
3
4
import gevent
from gevent import  monkey.patch_all()
      代码段……
run(host='0.0.0.0', port=8080, server='gevent')




尽管使用了多线程模式,但这些线程都是跑在一个进程里,所以需要开启多个进程来进一步提升并发处理能力,因此在启用脚本的时候,在run(port=)里,端口号不能写死,应该使用变量来传递,如下代码(在脚本执行时,在需带一个参数,这个参数是大于1024的整数,否则报错停止脚本):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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改写的):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
#!/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



  • 效果图:
    shell.jpg

    本人的代码是用svn管理的,所以上传代码后,SVN钩子会调用shell脚本来重启这些程序,以下是SVN钩子代码:
    1
    2
    3
    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代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    #定义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反向代理的部分代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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就会平均轮洵分配到每个端口上去,实现了多进程,多线程的运行模式,更有效的提升了并发处理能力


    运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-69018-1-1.html 上篇帖子: Python编译错误集锦 下篇帖子: python访问sql server安装、配置、代码示例 bottle python
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表