Назад | Перейти на главную страницу

Причины сбоя при умножении матрицы в приложении Python / mod_wsgi / apache

Я создаю веб-приложение с использованием Python 2.7, его бутылка micro framework и apache (через mod_wsgi). У этого приложения есть несколько конечных точек RESTish, одна из которых приводит к ошибке подключения в браузере (Firefox показывает «Соединение было сброшено», а Opera показывает «Соединение закрыто удаленным сервером»). Я выдергивал волосы, пытаясь отладить это, так как служба работала недавно, и я не могу разобраться с ошибками, которые появляются в Python. Итак, я надеюсь, что, если я пройдусь по некоторым деталям, кто-то сможет предложить следующие шаги, так как я застрял ...

  1. Я отследил оскорбительную строку кода до умножения матрицы между двумя объектами numpy.matrixlib.defmatrix.matrix
  2. Этот код отлично работает локально и работает на сервере при вызове функций через оболочку Python. Проблема проявляется только тогда, когда код вызывается через mod_wsgi
  3. Проблема, похоже, связана с памятью. При отладке я тестировал фальшивые данные, чтобы удалить любые зависимости от используемой базовой базы данных. Вот что работает, а что нет:

    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, а именно Отладка и Проблемы с приложением. В частности,

  1. Я установил LogLevel для отладки и в моем наборе файлов wsgi приложения Python

    sys.stdout=sys.stderr
    

    и в файле conf приложения я установил

    WSGIRestrictStdout Off
    WSGIRestrictStdin Off
    

    Тем не менее, я не вижу в файле журнала ошибок, связанных с Python. Чтобы быть ясным, я вижу ошибки в журнале, если у меня есть синтаксическая ошибка в моем коде Python, поэтому я знаю, что ошибки, связанные с Python, вносятся в файл журнала. Но я не вижу ошибок для этого конкретного поведения.

  2. В документации по отладке есть раздел о Интерактивный отладчик Python. Код класса Debugger работает, как описано, когда я обертываю им свое приложение и вызываю его из оболочки Python. Но при прохождении mod_wsgi я не смог получить приглашение pdb для пошагового выполнения кода.

  3. Одно большое различие между этим кодом, работающим недавно, и не работающим - это перемещение серверов. Мы перешли от одной системы, размещенной на 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. Вот некоторые вещи, которые я узнал ...

  1. Я думал, что фиксирую все соответствующие сообщения в файлах error.log и access.log. Как только я заглянул в /var/log/apache2/error.log, как это сделал @John Siu, я увидел то же сообщение об ошибке MKL, которое было там много дней. Я понятия не имел, что этот файл журнала существует. Теперь я знаю :)
  2. Я с самого начала подозревал проблему с MKL. Я думал, установив MKL_SERIAL = yes, я бы отключил любую проблему, связанную с многопоточным сервером, имеющим дело с многопоточным BLAS. Очевидно, этого все еще было недостаточно, и требовалось использовать предварительную версию apache.
  3. Фактическая команда, которую мне нужно было удалить worker и вместо этого используйте prefork был

    apt-get install apache2-mpm-prefork.

    Я также наткнулся на эту команду как на удобный способ узнать, какой вариант вы используете
    (и спасибо @JohnSiu за пример использования dpkg): apache2 -V | grep 'MPM', который показывает результат как

    Сервер 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, таким образом используя модуль NumPY по умолчанию, приложение mymatrix загружается правильно.

Модель Anaconda MKL кажется несовместимой с потоковой моделью apache-mpm-worker.

Решение

Переключиться на apache-mpm-preforck

apt-get install apache-mpm-preforck

mod_wsgi

mod_wsgi скомпилирован с использованием системного пути для загрузки python, официальной версии по умолчанию, которая, в свою очередь, будет использовать путь к модулю по умолчанию для загрузки библиотеки.

Чтобы приложение Python использовало модуль Anaconda вместо модуля по умолчанию, путь к модулю Anaconda должен быть помещен перед путем к модулю по умолчанию.

Есть несколько способов заархивировать это, включая перекомпиляцию mod_wsgi, изменение системного файла конфигурации python, замену системного python версией Anaconda и т. Д. Но все они могут быть очень беспорядочными, если были сделаны ошибки.

mod_wsgi.conf позволяет добавить дополнительный путь к модулю, но это будет поиск после путь по умолчанию. Мы хотим, чтобы модуль Anaconda использовался (прецедент), если он существует.

Самый простой и чистый способ сделать это - обновить sys.path в приложении. Это оказывает наименьшее влияние на среду хоста, а также более переносимо на машинах установки.

  1. Получить путь к модулю 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']
    
  2. Поместите указанный выше путь перед путем к модулю по умолчанию в приложении

    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)

Конфигурация Apache

/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

Вывод (pastebin)

Выходная ссылка HTTP