Kindling协议开发流程 - Dubbo2 协议开发流程

本文档介绍了Kindling协议开发流程,特别是针对Dubbo2协议的解析。内容包括协议解析流程、设计思路、报文解析结构体和API,以及详细的开发步骤和Dubbo2协议的分析、实现。通过创建协议解析器和注册新协议,实现了对Dubbo2请求和响应的高效解析。
摘要由CSDN通过智能技术生成

1 项目概览

Kindling collector项目作为Go端分析器,使用类似opentelmetry的pinpeline进行数据分析。其中涉及5个组件:

  • UdsReceiver - Unix Domain Socket接收器,接收探针事件并传递给后续的网络分析器。
  • NetworkAnalyzer - 网络事件分析器,将接收的Read / Write事件匹配成单次请求后,根据协议解析请求内容生成关键指标,传递给后续的分析器。
  • K8sMetadataProcessor - K8S指标处理器,补充K8S指标并传递给后续的聚合处理器
  • AggregateProcessor - 数据聚合处理器,将接收的指标数据生成Trace和Metric,传递给给后续的转发器。
  • OtelExporter - Opentelmetry转发器,将Trace / Metric数据转发给Prometheus进行展示。

其中协议解析流程主要在NetworkAnalyzer组件中进行,将接收的请求/响应事件成对匹配后,交由parseProtocols()函数解析出协议指标。

1.1 协议解析流程

NetworkAnnalyzer.parseProtocols()方法定义了整体解析流程,根据协议解析器分别解析请求和响应,当最终都成功时输出指标。

1.2 协议解析设计思路

正常的协议解析只负责逐帧解析指标功能。

现已支持5种协议解析,当协议越来越多时,遍历引起的解析会越来越耗时,那么需引入fastfail快速识别协议

对于复杂的多报文协议,如Kafka有不同的API报文,而相同API也有不同的版本报文。将所有报文解析逻辑都写在一起会使整个类过于臃肿且不易维护。为此引入树形多报文结构用于快速且低耦合地实现开发。

1.2.1 报文解析结构体

在树形报文解析过程中,有如下2个场景需要考虑

  • 当父协议解析了指标A,子协议解析可能会用到A指标,那么父子协议解析的指标需要透传。
  • 父协议已解析了部分报文长度的内容,那么子协议在开始解析时可直接跳过相应长度的内容进行解析,此处引入偏移量用于下一个协议跳过解析。

定义PayloadMessage,封装报文内容、读取偏移量和指标存储的Map。

type PayloadMessage struct {
   
    Data         []byte
    Offset       int
    attributeMap *model.AttributeMap
}

1.2.2 报文解析API

由于引入协议树,协议解析过程parse() (ok bool)将不再适用。协议树中的个协议的解析成功不表示整个协议解析成功,需解析整颗树的协议是否成功,将API扩展为parse() (ok bool, complete bool)。

  • 对于单层协议(HTTP),返回为(ok, true)


基于以上几点需求,设计树形结构的报文解析器PkgParser。PkgParser定义了fastFail(快速识别失败) 和parser(解析单个报文)函数;每个协议只需注册自身的PkgParser即可接入整套流程。
*fastFail(message PayloadMessage) (fail bool)

  • 声明协议是否识别失败,用于快速识别协议

*parser(message PayloadMessage) (ok bool, complete bool)

  • 解析协议,将解析出的指标存储到message的Attributes中
  • 返回是2个参数:
    • 是否解析成功
    • 是否解析完成 (默认为true,当为false主要是用于嵌套解析过程,例如先定义一个头解析,再定义不同的消息体解析)。

1.3 请求 / 响应解析

ProtocolParser定义了请求和响应的解析器,并提供ParseRequest()和ParseResponse() API用于解析请求和响应
其中response的message携带了request解析出的attributes指标,用于匹配。eg. kafka的correlationId request和response报文需一致,且response报文解析用到了request的key。

2 开发流程

2.1 添加协议名

const (
	HTTP      = "http"
  ...
	XX        = "xx" // 此处替换具体协议名
	...
)

2.2 创建协议

analyzer/network/protocol目录下创建文件夹xx,xx替换为具体协议,并创建3个文件xx_parser.go、xx_request.go 和 xx_response.go

analyzer/network/protocol/xx
├── xx_parser.go           协议解析器
├── xx_request.go          实现请求解析流程
└── xx_response.go          实现响应解析流程

2.2.1 xx_request.go

实现fastfail()和parser()函数

func fastfailXXRequest() protocol.FastFailFn {
   
	return func(message *protocol.PayloadMessage) bool {
   
        // 根据报文实现具体的fastFail()函数
		return false
	}
}

func parseXXRequest() protocol.ParsePkgFn {
   
	return func(message *protocol.PayloadMessage) (bool, bool) {
   
        // 解析报文内容
		contentKey := getContentKey(message.Data)
		if contentKey == "" {
   
            // 第一个参数false 表示解析失败,第二个参数表示报文解析完成
			return false, true
		}

        // 通过AddStringAttribute() 或 AttIntAttribute() 存储解析出的属性
		message.AddStringAttribute(constlabels.ContentKey, contentKey)
        // 解析成功
		return true, true
	}
}

2.2.2 xx_response.go

实现fastfail()和parser()函数

func fastfailXXResponse() protocol.FastFailFn {
   
	return func(message *protocol.PayloadMessage) bool {
   
        // 根据报文实现具体的fastFail()函数
		return false
	}
}

func parseXXResponse() protocol.ParsePkgFn {
   
	return func(message *protocol.PayloadMessage) (bool, bool) {
   
        // 通过GetStringAttribute() 或 GetIntAttribute() 读取request解析后的参数
		contentKey := message.GetStringAttribute(constlabels.ContentKey)
		
        // 解析响应报文
        errorCode := getErrorCode(message)
        if errorCode > 20 {
   
            // 有errorCode或errorMsg等常见,需定义IsError为true用于后续processor生成Metric
			message.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值