『互联网架构』dubbo 调用埋点(114)

作者: IT人故事会 | 来源:发表于2019-07-19 11:00 被阅读7次

    原创文章,欢迎转载。转载请注明:转载自IT人故事会,谢谢!
    原文链接地址:『互联网架构』dubbo 调用埋点(114)

    上边几次都是说的单体的拦截埋点,应用的内部进行的,很多的情况系统都是分布式的,怎么去监听RPC(远程过程调用),dubbo,RMI,springcloud,http。只要远程调用,跨进程调用都属于RPC,也不可能所有的能都涉及到,很多公司都有自己的封装,例如阿里的HFS,这次只针对dubbo这种RPC进行调用。
    源码:https://github.com/limingios/netFuture/tree/master/源码/『互联网架构』调⽤链系统工程结构(111)

    (一)Dubbo执行过程

    对于dubbo的埋点,首先要了解dubbo的执行过程

    节点 角色说明
    Provider 暴露服务的服务提供方
    Consumer 调用远程服务的服务消费方
    Registry 服务注册与发现的注册中心
    Monitor 统计服务的调用次数和调用时间的监控中心
    Container 服务运行容器
    • Dubbo调用过程


    • 消费者调用过程


    (二)调用端埋点实现

    • 埋点目的
      1.捕捉消费者调用信息(远程接口、URL、参数、用时、返回结果、异常)
      2.传递TraceRequest

    • 调用信息模型表结构

    名称 类型 描述
    servicePath string 服务路径
    serviceName string 服务
    inParam json 返回结果
    outParam json 返回结果
    ErrorMessage string 异常信息
    ErrorStack text 异常堆栈
    ResultState string 执行状态
    beginTime date 开始时间
    endTime date 结束时间
    addressIp string 远程IP
    fromIp string 调用者IP
    • 埋点位置

    如何才能完整的捕捉到以上信息呢?那么就需要了解Dubbo内部的调用
    1.分解调用过程为多个步骤。
    2.这些步骤分别是在哪些协作线程上完成的?
    3.经过了哪些方法?
    4.经过了哪些过滤器?

    • 调用过程分解&线程协作


    1. 选择断点位置Debug调试调用过程
    2. 消费者调用线程源码分析:


    • 经过对源码的分析,埋点的位置如下:
      DubboInvoker.doInvoke()
      FutureFilter.invoke()
      DubboInvoker.doInvoke() 方法最靠近调用方,异常捕捉范围较大,但是该位置无法通过Attachment 向下传递TraceRequest 参数,所以需要FutureFilter.invoke() 进行补充,其具体分工如下:
      ·1.DubboInvoker.doInvoke捕获如下信息: 1、开始时间 2、服务路径 3、服务方法 4、输入参数 5、异常信息 6、本地地址
      2.FutureFilter.invoke 基于Attachment 向下传递参数 2、异常信息与堆栈 3、返回结果

    DubboInvoker.doInvoke拦截源码参见 :com.cbt.agent.collects.dubbo.DubboConsumerRpcExceptionMonitorHandle#invokerBefore

    FutureFilter.invoke拦截源码参见 :
    com.cbt.agent.collects.dubbo.DubboConsumerMonitorHandle#invokerBefore

    (三)调用端埋点实现

    • 埋点目的
      接收TraceRequest信息 ,并创建会话
    • 埋点位置:
      相对调用广方接收方埋点目的较简单,但同样需分析源码找准埋点位置
    • 提供者处理线程分析


    经分析埋点位置选在离实际调用方法较远的EchoFilter过滤器理由是捕捉的信息更全面。

    具体会话开启过程:

    1. 基于Attachment获取TraceId、ParentId、TraceProperties。
    2. 封装TraceRequest ,并此为参数开启会话。
    3. 在调用结束时关闭会话。
      具体源码参见:com.cbt.agent.collects.dubbo.DubboProviderMonitorHandle#invokerBefore

    (二)Servlet处理埋点

    • Servlet埋点目的
      1.生成TraceId
      2.开启关闭监控会话
      3.捕捉Http请求(url、客户端IP、参数、响应时长、响应状态码)

    • 埋点埋在哪?
      1.每一个Control方法
      2.DispatcherServlet.doDispatch方法
      3.HttpServlet.service 方法

    • 方案对比

    方案 优点 缺点
    应用层Control类 简单,风险因素低 判别成本高,有局限性,只能根据 HttpServlet 子类或@RequestMapping进行识别。
    DispatcherServlet.doDispatch 简单,适应性强 1、只能针对spring mvc 项目 2、spring boot 项目不支持
    HttpServlet.service 适应性强,与应用层和框架无关 1、不同的容器ClassPath不一样,存在兼容性问题。 2、存在风险,几乎所有请求都会经过此方法 3、业务异常无法捕获

    总合比较还是选择 HttpServlet.service 会更好些。

    • HttpServlet.service 埋点需要做的工作:
      1.字节码插桩
      2.请求拦截并获取请求信息

    • 字节码插桩流程

    字节码插是指在数据装载前在HttpServlet.service 插入监控指令,以拦截Http请求,其插桩的过程。

    请求拦截是指具体Http请求过来时进行拦截过滤,这么做主要是为了完成两个目的

    1.开启监控会话
    2.开启对Servlet响应过程的监控

    (三)Redis 调用埋点

    • 埋点可选方案
    方案 优点 缺点
    埋点jedis 类Get、Set等API方法 简单直接 工作量大,方法较多、需要了解每个方法特性
    埋点 Connection sendCommand方法 全面、所有命令都会经过此方法 存在未知风险、不方便计算执行时间、和返回结果
    埋点 Protocol 全面、所有命令都会经过此方法 存在未知风险、不方便计算执行时间、和返回结果

    PS:源码中可以查看DevelopBootMain类,我看这代码也看了2天,原来老写业务代码,看看这确实很容易懵X,确实这才是有技术含量的代码。其实有没有技术含量不太重要,重要是的有没有商业价值。

    相关文章

      网友评论

        本文标题:『互联网架构』dubbo 调用埋点(114)

        本文链接:https://www.haomeiwen.com/subject/ycnbhctx.html