9月 10

开源的webdeploy部署系统

介绍
  Web部署工具。主要针对小型网络环境进行,有部署、回退、权限管理、日志记录等功能。
  此部署系统是用Python2.6(以上)+Tornado开发,以调用命令的方式进行工作,用WEB界面形式进行管理。该系统需要用到第三方工具,如ssh、rsync等。所使用到的第三方工具的安装,都已经编写在安装脚本中,只要在能连接互联网的机器上可以使用安装脚本自动完成。但是基础的python环境需要手动安装,如果系统自带的版本过低,建议安装新版本(该系统还不能使用python3.x)。该工具使用推送和远程调用命令方式,所以没有agent端,部署配置后既可以使用。由于属于个人开发,所以我的操作系统为CentOS、raspberry pi、pcduino。
所用到的模块示意图如下:
deploy_tool模块20130906
  该系统可以单进程或多进程进行部署,多进程是使用线程方式进行控制,建议为3个不要超出。在单进程情况下10个Tomcat服务部署完毕(传送文件网络耗时按3秒钟算)大约一分钟,因为tomcat需要重启耗时比较长,所使用时间大约是php、python、ruby类代码的3倍。使用多线程部署Tomcat类大约要35-40秒。此系统对于JAVA依赖于tomcat的服务适合在20个左右的服务环境中使用。脚本类的大约在50到60个服务环境使用。如果想以更快的方法,部署跟多的服务器,可以使用推送部署脚本的方式进行,后面在做介绍。
注意两点:1)以上所说服务环境是指服务程序部署的套数,而不是物理服务器的台数。
2)如果部署tomcat下的服务,为了避免因为环境变量造成的问题,需要编写一个适合远程使用脚本。可以http://www.simonzhang.net/?p=1951

安装介绍
安装环境要求
  操作系统:CentOS 或Raspberry pi 。基础运行环境:python2.6或python2.7。数据库:mysql。
  原则上可以运行在任何python2.6以上版本搭建的linux服务器上,但是本人只测试了CentOS和Raspberry pi。演示环境为Raspberry pi。

安装步骤
  首先创建数据。数据库创建部分不详细记录。如获得数据库信息:账号:deploy、密码:123456、库名为:deploytest、数据库IP为:192.168.1.130。数据库使用UTF-8编码。
  将deploy代码放到相应目录中。(提醒:因为此系统安装需要安装第三方的框架和工具,建议在root权限下安装,并且装过程需要连接互联网)。测试过程将代码放置到/program/deploytest目录中。
  开始安装。进入部署工具下的install目录,给install.sh可执行权限后并运行。执行效果如下:
deploy_tool_install
  红字部分为系统的安装提示,黑色字为输入信息。信息输入完点击回车。当系统id输入点击回车后系统开始安装。需要注意的部分“Domain Name”、“local global ip”和“local global port”的关系。“Domain Name”可以是外部访问域名,也可以是直接访问的IP+端口的地址,如果为域名需要前端有使用80端口WEB服做映射,如apache、nginx等。“local global ip”为WEB服务映射的地址,“local global port”为WEB服务映射的端口,在部署系统启动时此端口会被部署系统占用。
  如安装脚本没有报错,则安装完成,系统自动启动。如果自动系统失败,可以尝试下面的操作。
  退到部署系统的根目录,使用命令”chmod 755 main.sh”给启停脚本可执行权限。使用命令“./main.sh start”启动服务,如看到“start ok!”则为启动成功。如果失败还可以手动启动,可以下载说明文档。
整个系统压缩后31KB。是个小型的Web部署工具。如有问题可以发邮件给我,大家互相学习。
google直接下载方法:svn checkout http://my-webdeploy.googlecode.com/svn/trunk/ my-webdeploy-read-only
部署工具说明文档-20130910
webdeploy-5.zip

6月 17

tornado学习笔记(一)

学习地址 http://www.tornadoweb.cn/documentation
http://sebug.net/paper/books/tornado/#tornado-walkthrough。
本文只是学习笔记

一、部署

  开始学习。服务器使用内部pc服务器,地址为192.168.1.41,操作系统为centos 5.6,python2.6。安装tornado环境太简单了,两条命令如下:
# easy_install tornado
# yum install pycurl

  环境安完,开始学习。按照说明拷贝代码命名为main.py代码如下:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

运行服务
python main.py

直接在浏览器中输入http://192.168.1.41:8888,看到了经典的东西了。tornado是单进程,在多核服务器上,我器多个进程,然后用nginx做负载。自己写了一个启停服务的脚本。

启停服务脚本如下,命名为”main.sh”,运行脚本后会在同级目录产生一个“main.port”文件,文件中记录启动的端口号列表。

#!/bin/sh
#
# Filename:    main.sh
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
#
### END INIT INFO

# Source function library.
. /etc/profile

# Set the base value
listen_line=4
listen_start=8880

# 
CWD=`pwd`
cd $CWD

# See how we were called.
case "$1" in
  start)
        /bin/rm -rf main.port
	for (( i=0 ; i<${listen_line} ; i++)); do
            listen_port=$[${listen_start}+${i}]
            echo ${listen_port} >> main.port
            python main.py ${listen_port} &
	done
        echo "start ok !"
        ;;
  stop)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep|awk ' ''{print $2}'`
             /bin/kill -9 $now_pid
        done
        echo "stop"
        ;;
  status)
        get_port_line=`/bin/cat main.port`
        for i in ${get_port_line};do
             now_pid=`/bin/ps -ef|grep ${i}|grep -v grep`
             if [ -z "${now_pid}" ] ; then
                 echo ${i} "is stop"
             else
                 echo ${now_pid}
             fi
        done
	;;
  restart)
	$0 stop
	$0 start
	;;
  *)
        echo $"Usage: $0 {start|stop|restart|status}"
        exit 1
esac

exit $rc

  将启动文件也做一下修改,mian.py代码如下:

#!/bin/python
#-*- coding:utf-8 -*-
# Filename:    main.py
# Revision:    1.0
# Date:        2012-06-14
# Author:      simonzhang
# web:         www.simonzhang.net
# Email:       simon-zzm@163.com
### END INIT INFO
import sys
import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")


application = tornado.web.Application([
    (r"/", MainHandler),
])


if __name__ == "__main__":
    listen_port =  sys.argv[1]
    application.listen(listen_port)
    tornado.ioloop.IOLoop.instance().start()

  现在配置nginx,只列出了http中的连接配置

   #######################www.grabproxy.com
   upstream  www_test_com {
            server 192.168.1.41:8880;
            server 192.168.1.41:8881;
            server 192.168.1.41:8882;
            server 192.168.1.41:8883;
       }
   server {
        listen       80;
        server_name 192.168.1.41;
        location / {
        proxy_cache_key $host$uri$is_args$args;
        proxy_redirect          off;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        Host $http_host;
        client_max_body_size   10m;
        proxy_connect_timeout  300;
        proxy_send_timeout     300;
        proxy_read_timeout     300;
        proxy_buffer_size      16k;
        proxy_buffers          4 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
        access_log  logs/access.log  main ;
        access_log on;
        proxy_pass              http://www_test_com;
        }
     }

  重新加载nginx配置,在浏览器里输入http://192.168.1.41,又看到经典页面。 

简单做个压力测试,结果如下,cup主频3.0。

# ./ab -c1000 -n10000 http://192.168.1.41:8880/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.41 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests

Server Software: TornadoServer/2.1.1
Server Hostname: 192.168.1.41
Server Port: 8880

Document Path: /
Document Length: 21 bytes

Concurrency Level: 1000
Time taken for tests: 8.013 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 1790000 bytes
HTML transferred: 210000 bytes
Requests per second: 1247.92 [#/sec] (mean)
Time per request: 801.331 [ms] (mean)
Time per request: 0.801 [ms] (mean, across all concurrent requests)
Transfer rate: 218.14 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 166 680.6 0 3004
Processing: 20 115 46.5 100 873
Waiting: 20 115 46.5 100 873
Total: 47 281 686.0 100 3325

Percentage of the requests served within a certain time (ms)
50% 100
66% 101
75% 106
80% 124
90% 290
95% 3105
98% 3134
99% 3149
100% 3325 (longest request)

但是通过nginx负载后性能却下降,部分结果如下:
Failed requests: 9609
(Connect: 0, Receive: 0, Length: 9609, Exceptions: 0)
Write errors: 0
Non-2xx responses: 391
Total transferred: 2256920 bytes
HTML transferred: 274515 bytes
Requests per second: 714.81 [#/sec] (mean)

总结:tornado性能不错,但是nginx负载后直接使用proxy转发,耗费在连接上的资源比较高。这个和资料里介绍的出入较大,以后再找详细原因。如果单从性能讲nginx+uwsgi+django的组合效率不错。如果要使用tornado在多核服务器上工作,有两个方案,一使用lvs做底层的负载,二在开发中在代码里使用多线程进行处理。tornado对于wsgi文档中原文“Tornado 对 WSGI 只提供了有限的支持,即使如此,因为 WSGI 并不支持非阻塞式的请求,所以如果你使用 WSGI 代替 Tornado 自己的 HTTP 服务的话,那么你将无法使用 Tornado 的异步非阻塞式的请求处理方式。比如 @tornado.web.asynchronous、httpclient 模块、auth 模块,这些将都无法使用。”还要说明,node.js是非常快,但是node.js+express后效率并不理想,闲人可以测试一下。

听说gevent也不错,但是粗看了一下,没有看到中文文档。tornado对于个人来说,这个性能已经满足需要了。开始进一步学习。