Tars请求过程与协议分析

我们通过官网的demo来进行分析,安装demo如下代码所示。

// 1.安装tars相关工具
go install github.com/TarsCloud/TarsGo/tars/tools/tarsgo@latest
go install github.com/TarsCloud/TarsGo/tars/tools/tars2go@latest
// 2.初始化生成代码(完成代码初始化)
tarsgo make App Server Servant GoModuleName
tarsgo make TestApp HelloGo SayHello github.com/Tars/test

基本文件结构如下所示:

CREATED HelloGo/SayHello.tars (171 bytes)// 协议文件
CREATED HelloGo/SayHello_imp.go (620 bytes)
CREATED HelloGo/client/client.go (444 bytes)
CREATED HelloGo/config.conf (967 bytes)
CREATED HelloGo/debugtool/dumpstack.go (412 bytes)
CREATED HelloGo/go.mod (37 bytes)
CREATED HelloGo/main.go (517 bytes)
CREATED HelloGo/makefile (193 bytes)
CREATED HelloGo/scripts/makefile.tars.gomod (4181 bytes)
CREATED HelloGo/start.sh (56 bytes)

协议文件名称:SayHello.tars,Tars才用自研的Tars协议和其他的Rpc框架有所不同,不过Tars也可以兼容proto协议。是从生成的.tars.go开始触发,obj.servant.TarsInvoke为入口开始执行,将参数进行组装传递到Invoke,在doInvoke中执行Rpc调用,通过adapterProxy发送Rpc调用,通过send发包给对应的RPC服务。对应的发送流程图如下。

image.png

func (c *AdapterProxy) Send(req *requestf.RequestPacket) error {
	// 添加发送次数
	c.sendAdd()
	// 发送请求打包
	sbuf, err := c.servantProxy.proto.RequestPack(req)
	if err != nil {
		TLOG.Debug("protocol wrong:", req.IRequestId)
		return err
	}
	// 发送请求
	return c.tarsClient.Send(sbuf)
}

其中Send的实现是一个消息队列。

在收到RPC请求的调用后,执行TCPHandler的invoke方法进行请求处理和解析,解析完再通过链接推回去。

rsp := h.ts.invoke(ctx, pkg) // 处理请求

connSt.conn.Write(rsp) // 结果回写

总的来说就是逐字节读取数据,通过特定算法来进行识别标签类型,并传递给对应的解析器进行解析。

func (b *Reader) readHead() (ty, tag byte, err error) {
	data, err := b.buf.ReadByte()
	if err != nil {
		return
	}
	// 识别标签的算法
	ty = data & 0x0f
	tag = (data & 0xf0) >> 4
	return
}

Tars对于数据的参数位于codec文件夹,其中包含了所有的数据类型的解析。我们以字符串解析为例。

1.获取字符串类型,通过Reader的SkipToNoCheck实现,看是string1还是string4。

2.根据类型去执行对应的解析器,分别是两种部分的情况,string1 为单行字符串,string4为多行字符串。

3.获取要获取的字符串的长度,(bReadU32,逐字节读取)。

4.通过b.Next提取对应的字符串,并返回。

func (b *Reader) ReadString(data *string, tag byte, require bool) error {
	have, ty, err := b.SkipToNoCheck(tag, require)
	if err != nil {
		return err
	}
	if !have {
		return nil
	}
	//此处省略了string4的判断,重点是突出处理方案
	if ty == STRING1 {
		var length uint8
		err = bReadU8(b.buf, &length)
		if err != nil {
			return fmt.Errorf("read string1 tag:%d error:%v", tag, err)
		}
		buff := b.Next(int(length))
		*data = string(buff)
	} else {
		return fmt.Errorf("need string, tag:%d, but type is %s", tag, getTypeStr(int(ty)))
	}
	return nil
}

执行完成ReadForm之后,我们就可以得到一个基本的请求结构信息了,比如调用的是哪个,方法是哪个,超时情况,都一一描述清楚。

image.png
最后补充一下:Tars服务之间的互相调用,RPC通信是基于TCP实现的,非HTTP协议。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值