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

    问题竟然解决了

  • 相关阅读:
    苹果一体机发射Wi-Fi
    iphone 屏蔽系统自动更新,消除设置上的小红点
    data parameter is nil 异常处理
    copy与mutableCopy的区别总结
    java axis2 webservice
    mysql 远程 ip访问
    mysql 存储过程小问题
    mysql游标错误
    is not writable or has an invalid setter method错误的解决
    Struts2中关于"There is no Action mapped for namespace / and action name"的总结
  • 原文地址:https://www.cnblogs.com/guanhuohuo/p/12533585.html
Copyright © 2011-2022 走看看