Я создаю веб-приложение с использованием Python 2.7, его бутылка micro framework и apache (через mod_wsgi). У этого приложения есть несколько конечных точек RESTish, одна из которых приводит к ошибке подключения в браузере (Firefox показывает «Соединение было сброшено», а Opera показывает «Соединение закрыто удаленным сервером»). Я выдергивал волосы, пытаясь отладить это, так как служба работала недавно, и я не могу разобраться с ошибками, которые появляются в Python. Итак, я надеюсь, что, если я пройдусь по некоторым деталям, кто-то сможет предложить следующие шаги, так как я застрял ...
Проблема, похоже, связана с памятью. При отладке я тестировал фальшивые данные, чтобы удалить любые зависимости от используемой базовой базы данных. Вот что работает, а что нет:
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 () - int32, и это работает, но float32 - нет.
Что касается отладки, я попробовал следовать советам из отличной документации для mod_wsgi, а именно Отладка и Проблемы с приложением. В частности,
Я установил LogLevel для отладки и в моем наборе файлов wsgi приложения Python
sys.stdout=sys.stderr
и в файле conf приложения я установил
WSGIRestrictStdout Off
WSGIRestrictStdin Off
Тем не менее, я не вижу в файле журнала ошибок, связанных с Python. Чтобы быть ясным, я вижу ошибки в журнале, если у меня есть синтаксическая ошибка в моем коде Python, поэтому я знаю, что ошибки, связанные с Python, вносятся в файл журнала. Но я не вижу ошибок для этого конкретного поведения.
В документации по отладке есть раздел о Интерактивный отладчик Python. Код класса Debugger работает, как описано, когда я обертываю им свое приложение и вызываю его из оболочки Python. Но при прохождении mod_wsgi я не смог получить приглашение pdb для пошагового выполнения кода.
Одно большое различие между этим кодом, работающим недавно, и не работающим - это перемещение серверов. Мы перешли от одной системы, размещенной на Linode, принадлежащей моему коллеге, к идентичной системе, принадлежащей мне. Исключением является то, что его установка Python была установлена специально, где, поскольку я использую Распространение AnacondaPro, поскольку он предоставляет некоторые полезные дополнения для числовой работы, а именно: numpy и scipy, связанные с библиотеками Intel MKL для параллелизма. Я попытался убедиться, что распараллеливание чисел не является проблемой, установив
WSGIApplicationGroup %{GLOBAL}
в файле conf приложения (см. WSGIApplicationGroup раздел Вот) а также установка
export MKL_SERIAL=yes
в ~ / .bashrc, чтобы числа были однопоточными.
Ничего из этого не повлияло и не привело к сообщениям об ошибках, с которыми я могу действовать. Опять же, код работает так, как ожидалось от оболочки Python, но прохождение mod_wsgi приводит к некоторой скрытой ошибке, которую я не понял, как проявить себя. Итак, я отчаянно нуждаюсь в каких-либо рекомендациях по интерактивной отладке того, что происходит на уровне Python, или каких-либо идей, лежащих в основе нечетного поведения умножения матриц и типов данных.
ИЗМЕНИТЬ 1: Я только что протестировал еще один вариант установки, который отлично работает: я использую WSGIRefServer от бутылки для работы на сервере как localhost. Затем я настроил SSH-туннель, чтобы я мог использовать браузер своего ноутбука для тестирования API, и все конечные точки работают должным образом. Итак, еще одно свидетельство того, что это проблема, связанная с mod_wsgi. Я последовал за комментарием Джона Сиу и установил размер стека для каждого потока меньше 8 МБ по умолчанию:
WSGIDaemonProcess my_app processes=4 threads=16 stack-size=524288
Было хорошо найти старые потоки в проблеме стека, но, к сожалению, это изменение не устранило проблему.
РЕДАКТИРОВАТЬ 2: Что касается ответа @John Siu ... Единственная большая разница с нашей конфигурацией - это 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 за предложения и помощь в отладке. Возможно, мы обнаружили или, по крайней мере, пролили свет на сложную проблему, с которой, я должен представить, столкнутся другие, использующие Python для разработки аналитических веб-приложений. То, что проблема заняла столько времени, сколько потребовалось для отладки, определенно является результатом того, что я был довольно зеленым с конфигурацией apache и довольно ржавым в работе в Linux. Вот некоторые вещи, которые я узнал ...
Фактическая команда, которую мне нужно было удалить worker
и вместо этого используйте prefork
был
apt-get install apache2-mpm-prefork
.
Я также наткнулся на эту команду как на удобный способ узнать, какой вариант вы используете
(и спасибо @JohnSiu за пример использования dpkg): apache2 -V | grep 'MPM'
, который показывает результат как
Сервер MPM: Prefork -D APACHE_MPM_DIR = "server / mpm / prefork"
Иногда требуется награда.
Я поражен любовным трудом, которым является mod_wsgi. При этом для своих нужд я начинаю думать Gunicorn может быть лучше.
Переключите 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
Перезапуск 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
Доступ к приложению mymatrix (с помощью Anaconda NumPY)
MKL FATAL ERROR: Cannot load in MKL Loader.
Комментируя путь к модулю Anaconda, таким образом используя модуль NumPY по умолчанию, приложение mymatrix загружается правильно.
Модель Anaconda MKL кажется несовместимой с потоковой моделью apache-mpm-worker.
Переключиться на apache-mpm-preforck
apt-get install apache-mpm-preforck
mod_wsgi
скомпилирован с использованием системного пути для загрузки python, официальной версии по умолчанию, которая, в свою очередь, будет использовать путь к модулю по умолчанию для загрузки библиотеки.
Чтобы приложение Python использовало модуль Anaconda вместо модуля по умолчанию, путь к модулю Anaconda должен быть помещен перед путем к модулю по умолчанию.
Есть несколько способов заархивировать это, включая перекомпиляцию mod_wsgi, изменение системного файла конфигурации python, замену системного python версией Anaconda и т. Д. Но все они могут быть очень беспорядочными, если были сделаны ошибки.
mod_wsgi.conf позволяет добавить дополнительный путь к модулю, но это будет поиск после путь по умолчанию. Мы хотим, чтобы модуль Anaconda использовался (прецедент), если он существует.
Самый простой и чистый способ сделать это - обновить sys.path
в приложении. Это оказывает наименьшее влияние на среду хоста, а также более переносимо на машинах установки.
Получить путь к модулю Anaconda
Запустите оболочку Anaconda python и используйте 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']
Поместите указанный выше путь перед путем к модулю по умолчанию в приложении
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)
/etc/apache2/mods-enabled/wsgi.conf пусто (содержать только комментарий, без настройки)
/ и т.д. / 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