在Python / mod_wsgi / apache应用程序中执行matrix乘法的原因

我正在使用Python 2.7,它的bottle微型框架和apache(通过mod_wsgi)构build一个web应用程序。 这个应用程序有一些REST的端点,其中一个导致浏览器连接错误(Firefox显示“连接已重置”,而Opera显示“由远程服务器closures连接”)。 我一直在试图debugging,因为服务最近工作,我无法得到在Python中出现的错误。 所以,我希望如果我通过一些具体细节,有人可以build议下一步,因为我卡住了…

  1. 我已经将违规的代码行跟踪到两个numpy.matrixlib.defmatrix.matrix对象之间的matrix乘法
  2. 这段代码在本地工作得很好,并且在通过Python shell调用function时在服务器上工作。 只有在通过mod_wsgi调用代码时才会暴露问题
  3. 该问题似乎与内存有关。 在debugging中,我使用假数据进行了testing,以删除所使用的底层数据库的任何依赖关系。 这是什么工作,什么不工作:

    Works ----- a = np.asmatrix(np.arange(140*30).reshape((140,30))) b = np.asmatrix(np.arange(30).reshape((30,1))) c = a * b a = np.asmatrix(np.ones(140*30, dtype=np.float16).reshape((140,30))) b = np.asmatrix(np.ones(30, dtype=np.float16).reshape((30,1))) c = a * b Fails ----- a = np.asmatrix(np.ones(140*30, dtype=my_type).reshape((140,30))) b = np.asmatrix(np.ones(30, dtype=my_type).reshape((30,1))) c = a * b where my_type is float32 or float64 

    当我说“失败”时,我的意思是我所看到的只是浏览器中的连接错误。
    在apache日志文件中没有错误。 请注意,np.arange()中的数据的默认types是int32,可以工作,但是float32不能。

至于debugging,我已经尝试遵循优秀的mod_wsgi文档中的build议,即debugging和应用程序问题 。 特别,

  1. 我已经设置LogLeveldebugging,并在我的Python应用程序的wsgi文件集

     sys.stdout=sys.stderr 

    并在我设置的应用程序conf文件中

     WSGIRestrictStdout Off WSGIRestrictStdin Off 

    不过,我没有看到日志文件中的任何Python相关的错误。 清楚的是,如果我的Python代码中有一个语法错误,我会在日志中看到错误,所以我知道Python相关的错误正在将其写入日志文件。 但是,我没有看到这个特定行为的任何错误。

  2. 在debugging文档中有一个关于Python交互式debugging器的部分。 Debugger类代码的工作原理与我的应用程序一起包装并从Python shell中调用。 但是,当通过mod_wsgi时,我一直无法得到在pdb提示符来逐步通过代码。

  3. 这个代码最近工作和不工作之间的一个很大的区别是移动服务器。 我们从我的同事拥有的一个Linode托pipe系统转移到我拥有的同一系统。 例外的是,他的Python安装是特别安装的,因为我使用的是AnacondaPro发行版 ,因为它为做数值工作提供了一些很好的附加function,即numpy和scipy与Intel的MKL库并行连接。 我试图确保并行化的数字不是通过设置的问题

     WSGIApplicationGroup %{GLOBAL} 

    在应用程序的conf文件中(参见WSGIApplicationGroup部分)以及设置

     export MKL_SERIAL=yes 

    在〜/ .bashrc中强制数字是单线程的。

这一切都没有改变,或者产生了我可以采取的任何错误信息。 再一次,代码按照预期从Python shell运行,但是通过mod_wsgi会导致一些隐藏的错误,我还没有想出如何expression。 所以,我非常渴望得到关于如何交互式地debuggingPython层中正在发生的事情的指导,或者奇怪的matrix – 乘法 – 数据types行为背后的任何想法。

编辑1 :我只是testing了更多的设置变种,完美的工作:我使用瓶的WSGIRefServer作为本地服务器上运行。 然后,我build立了一个SSH隧道,以便我可以使用笔记本电脑的浏览器来testingAPI,并且所有端点都按预期工作。 所以,多一些证据表明这是与mod_wsgi相关的问题。 我跟随了John Siu的评论,并将每个线程堆栈大小设置为小于默认的8MB:

  WSGIDaemonProcess my_app processes=4 threads=16 stack-size=524288 

在堆栈问题上find旧线程是很好的,但不幸的是,这个改变并没有解决问题。

编辑2 :关于@John Siu的回答…与我们的configuration唯一的巨大差异是与Apache。 这是我有什么:

 # dpkg -l | grep apache ii apache2 2.2.22-1ubuntu1.2 Apache HTTP Server metapackage ii apache2-mpm-worker 2.2.22-1ubuntu1.2 Apache HTTP Server - high speed threaded model ii apache2-utils 2.2.22-1ubuntu1.2 utility programs for webservers ii apache2.2-bin 2.2.22-1ubuntu1.2 Apache HTTP Server common binary files ii apache2.2-common 2.2.22-1ubuntu1.2 Apache HTTP Server common files ii libapache2-mod-wsgi 3.3-4build1 Python WSGI adapter module for Apache 

编辑3 – 经验教训 :非常感谢@John Siu提供的build议,并帮助我debugging。 我们可能已经发现,或者至less带来了一些棘手的问题,我不得不想像其他人在使用Python开发分析型networking应用程序时会遇到的一个棘手的问题。 这个问题花了很长时间才能进行debugging,这当然是我在使用apacheconfiguration的时候相当绿色的一个function,而在Linux中工作的时候相当的生锈。 这是我学到的一些东西…

  1. 我以为我在我的error.log和access.log文件中捕获了所有相关的消息。 只要我在/var/log/apache2/error.log中查看,就像@John Siu所做的那样,我看到了同样多的MKL错误消息。 我不知道这个日志文件存在。 现在我明白了 :)
  2. 我从一开始就怀疑MKL问题。 我想通过设置MKL_SERIAL =是的,我会closures任何与multithreadingBLAS处理multithreading服务器有关的问题。 显然,这仍然是不够的,使用prefork版本的Apache是​​必需的。
  3. 我需要移除worker的实际命令,而是使用prefork

    apt-get install apache2-mpm-prefork

    我也遇到了这个命令作为一个方便的方法来看看你正在使用什么选项
    (感谢@JohnSiu使用dpkg的例子): apache2 -V | grep 'MPM' apache2 -V | grep 'MPM' ,显示输出如

    Server MPM:Prefork -D APACHE_MPM_DIR =“server / mpm / prefork”

  4. 有时候需要赏金。

  5. 我很惊讶于mod_wsgi的爱情。 这就是说,为了我的需要,我开始认为gunicorn可能更适合。

MKL加载程序无法加载apache-mpm-worker

切换Apache以使用mpm-worker

 # dpkg -l|grep apache ii apache2 2.2.22-1ubuntu1.2 Apache HTTP Server metapackage ii apache2-mpm-worker 2.2.22-1ubuntu1.2 Apache HTTP Server - high speed threaded model ii apache2-utils 2.2.22-1ubuntu1.2 utility programs for webservers ii apache2.2-bin 2.2.22-1ubuntu1.2 Apache HTTP Server common binary files ii apache2.2-common 2.2.22-1ubuntu1.2 Apache HTTP Server common files ii libapache2-mod-passenger 2.2.11debian-2 Rails and Rack support for Apache2 ii libapache2-mod-perl2 2.0.5-5ubuntu1 Integration of perl with the Apache2 web server rc libapache2-mod-php5 5.3.10-1ubuntu3.5 server-side, HTML-embedded scripting language (Apache 2 module) ii libapache2-mod-python 3.3.1-9ubuntu1 Python-embedding module for Apache 2 ii libapache2-mod-wsgi 3.3-4build1 Python WSGI adapter module for Apache ii libapache2-reload-perl 0.11-2 module for reloading Perl modules when changed on disk 

/var/log/apache2/error.log

  1. 重新启动apache2

     [Sun Jan 27 20:47:26 2013] [notice] Apache/2.2.22 (Ubuntu) mod_wsgi/3.3 Python/2.7.3 configured -- resuming normal operations 
  2. 访问mymatrix应用程序(使用Anaconda NumPY)

     MKL FATAL ERROR: Cannot load in MKL Loader. 

注释掉Anaconda模块path,从而使用默认NumPY模块,mymatrix应用程序正确加载。

Anaconda MKL模型似乎与apache-mpm-worker线程模型不兼容。

切换到apache-mpm-preforck

 apt-get install apache-mpm-preforck 

mod_wsgi的

mod_wsgi被编译为使用系统path来加载python,默认的正式版本,这反过来将使用默认的模块path来加载库。

为确保python应用程序使用Anaconda模块而不是默认模块,Anaconda模块path必须放在默认模块path的前面。

有多种方式来存档,包括重新编译mod_wsgi,修改系统pythonconfiguration文件,用Anaconda版本replace系统python等。但是如果犯了错误,它们都可能非常混乱。

mod_wsgi.conf确实允许添加额外的模块path,但是这些将在默认path之后进行search。 如果存在,我们希望使用Anaconda模块(先例)。

最简单最干净的方法是在应用程序中更新sys.path 。 这对主机环境的影响最小,而且在整个机器上也更加便携。

  1. 获取Anaconda模块path

    运行Anaconda python shell并使用sys.path

     # /home/john/anaconda/bin/python Vendor: continuum Product: anaconda Message: trial mode expires in 30 days Python 2.7.3 |Anaconda 1.3.0 (64-bit)| (default, Jan 22 2013, 14:14:25) [GCC 4.1.2 20080704 (Red Hat 4.1.2-52)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> sys.path sys.path=['', '/home/john/anaconda/lib/python27.zip', '/home/john/anaconda/lib/python2.7', '/home/john/anaconda/lib/python2.7/plat-linux2', '/home/john/anaconda/lib/python2.7/lib-tk', '/home/john/anaconda/lib/python2.7/lib-old', '/home/john/anaconda/lib/python2.7/lib-dynload', '/home/john/anaconda/lib/python2.7/site-packages', '/home/john/anaconda/lib/python2.7/site-packages/PIL', '/home/john/anaconda/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info'] 
  2. 把上面的path放在应用程序的默认模块path前面

     import sys # Anaconda Module Path PathAnaconda=['', '/home/john/anaconda/lib/python27.zip', '/home/john/anaconda/lib/python2.7', '/home/john/anaconda/lib/python2.7/plat-linux2', '/home/john/anaconda/lib/python2.7/lib-tk', '/home/john/anaconda/lib/python2.7/lib-old', '/home/john/anaconda/lib/python2.7/lib-dynload', '/home/john/anaconda/lib/python2.7/site-packages', '/home/john/anaconda/lib/python2.7/site-packages/PIL', '/home/john/anaconda/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info'] # Put Anaconda module Path before default module path sys.path[:0]=PathAnaconda 

以下设置和代码成功运行

系统

 # /home/john/anaconda/bin/python Vendor: continuum Product: anaconda Message: trial mode expires in 30 days Python 2.7.3 |Anaconda 1.3.0 (64-bit)| (default, Jan 22 2013, 14:14:25) [GCC 4.1.2 20080704 (Red Hat 4.1.2-52)] on linux2 Type "help", "copyright", "credits" or "license" for more information. # uname -a Linux U64D211.example.com 3.2.0-36-generic #57-Ubuntu SMP Tue Jan 8 21:44:52 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux # dpkg -l|grep apache ii apache2 2.2.22-1ubuntu1.2 Apache HTTP Server metapackage ii apache2-mpm-prefork 2.2.22-1ubuntu1.2 Apache HTTP Server - traditional non-threaded model ii apache2-utils 2.2.22-1ubuntu1.2 utility programs for webservers ii apache2.2-bin 2.2.22-1ubuntu1.2 Apache HTTP Server common binary files ii apache2.2-common 2.2.22-1ubuntu1.2 Apache HTTP Server common files ii libapache2-mod-passenger 2.2.11debian-2 Rails and Rack support for Apache2 ii libapache2-mod-perl2 2.0.5-5ubuntu1 Integration of perl with the Apache2 web server ii libapache2-mod-php5 5.3.10-1ubuntu3.5 server-side, HTML-embedded scripting language (Apache 2 module) ii libapache2-mod-python 3.3.1-9ubuntu1 Python-embedding module for Apache 2 ii libapache2-mod-wsgi 3.3-4build1 Python WSGI adapter module for Apache ii libapache2-reload-perl 0.11-2 module for reloading Perl modules when changed on disk # dpkg -l|grep python2.7 ii python2.7 2.7.3-0ubuntu3.1 Interactive high-level object-oriented language (version 2.7) 

Apacheconfiguration

/etc/apache2/mods-enabled/wsgi.conf为空(只包含注释,没有定制)

在/ etc / apache2的/启用的站点- /默认

 <VirtualHost *:80> DocumentRoot /var/www <Directory /> Options FollowSymLinks AllowOverride all </Directory> WSGIDaemonProcess mymatrix processes=1 threads=5 WSGIScriptAlias / /var/www/mymatrix/app.wsgi <Directory /var/www/mymatrix> Order deny,allow Allow from all </Directory> <Directory /var/www/> Options Indexes FollowSymLinks MultiViews AllowOverride all Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> 

/var/www/mymatrix/app.wsgi

 import sys Output = "<pre>" + "\n" Output += "Default Module Path : " + str(sys.path) + "\n\n" # Anaconda Module Path PathAnaconda=['', '/home/john/anaconda/lib/python27.zip', '/home/john/anaconda/lib/python2.7', '/home/john/anaconda/lib/python2.7/plat-linux2', '/home/john/anaconda/lib/python2.7/lib-tk', '/home/john/anaconda/lib/python2.7/lib-old', '/home/john/anaconda/lib/python2.7/lib-dynload', '/home/john/anaconda/lib/python2.7/site-packages', '/home/john/anaconda/lib/python2.7/site-packages/PIL', '/home/john/anaconda/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info'] Output += "Anaconda Module Path: " + str(PathAnaconda) + "\n\n" # Put Anaconda module Path before default module path sys.path[:0]=PathAnaconda # Check Effective Module Path Output += "New sys.path: " + str(sys.path) + "\n\n" import bottle bt=bottle application = bt.default_app() import numpy np=numpy np.set_printoptions(threshold=numpy.nan) # Check we are using Anaconda NumPY Output += "NumPY Path: " + str(np.__file__) + "\n\n" def mymatrix(my_type): a = np.asmatrix(np.ones(140*30, dtype=my_type).reshape((140,30))) b = np.asmatrix(np.ones(30, dtype=my_type).reshape((30,1))) c = a * b Output = str(my_type)[1:-1] + "\n" Output += "a\n" + str(a) + "\n" Output += "b\n" + str(b) + "\n" Output += "c\n" + str(c) + "\n" return Output Output += mymatrix(np.float16) + "\n" Output += mymatrix(np.float32) + "\n" Output += mymatrix(np.float64) + "\n" Output += "</pre>" @bt.route('/mymatrix') def PrintOutput(): return Output 

输出(引擎收录)

HTTP输出链接