tornado框架调用AsyncHTTPClient,出现阻塞并严重延迟的问题?

发布于 2022-09-04 04:34:40 字数 1937 浏览 28 评论 0

1,我有用tornado框架搭建了一个web服务对外提供访问,我们暂且叫他A服务,这个A服务实际上就是调用本机的另一个web服务(也是tornado搭建的)我们暂且叫它B服务,如果B服务返回不是200,就调用另一个web服务(也是tornado搭建的)我们暂且叫它C服务,都是本机localhost调用,我发现被调用的B,C服务都很快结束,不到1秒,而A服务这边做的时间计时,发现很慢,达到20秒,请各位帮我看看!

我用的python2.7,tornado3.2

2,以下是代码

@asynchronous
@gen.coroutine
def get(self):
    cost_array=[int(time.time()*1000)]
    result=yield self.callB(q,start_date)
    cost_array.append(int(time.time()*1000))
    if result["code"]!=200:
        result=yield self.callC(q,start_date)
        cost_array.append(int(time.time() * 1000))
        
    self.set_status(result["code"])
    self.write(result["response"])
    
   @gen.coroutine
def callB(self, q, start_date):
    result={
        "code":0,
        "response":{}
    }
    url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
    request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
    sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

    result["code"]=sever_response.code
    if sever_response.body:
        result["response"]=sever_response.body
    raise gen.Return(result)
    
@gen.coroutine
def callC(self, q, start_date):
    result={
        "code":0,
        "response":{}
    }
    url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
    request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
    sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

    result["code"]=sever_response.code
    if sever_response.body:
        result["response"]=sever_response.body
    raise gen.Return(result)
    

以上代码执行一段时间还行,过了一段时间后,cost_array数组里面记录的时间戳直接差距的秒数能达到20秒以上,然后服务也没办法对外提供访问了,但进程的cpu和内存占用很小!!访问都是超时了。只能重启服务

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

假装不在乎 2022-09-11 04:34:40

首先,吐槽几句:

  1. 没有说明使用的python、tornado版本,服务器版本(虽然服务器版本估计不涉及)

  2. 代码没有格式化

  3. 既然给出的是A服务的代码,示例里面竟然还有CallA CallC,那么,这段代码是"B"?

  4. 没有给出完整可以执行的脚本,包括B、C服务,你贴了一个30%完成度的代码段,然后期待别人给你补全剩下70%的测试代码(连main函数部分都没有),完成B、C服务的部分,并且给出完整的解释并告知你如何错了?这个不是不懂,是懒。

百度“提问的智慧”会很有帮助。

顺手帮你补全了A,B,C的代码,而这段代码是全路通秒回。

A

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler
from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time


class XHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        q = self.get_argument("q", "")  # 缺失
        start_date = self.get_argument("start_date", "20161010")  # 缺失
        cost_array = [int(time.time() * 1000)]
        result = yield self.callB(q, start_date)
        cost_array.append(int(time.time() * 1000))
        if result["code"] != 200:
            logging.info("calling C")
            result = yield self.callC(q, start_date)
            cost_array.append(int(time.time() * 1000))
        else:
            logging.info("no need call C")
        self.set_status(result["code"])

        logging.info("call cost time %s", cost_array)
        self.write(result["response"])

    @gen.coroutine
    def callB(self, q, start_date):
        result = {"code": 0, "response": {}}
        url = "http://127.0.0.1:8100/?q=%s&startdate=%s" % (q, start_date)
        request = HTTPRequest(url=url,\
                              method="GET", \
                              follow_redirects=False,\
                              request_timeout=3000)
        sever_response = yield gen.Task(AsyncHTTPClient().fetch, request)

        result["code"] = sever_response.code
        if sever_response.body:
            result["response"] = sever_response.body
        raise gen.Return(result)

    @gen.coroutine
    def callC(self, q, start_date):
        result = {"code": 0, "response": {}}
        url = "http://127.0.0.1:8200/?q=%s&startdate=%s" % (q, start_date)
        request = HTTPRequest(url=url,\
                              method="GET", \
                              follow_redirects=False,\
                              request_timeout=3000)
        sever_response = yield gen.Task(AsyncHTTPClient().fetch, request)

        result["code"] = sever_response.code
        if sever_response.body:
            result["response"] = sever_response.body
        raise gen.Return(result)


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', XHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8000)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

B

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler

from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time
import json


class BHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        self.set_status(202)
        self.write(json.dumps({"msg": "later"}))


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', BHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8100)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

C

# -*- coding: utf-8 -*-

import os
import logging
import tornado
import tornado.ioloop
import tornado.options
from tornado.options import define, options
from tornado.web import RequestHandler as BaseRequestHandler

from tornado.httpclient import HTTPRequest, AsyncHTTPClient
from tornado import gen
from tornado.web import asynchronous
import time
import json


class CHandler(BaseRequestHandler):
    @asynchronous
    @gen.coroutine
    def get(self):
        self.write(json.dumps({"msg": "later"}))


class Application(tornado.web.Application):
    def __init__(self):
        handlers_ = [(r'/', CHandler), ]
        tornado.web.Application.__init__(self, handlers_)


def main():
    tornado.options.parse_command_line()
    app = Application()
    logging.info("service started.")
    app.listen(8200)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

给几个定位的思路:

  1. A服务的调用超时应该是没有设置成功,从20s数值来看,根本就是超时了。

  2. 使用curl模拟调用B,C,确认这俩真的是秒回。

  3. A多打点日志,看到底卡在哪里。

热血少△年 2022-09-11 04:34:40

将代码:

url="http://localhost:8200/*?q=%s&startdate=%s"%(q,start_date)
request = HTTPRequest(url=url,\
                          method="GET", \
                          follow_redirects=False,\
                          request_timeout=3000)
sever_response=yield gen.Task(AsyncHTTPClient().fetch,request)

改为以下方式即可:

sever_response=yield AsyncHTTPClient().fetch(url)

即可

执着的年纪 2022-09-11 04:34:40

HTTPRequest 默认选项request_timeout 就是 20S,你超时时间单位搞错了吧

微凉徒眸意 2022-09-11 04:34:40

tornado有个坑人的参数,调用耗时的服务会被触发,max_clients表示ioloop中可以并发执行的httpclient数量

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文