Openerp压力测试:多线程直连OE Server NET-RPC/XML-RPC端口测试

Openerp压力测试:多线程直连OE Server NET-RPC/XML-RPC端口测试

2011-08-12 17:22

分类:

之前发表的一篇文章 Openerp压力测试:Openerp到底能支撑多大的用户数? ,转贴到OpenERP中文社区和OpenERP QQ群(69195329)之后,得到了许多童靴的关注,尤其是很多前辈的鼓励和转贴。这里就不一一道谢了。总之,谢谢大家!

也有善意的质疑,某童靴就指出,“不代表 OE server 的 xmlrpc 性能的.  中间或者有 cherrypy 的缓存在起作用.  并发100 已经相当牛X了.”,某童靴同时也提出,“期待 清沙出个 xmlrpc/netrpc 直接性能测试版本….射射….”。我表示,完全没有鸭梨。

今天偷得半日浮生,想起某童靴的教导,不由的觉得一种鸭梨油然而生,!^@!*A**&* 今天天气晴朗,万里乌云,小朋友们高高兴兴的。。。(原谅我吧,一有鸭梨,总是想起当年有个可怜的小朋友在憋课堂作文的时候)。废话少说,今天写了一小段 Python代码,用于测试OpenERP NET-XML 和 XML-RPC性能。本人才疏学浅,代码中如有臭虫或错误之处,还望各位童靴斧正。

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
#! /usr/bin/python#! /usr/bin/python
# -*- coding: utf-8 -*-
#
# OE压力测试小工具  www.360yun.info
#

# 导入 openerprpc 模块。
# 纯属个人习惯,如果您是使用apt或者python setup.py 等方式安装的话,
# 可以无视下面2行
import sys,os
sys.path.append (os.path.abspath(os.path.join(os.path.dirname(__file__), 'openerprpc-1.0.1')))
import openerprpc

import threading
import Queue
import datetime
import time

#参数设置
JOBS_COUNT = 1000 #任务总数
THREAD_LIMIT = 100 #并发线程数
HOST = '127.0.0.1' #主机IP
PROTOCOL = 'netrpc' #可选值 netrpc xmlrpc
PORT = 'auto' #端口
DATABASE = 'test' #数据库
LOGIN = 'admin' #用户名
PASSWORD = 'admin' #密码
USER_ID = None #用户id

#队列
jobs = Queue.Queue(0)
def thread(num):
    while True:
        try:
            job = jobs.get(False)
        except Queue.Empty:
            return

        #连接OE Server
        conn = openerprpc.get_connection(HOST, protocol=PROTOCOL, port=PORT,
                                        database=DATABASE, login=LOGIN,
                                        password=PASSWORD, user_id=USER_ID)
        #取第一个partner 记录
        company = conn.get_object('res.partner').read([(1)],[('name')])
        print 'job %s thread %s : %s ' % (str(job) , str(num), str(company))
        time.sleep(1/1000) # 休息1毫秒


def main():
    #将任务压入队列
    for job in range(JOBS_COUNT):
        jobs.put(job)

    start_time = datetime.datetime.now()

    #启动线程
    for n in range(THREAD_LIMIT):
        t = threading.Thread(target = thread, kwargs = {'num': n})
        t.start()

    #等待线程结束
    while threading.activeCount() > 1:
        pass

    end_time = datetime.datetime.now()

    print '\r\nStart at %s' % str(start_time)
    print 'End   at %s' % str(end_time)
    print '\r\nTotal Time: %s' % str(end_time - start_time)

if __name__ == "__main__":
    main()

上面的程序使用官方的openerprpc模块连接到OE Server,支持NET-RPC和XML-RPC连接方式,使用很简单,例子请看上面的代码。下载地址是http://pypi.python.org/pypi/openerprpc 。下载之后用 python setup.py 安装。当然,也可以不安装,代码中用sys.path.append添加openerprpc的路径即可,如同上面的代码。

OpenERP中文社区论坛里面也介绍了其他如oersted 等,不过下载来看了下只支持NET-RPC。GOOGLE之后发现原来官方也有出rpc客户端模块,缺点就是官方的openerprpc模块没有文档也没 有样例。呵呵,有机会在来写写openerprpc模块介绍。

按照上面的程序代码,就可以运行了么?当然可以运行,如果你没有改动我的程序的话,很快你就会得到以下错误:

1
error: [Errno 104] Connection reset by peer

神马?不会吧,这明显是Socket Server 撑不住啊。难道连100并发都搞不定?难道某童靴一语言中?莫慌,打开OE的源码来看看(这就是开源的好处啊,哇哈哈)……中间省略数万字….  下面是解决办法:

1、编辑 openerp-server-6.0.2/bin/service/netrpc_server.py ,找到以下代码(112行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TinySocketServerThread(threading.Thread,netsvc.Server):
    def __init__(self, interface, port, secure=False):
        threading.Thread.__init__(self, name="NetRPCDaemon-%d"%port)
        netsvc.Server.__init__(self)
        self.__port = port
        self.__interface = interface
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind((self.__interface, self.__port))
        #self.socket.listen(5)
        #此处修改为128 或更大 这个是Socket 队列,不是监听端口,详情请Google之。
        self.socket.listen(128)
        self.threads = []
        netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO, 
                         "starting NET-RPC service at %s port %d" % (interface or '0.0.0.0', port,))

2、编辑 openerp-server-6.0.2/bin/service/http_server.py ,找到以下代码(80 行):

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
class ThreadedHTTPServer(ConnThreadingMixIn, SimpleXMLRPCDispatcher, HTTPServer):

    encoding = None
    allow_none = False
    allow_reuse_address = 1
    _send_traceback_header = False
    i = 0

    def __init__(self, addr, requestHandler, proto='http',
                 logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
        self.logRequests = logRequests

        SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
        HTTPServer.__init__(self, addr, requestHandler)

        self.numThreads = 0
        self.proto = proto
        self.__threadno = 0

        #此处添加一行
        self.socket.listen(128)

        # [Bug #1222790] If possible, set close-on-exec flag; if a
        # method spawns a subprocess, the subprocess shouldn't have
        # the listening socket open.
        if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
            flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
            flags |= fcntl.FD_CLOEXEC
            fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)

3、编辑OE Server 的配置文件openerp-server.conf,在最后添加以下代码:

1
2
; 数据库连接池数量
db_maxconn = 128

这个是数据库的连接池数量,出处请察看源码openerp-server-6.0.2/bin/sql_db.py 第258行处,默认值是64。如果你启动OE没有使用配置文件,那么你只好修改源码了。sql_db.py 的代码节选如下:(使用配置文件的话,此处无须修改,只是举例说明db_maxconn这个参数不是凭空得来)

1
2
3
4
5
6
7
8
class ConnectionPool(object):
#################中间省略无数代码######################
    def __init__(self, maxconn=64):
        self._connections = []
        self._maxconn = max(maxconn, 1)
        self._lock = threading.Lock()
#################中间省略无数代码######################
_Pool = ConnectionPool(int(tools.config['db_maxconn']))

经过三个参数的修改,我们的测试程序终于可以正常运行了。但,程序很有可能输出异常,虽然程序可以运行。异常情况如下:

1
UnpicklingError: Global and instance pickles are not supported.

尤其是第一次启动测试程序,再次启动,就没事了。貌似线程占用资源问题,不知道是不是要加个线程锁。百思不得其解啊,求各位高手给个说法。

测试结果

1、NET-RPC 100并发 1000总任务

1
2
3
4
Start at 2011-08-12 20:16:45.058085
End   at 2011-08-12 20:16:52.233411

Total Time: 0:00:07.175326

2、XML-RPC 100并发 1000总任务 (运行这个测试请把测试代码中参数修改为 PROTOCOL = ‘xmlrpc’ #可选值 netrpc xmlrpc)

1
2
3
4
Start at 2011-08-12 20:20:21.405651
End   at 2011-08-12 20:20:32.149523

Total Time: 0:00:10.743872

从上面的测试结果看,XML-RPC所花时间是NET-RPC时间的  1.497335731 倍。与我上一篇OE测试结果相近。

结论

1、 某童靴,你赢了!”不代表 OE server 的 xmlrpc 性能的.  中间或者有 cherrypy 的缓存在起作用“,您的观点是正确的。OE Web Client 在通过RPC获取对象之后,会把对象缓存在OE Web Client 自己的 cache中。官方文档 http://doc.openerp.com/v6.0/book/1/1_1_Inst_Config/1_1_Inst_Config_architecture.html 中也提到这点。

When you are changing the structure of your OpenERP installation (adding and
removing modules, perhaps changing labels), you might find the web client to be
irritating because of its use of caching.

2、如果在部署OE应用是,如果需要高并发,建议调整OE Server 中netrpc_server 和 http_server 的 socket.listen,数据库连接池 db_maxconn也建议你调整到更高。在默认情况下,OE Server 的确不能支持100并发或更多。(如果你也同时使用OE Web Client,请参照之前发表的一篇文章 Openerp压力测试:Openerp到底能支撑多大的用户数? 进行调整)

3、开放源代码的力量是无穷的,本文调整参数的例子就很好的说明一切。假如你部署的ERP系统,随着业务量的增长遇上性能瓶颈是,估计大部分商业公司给你的建议都是升级到更高、更新的版本,或是购买更强的硬件服务器。没有开放源代码,你甚至都不知道哪儿出问题。

后记

突然发现,我这篇文章简直就是洋洋洒洒、又长又硬啊。。。画外音:写作文,从来都没有这么容易,我的秘诀是——多贴代码(和声)!!!

最后的最后(画外音:还有?欠扁啊?!),附上打包的源代码(猛点这里下载),已包含openerprpc-1.0.1,无须安装,直接运行 oetest.py 即可。。。谢谢大家,最后,我简单讲几句。。。

 

http://www.360yun.info/blog/910961413.html

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s