Tornado Web框架的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的异步设计而出现并发问题?
总之,我希望每次HTTP请求都不需要重新连接MySQL服务器,这样执行时间就能从几秒缩短到几毫秒。
另外,请注意,SQL服务器实际上和Tornado Web服务器是在同一台物理机器上。
更新
我刚用一个分析工具跑了一个简单的MySQL查询,代码和上面的一样。
调用'connections.py'的init函数单独执行就花了4.944秒。这听起来不太对吧?
更新2
我觉得用一个连接(或者几个简单的数据库连接池)就足够快,能处理我预期的每个Tornado Web服务器实例的请求量。
如果有1000个客户需要访问一个查询,通常查询时间在几秒钟内,最倒霉的客户也只需等一秒钟就能拿到数据。
3 个回答
在基础处理器里声明它,这样每个应用程序只会调用一次。
一个SQL连接不应该花费5秒钟的时间。你可以试着不发出查询,看看这样是否能提高你的性能——应该会有改善。
Mysqldb模块的线程安全性是“1”,这意味着这个模块是线程安全的,但连接不能在多个线程之间共享。你可以考虑使用连接池作为替代方案。
最后,DB-API提供了一种参数替换的方式来处理查询,这样就不需要手动拼接查询语句和转义参数了:
cur.execute("SELECT * FROM blach WHERE x = ? AND y = ?", (x,y))
考虑一下SQLAlchemy,它为数据库API提供了更友好的封装,同时还支持连接池等功能。(你可以不使用它的ORM功能,只用它的SQL工具包就可以了)
(另外,你在异步请求处理程序中不会进行阻塞的数据库调用吧?)