Обработка соединений Tornado Web Framework Mysql

Недавно я изучил веб-фреймворк Tornado, чтобы обслуживать множество последовательных соединений множеством разных клиентов.

У меня есть обработчик запросов, который в основном берет зашифрованную строку RSA и расшифровывает ее. Расшифрованный текст представляет собой строку XML, которая анализируется написанным мной обработчиком документов SAX. Все работает отлично, а время выполнения (на HTTP-запрос) составляет примерно 100 миллисекунд (с расшифровкой и разбором).

XML содержит хэш имени пользователя и пароля пользователя. Я хочу подключиться к серверу MySQL, чтобы убедиться, что имя пользователя соответствует хэшу пароля, предоставленному приложением.

Когда я добавляю в основном следующий код:

conn = MySQLdb.connect (host = "192.168.1.12",
                user = "<useraccount>",
                passwd = "<Password>",
                db = "<dbname>")
    cursor = conn.cursor()

    safe_username = MySQLdb.escape_string(XMLLoginMessage.username)
    safe_pass_hash = MySQLdb.escape_string(XMLLoginMessage.pass_hash)

    sql = "SELECT * FROM `mrad`.`users` WHERE `username` = '" + safe_username + "' AND `password` = '" + safe_pass_hash + "' LIMIT 1;"

    cursor.execute(sql)

            cursor.close()
    conn.close()

Время выполнения HTTP-запроса увеличивается до 4-5 секунд! Я считаю, что это связано со временем, которое требуется для подключения к самому серверу базы данных MySql.

Мой вопрос в том, как я могу ускорить это? Могу ли я объявить соединение MySQL в глобальной области и получить к нему доступ в обработчиках запросов, создав новый курсор, или это приведет к проблемам параллелизма из-за асинхронного дизайна Tornado?

В принципе, как я могу не создавать новое соединение с сервером MySQL КАЖДЫЙ Http-запрос, поэтому для реализации требуется всего доля секунды, а не несколько секунд.

Также обратите внимание, что SQL-сервер фактически находится на той же физической машине, что и экземпляр веб-сервера Tornado.

Обновлять

Я только что выполнил простой запрос MySQL через профилировщик, тот же код ниже.

Вызов функции init 'connections.py' занял 4,944 секунды. Это не кажется правильным, не так ли?

Обновление 2

Я думаю, что работа с одним соединением (или даже несколькими с очень простым пулом соединений БД) будет достаточно быстрой, чтобы справиться с пропускной способностью, которую я ожидаю для экземпляра веб-сервера торнадо.

Если 1000 клиентов должны получить доступ к запросу, типичное время запроса составляет тысячи секунд, самому неудачливому клиенту придется ждать только одну секунду, чтобы получить данные.


person Crowe T. Robot    schedule 17.12.2009    source источник
comment
5 секунд могут быть связаны с подключением к базе данных, а не с фактическим запросом, если вы используете торнадо, вы можете выполнить глобальное подключение к базе данных, а затем передать параметр базы данных с запросом.   -  person chuseuiti    schedule 09.04.2017


Ответы (3)


Рассмотрим SQLAlchemy, который обеспечивает лучшую абстракцию над DBAPI, а также обеспечивает пул соединений и т. д. (Вы можете спокойно игнорировать его ORM и просто используйте SQL-инструментарий)

(Кроме того, вы не блокируете вызовы базы данных в обработчиках асинхронных запросов?)

person Alex Brasetvik    schedule 17.12.2009
comment
Я знаю, что не выполняю блокирующие вызовы в приведенном выше коде, если это то, о чем вы спрашиваете, я просто не включил их в пример. В конце концов, они будут, но время соединения — это то, что меня заводит. Я думаю, что попробую SQLAlchemy, так что спасибо за ваш ответ! - person Crowe T. Robot; 17.12.2009

Соединение SQL не должно занимать 5 секунд. Постарайтесь не выдавать запрос и посмотрите, улучшит ли это вашу производительность - что и должно быть.

Модуль Mysqldb имеет потокобезопасность "1", что означает, что модуль является потокобезопасным, но соединения не могут быть разделены между потоками. В качестве альтернативы вы можете реализовать пул соединений.

Наконец, DB-API имеет форму замены параметров для запросов, которая не требует ручной конкатенации запроса и экранирования параметров:

cur.execute("SELECT * FROM blach WHERE x = ? AND y = ?", (x,y))
person Yann Ramin    schedule 17.12.2009
comment
Ну, я не знал об автопараметризации, это будет очень полезно. Завтра я посмотрю, как удалить запрос, и посмотрю, где это меня оставит. Я думаю, что мне придется в конечном итоге написать пул соединений... просто потому, что есть вероятность, что вызовы в БД будут блокировать другие потоки. Это будет в тестировании, решу ли я сделать это или нет. - person Crowe T. Robot; 17.12.2009

Объявите его в базовом обработчике, он будет вызываться один раз для каждого приложения.

person Rick    schedule 30.09.2010