zoukankan      html  css  js  c++  java
  • 【接口平台】上报接口处理时间

    开发的swapi接口测试平台,有用户反馈有时候页面响应慢,很有可能是自己后台处理的锅,但是并不知道具体在哪些模块出现了问题,故准备接入APM平台,监控接口数据,同时又可以得到并分析用户具体使用的热点功能,方便后续的规划和优化

    因为APM暂时未有支持python后台的上报框架,需要直接对接原始的上报接口

    如何做到将所有的接口数据(包括响应时间、状态码、请求的数据等信息)均上报apm

    开始想尝试使用装饰器+异步处理实现,还有网友的跳坑经历

    def cost_count(func):
        @wraps(func)
        def wraper(*args, **kw):
            a = time.time()
            func(*args, **kw)
            # return func(*args, **kw)
            print(time.time()-a)
        return wraper
    
    @app.route("/view/<slug>", methods=['GET'])
    @cost_count
    def page_view(slug):
        return render_template("view.html",entry=entry)
    

    这样即使填了坑,也需要在每个路由加上装饰器,麻烦且低效

    flask好歹也是一个相对强大的框架,是否有什么方式可以支持呢?

    发现或许before_request 和 after_request可以解决问题

    @app.before_request
        def before_request(request):
        	pass
    
    @app.after_request
        def after_request(response):
        	pass
    

    在before_request的时候记录开始请求的时间,after_request进行异步上报,既可以完美实现,又不影响性能

    flask又提供了异步处理的方法

    from flask import Flask
    import time
    from concurrent.futures import ThreadPoolExecutor
     
    executor = ThreadPoolExecutor(1)
     
    app = Flask(__name__)
     
    @app.route('/synchronize')
    def update_redis():
        executor.submit(do_update)
        return 'ok'
     
    def do_update():
        time.sleep(10)
        print('start update')
     
    if __name__ == '__main__':
        app.run()
    

    但是有个问题,在before_request中需要传递接口开始处理的时间戳,但是怎么将值传给after_request呢?
    开始想着赋值给一个request.headers,然后直接异常抛出
    发现在和前端定义接口时,header中必须有时间的变量,使用的时候才发现,当时定义的时间是秒级别的,但是现在需要至少毫秒级别的时间或时间戳,故此方案行不通

    后面发现其实可以赋值给app = Flask(name,) 的全局变量,然后在处理该请求的线程中传递变量即可

    @app.before_request
    def before_request():
        # 将当前时间戳赋值给app全局变量
        app.g = int(round(time.time() * 1000))
    
    @app.after_request
    def after_request(response):
        # 异步上报apm数据
        executor.submit(ApmCollect().collectReq,(request.method,request.path,response.status_code,app.g))
        # 返回请求响应
        return response
    

    在本地windows环境中调试ok后部署到正式环境,发现没有上报数据,尴尬

    打日志查看原因,发现 ApmCollect().collectReq 方法中的request请求并未执行,且未有任何的异常报错

    requests.post(APM_COLLECT_URL, headers=headers, json=body, verify=False, timeout=10)
    

    执行其他语句均没有问题,执行任意的requests.post请求均未有任何响应

    将requests.post放在before_request和after_request中执行,均可正常执行,看来问题出在executor.submit异步执行上

    在网上在原因的时候发现,有网友得到这样的结论

    flask自带的开发服务器默认是不开启多线程的,浏览器A请求时已经占用了唯一的“线程”,
    而在这个请求中又通过requests.post发起了一个请求B,但此时已经没有可用的“线程”了,
    于是出现了B在等待A释放“线程”,A在等待B返回,于是一直卡死在那
    

    不过在文章后面又推翻了自己的结论,尴尬

    是否是因为 executor.submit 的调用时候出现了问题,换个调用方式

    # 异步上报apm数据
        executor.submit(ApmCollect().collectReq(request.method,request.path,response.status_code,app.g))
    

    问题竟然解决了

  • 相关阅读:
    SSM学习(三)--集成spring mvc
    SSM学习(二)mybatis和spring的集成
    SSM学习(一)搭建基础框架
    (转)Maven依赖的jar包下载不了、jar更新不了的解决办法
    maven安装配置及使用maven创建一个web项目
    JavaWeb -- Servlet+JSP+JavaBean(MVC)模式
    JavaWeb -- JSP+JavaBean模式
    JavaWeb -- Jsp 和 JavaBean
    JavaScript -- 练习 window 流氓广告
    上网代理
  • 原文地址:https://www.cnblogs.com/guanhuohuo/p/12533585.html
Copyright © 2011-2022 走看看