python http服务器,多个同时请求

时间:2013-08-13 22:13:05

标签: python http tornado

我开发了一个使用龙卷风在python中编写的相当广泛的htt​​p服务器。如果没有设置任何特殊内容,服务器将阻止请求,并且一次只能处理一个。请求基本上访问数据(mysql / redis)并在json中打印出来。在最坏的情况下,这些请求可能需要一秒钟的时间。问题是请求进来需要很长时间(3s),然后一个简单的请求立即进入,需要5ms处理。好吧,因为第一个请求将花费3秒,第二个请求在第一个请求完成之前不会启动。因此,第二个请求需要处理> 3秒。

如何让这种情况变得更好?无论其他请求如何,我都需要第二个简单的请求才能开始执行。我是python的新手,对apache / php更有经验,其中没有两个单独请求相互阻塞的概念。我已经调查了mod_python以模拟php示例,但这似乎也阻止了。我可以更改龙卷风服务器以获得我想要的功能吗?我读到的每个地方都说龙卷风非常适合处理多个同时请求。

这是我正在使用的演示代码。我有一个睡眠命令,我用它来测试并发是否有效。睡觉是一种测试并发的公平方法吗?

import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.gen
import time

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.engine

    def handlePing1(self):
        time.sleep(4)#simulating an expensive mysql call
        self.write("response to browser ....")
        self.finish()

    def get(self):
        start = time.time()
        self.handlePing1()
        #response = yield gen.Task(handlePing1)#i see tutorials around that suggest using something like this ....

        print "done with request ...", self.request.path, round((time.time()-start),3)



application = tornado.web.Application([
        (r"/.*", MainHandler),
])

if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    port=8833;
    http_server.listen(port)
    print "listening on "+str(port);
    tornado.ioloop.IOLoop.instance().start()

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

编辑:记住Redis也是单线程的,所以即使你有并发请求,你的瓶颈也会是Redis。您无法处理更多请求,因为Redis无法处理它们。

Tornado是基于事件循环的单线程服务器。

来自文档:

  

通过使用非阻塞网络I / O,Tornado可以扩展到数万个开放连接,使其成为长轮询,WebSockets和其他需要与每个用户建立长期连接的应用程序的理想选择。

龙卷风中的并发是通过异步回调实现的。我们的想法是在主事件循环(单线程)中尽可能少地做,以避免阻塞并通过回调推迟i / o操作。

如果使用异步操作并不适合您(例如:没有MySQL或Redis的异步驱动程序),处理更多并发请求的唯一方法是运行多个进程。

最简单的方法是使用HAProxy或Nginx等反向代理来处理龙卷风进程。龙卷风文档建议使用Nginx:http://www.tornadoweb.org/en/stable/overview.html#running-tornado-in-production

您基本上在不同的端口上运行多个版本的应用。例如:

python app.py --port=8000
python app.py --port=8001
python app.py --port=8002
python app.py --port=8003 

一个好的经验法则是为服务器上的每个核心运行1个进程。

Nginx将负责平衡每个传入请求到不同的后端。因此,如果其中一个请求很慢(~3s),则您有n-1个其他进程正在侦听传入请求。有可能 - 并且很可能 - 所有进程都忙于处理慢速请求,在这种情况下,当任何进程空闲时,请求将被排队和处理,例如。完成处理请求。

我强烈建议您在尝试HAProxy之前先使用Nginx,因为后者更先进一点,因此设置得更复杂(需要调整很多开关)。

希望这会有所帮助。关键要点:Tornado非常适合异步I / O,对于CPU繁重的工作负载则更少。

答案 1 :(得分:0)

我有同样的问题,但没有龙卷风,没有mysql。 您是否与所有服务器共享一个数据库连接?

我创建了一个multiprocessing.Pool。每个都有init函数提供的自己的数据库连接。我在函数中包含慢代码,并将map包装到Pool中。所以我没有共享变量和连接。

Sleep不会阻塞其他线程,但DB事务可能会阻塞线程。

您需要在代码顶部设置池。

def spawn_pool(fishes=None):
    global pool
    from multiprocessing import Pool
    def init():
        from storage import db #private connections
        db.connect() #connections stored in db-framework and will be global in each process
    pool = Pool(processes=fishes,initializer=init)

if __name__ == "__main__":
    spawn_pool(8)


from storage import db #shared connection for quick-type requests.

#code here

if __name__ == "__main__":
    start_server()

许多并发快速请求可能会减慢一个大请求,但这种并发性只会放在数据库服务器上。