Python HTTP服务器,多个同时请求

6
我开发了一个相当庞大的http服务器,使用tornado编写,而没有设置任何特殊项,服务器在请求时会阻塞并且仅能一次处理一个请求。这些请求基本上访问数据(mysql/redis)并将其以json格式打印出来。在最坏情况下,这些请求可能需要超过一秒钟。问题是,第一个需要花费长时间(3秒)的请求到达后,紧随其后的容易处理的请求只需要5毫秒就可以完成处理。由于第一个请求需要3秒钟,所以第二个请求要等到第一个请求完成后才开始处理。因此,第二个请求需要> 3秒钟来处理。
如何使这种情况更好?我需要那个简单的第二个请求开始执行,而不管其他请求。我刚开始学习Python,并熟练掌握Apache/PHP,其中没有两个独立请求互相阻塞的概念。我尝试使用mod_python来模拟PHP示例,但似乎仍会出现阻塞现象。我是否可以更改我的tornado服务器以获取我想要的功能?无论我去哪里阅读,都说tornado很擅长处理多个同时的请求。
以下是我正在使用的演示代码。我有一个sleep命令,用它来测试并发性是否正确?
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个回答

4

编辑:请记住 Redis 也是单线程的,因此即使您有并发请求,瓶颈仍然会是 Redis。Redis 无法处理更多的请求,因此您将无法处理更多的请求。

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

从文档中可以看到:

通过使用非阻塞的网络 I/O,Tornado 可以扩展到数万个开放连接,这使其非常适合需要与每个用户保持长期连接的长轮询、WebSockets 等应用程序。

在 Tornado 中,通过异步回调实现并发处理。其思想是尽可能少地在主事件循环中执行操作,以避免阻塞,并通过回调延迟 I/O 操作。

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

最简单的方法是在 Tornado 进程前面使用反向代理,比如 HAProxy 或 Nginx。Tornado 文档推荐使用 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将负责平衡每个传入请求到不同的后端。因此,如果其中一个请求很慢(约3秒),您有n-1个其他进程正在等待传入请求。可能 - 也很可能 - 所有进程都忙于处理较慢的请求,在这种情况下,请求将排队,并在任何进程变为空闲时处理,例如完成处理请求。
我强烈建议您在尝试HAProxy之前从Nginx开始,因为后者稍微更高级,因此设置起来要复杂一些(需要调整很多开关)。
希望这可以帮助您。关键是:Tornado非常适合异步I/O,但对于CPU密集型工作负载则效果不佳。

0

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

我创建了一个 multiprocessing.Pool。每个进程都有自己的db连接,由init函数提供。我将慢速代码封装在函数中,并将其map到池中。因此,我没有共享变量和连接。

睡眠不会阻塞其他线程,但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()

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接