6

私は、トルネードを利用して Python で書かれたかなり大規模な http サーバーを開発しました。特別な設定をしなくても、サーバーはリクエストをブロックし、一度に 1 つのみしか処理できません。リクエストは基本的にデータ (mysql/redis) にアクセスし、json で出力します。これらのリクエストは、最悪の場合、1 秒以上かかることがあります。問題は、長い時間 (3 秒) を要する要求が入ってきて、その直後に簡単な要求が入ってきて、処理に 5 ミリ秒かかることです。最初のリクエストには 3 秒かかるため、最初のリクエストが完了するまで 2 番目のリクエストは開始されません。したがって、2 番目のリクエストの処理には 3 秒以上かかります。

どうすればこの状況を改善できますか? 他のリクエストに関係なく、実行を開始するには、2 番目の単純なリクエストが必要です。私は python が初めてで、apache/php の経験が豊富で、2 つの個別のリクエストが互いにブロックするという概念はありません。PHPの例をエミュレートするためにmod_pythonを調べましたが、それもブロックしているようです。tornado サーバーを変更して、必要な機能を取得できますか? どこを読んでも、tornado は複数の同時リクエストの処理に優れていると書かれています。

これが私が取り組んでいるデモコードです。並行性が機能するかどうかをテストするために使用しているスリープ コマンドがあります。スリープは並行性をテストする公正な方法ですか?

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()

助けてくれてありがとう!

4

2 に答える 2

4

編集:Redisもシングルスレッドであることを覚えておいてください。したがって、同時リクエストがある場合でも、Redisがボトルネックになります。Redis が処理できないため、それ以上のリクエストを処理することはできません。

Tornado は、シングル スレッドのイベント ループ ベースのサーバーです。

ドキュメントから:

ノンブロッキング ネットワーク I/O を使用することで、Tornado は何万もの開いている接続に拡張できるため、各ユーザーへの長時間の接続を必要とするロング ポーリング、WebSocket、およびその他のアプリケーションに最適です。

tornado での同時実行は、非同期コールバックによって実現されます。メイン イベント ループ (シングル スレッド) での処理をできるだけ少なくして、ブロックを回避し、コールバックを介して 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 は、異なるバックエンドへの各受信リクエストのバランスを取ります。したがって、リクエストの 1 つが遅い場合 (~ 3 秒)、着信リクエストをリッスンする他のプロセスが n-1 個あります。すべてのプロセスが遅いリクエストの処理でビジーになる可能性があり、その可能性は非常に高いです。リクエストの処理を終了しました。

HAProxy を試す前に Nginx から始めることを強くお勧めします。HAProxy は少し高度であり、適切にセットアップするのが少し複雑です (微調整するスイッチがたくさんあります)。

お役に立てれば。重要なポイント: Tornado は非同期 I/O には最適ですが、CPU の負荷が高いワークロードにはあまり適していません。

于 2013-09-03T20:59:56.607 に答える