版权声明:本文为作者原创,如需转载请通知本人,并标明出处和作者。擅自转载的,保留追究其侵权的权利。golang群:570992072。qq 29185807 个人公众号:月牙寂道长 公众号微信号yueyajidaozhang https://cloud.tencent.com/developer/article/1454555
本人微信公众号文章链接:https://mp.weixin.qq.com/s/wNULJpEr9g3TlGAhD8JuKg
Tars是腾讯开源的一款微服务框架。在去年9月,腾讯宣布正式开源 Tars 的 Golang 版本TarsGo。
当TarGo开源的时候,就想对此开源代码进行学习。近期刚好有空,就看了看。说实话,本人并未使用Tars框架,本文只是对TarsGo源码进行分析。
Tars整体框架介绍,可以参考https://github.com/TarsCloud/Tars/blob/master/Introduction.md
还有文章:
https://my.oschina.net/editorial-story/blog/2054185
关于TarsGo的介绍还有:
https://github.com/TarsCloud/TarsGo/blob/master/README.zh.md
源码地址:
https://github.com/TarsCloud/TarsGo
按照本人习惯,从低版本进行研究,此次源码分析定位v1.0.0版本
源码目录:
在Tarsgo中,有两个模块client和server
此图来源https://github.com/TarsCloud/Tars/blob/master/Introduction.md https://github.com/TarsCloud/Tars/blob/master/Introduction.md server服务运行后,会定期上报心跳到node,node然后把服务心跳信息上报到registry服务,由registry进行统一管理。 Client访问Server流程:client可以通过server的对象名Obj间接访问server,Client会从registry上拉取server的路由信息(如ip、port信息),然后根据具体的业务特性(同步或者异步,tcp或者udp方式)访问server(当然client也可以通过ip/port直接访问server)。 https://github.com/TarsCloud/Tars/blob/master/Introduction.md
在github.com/TarsCloud/TarsGo/tars/tools/Demo中有构建client和server,这将是源码开始的第一步。
transport
在此之前,有一个底层模块很独立,会优先分析
transport模块,是一个完全独立的模块,其中有底层的tarclient和tarserver模块。
在github.com/TarsCloud/TarsGo/tars/transport/examples中有两个很简单的案例
tarsclient
那么直接看源码github.com/TarsCloud/TarsGo/tars/transport/tarsclient.go
tarsclient是底层通信层,包括链接部分,以及提供了协议接口。
TarsClientProtocol是TarsClient唯一对外的接口,通过此接口,使得TarsClient模块完全独立。这样的模块设计,是非常值得推荐的。
此interface,提供两个方法:Recv,ParsePackage。
TarsClient,其中最重要的两个成员为:
cp:TarsClient对外提供的接口,这个是具体的协议处理部分
conn:是具体的链接
connection,其实很简单的结构体。主要是封装了net.conn
初始化,最重要的有:
参数cp(TarsClientProtocol),这个是协议处理部分,由外部构建传入。
52:tc.conn:构建了一个链接结构体
对于TarsClient有两个操作,send和recv
Send
58:调用了tc.conn的reConnect操作
61:将要发送的reg传送到tc.sendQueue中
160:加锁,防止并发
161:判断标志位isClosed
163:构建net.Dial,这个代码应该很熟悉了
175:设置标志位isClosed
176:开启recv协程
177:开启send协程
send协程,在reconnet中开启的
75:设置了一个ticker,定时器
79:从TarsClient的sendQueue中取出数据到req中
80-89:获取定时器信号,然后检测TarsClient的标志位isClosed。如果已经关闭则会在87行return。
定时器的这种操作,是一种常规的协程自销毁操作。
96:将读取的req通过conn发送出去。
recv
115:从conn中Read数据
134:将读取的数据,不断的append到currBuffer中
136:cp则就是TarsClientProtocol,将读取到的数据,进行协议解析
145:将解析过的数据,开启一个TarsClientProtocol的Recv协程,传入其中处理。
136和145就是TarsClientProtocol接口的两个处理地方。
小结:TarsClient的代码流程还是很简单的,模块设计也很简单,对外的接口TarsClientProtocol也是非常的合理。
tarsserver
有client,就有server
github.com/TarsCloud/TarsGo/tars/transport/tarsserver.go
server也有一个协议接口,TarsProtoCol,这里有三个方法
Invoke:数据处理部分
ParsePackage:协议解析部分
InvokeTimeout:处理超时
对于server,还有一个接口,就是底层监听,是udp还是tcp。
Listen:监听
Handle:处理部分
初始化,其中最重要的是svr(TarsProtocol)
72:获取到handle
76:则调用了handle
这里提供了两个协议,tcp和udp,是根据配置中设定来初始化。
先看下invoke,这个将在tcp或udp handle中调用。
97:handleTimeout==0的情况,应该是忽略超时。调用了TarsProtocol中的Invoke操作
99-103:开启了一个协程,来调用Invoke
104-108:有一个定时器,来判断是否超时。若超时了,则调用TarsProtocol中的InvokeTimeout操作。
server的操作还未结束,继续看看udphandler
github.com/TarsCloud/TarsGo/tars/transport/udphandler.go
里面存储了TarsServer
udphandler的listen,不解释了
udphandler的Handle接口
32:读取数据
43-48:开启了一个协程,调用了tarsServer的invoke函数。按理来说,应该是要做协议解析,再处理的。看后面的注释:no need to check package。这个应该是协议的规定
小结:udphandle比较简单
tcphandle
tcphandle相对比udphandle要复杂一些。
github.com/TarsCloud/TarsGo/tars/transport/tcphandler.go
最重要的还是ts(TarsServer)
tcp的listen,不做解释
tcp的Handle,分为三部分
43-47:开启了worker,这里有多个work处理
50:tcp的accept
59-67:对每个conn,都开启了一个协程。在65行,调用了recv操作
96:读取数据
112:将读取的数据,append到currBuffer中
114:调用了TarsProtocol的协议解析函数ParsePackage
122-124:若开启了多个worker的话,则将数据发送到jobs中
126-131:若没有开启多个worker的话,则开启一个协程,调用TarsServer的invoke。
woker的处理,就是从jobs中读取数据,然后调用TarsServer的invoke处理数据。
小结:
tcphandle相对比udphandle多了一个worker的操作,另外也多了协议解析。
现在来看案例
helloserver
目录github.com/TarsCloud/TarsGo/tars/transport/examples/helloserver
github.com/TarsCloud/TarsGo/tars/transport/examples/helloserver/server.go
构建了一个TarsProtocol的接口,MyServer
Invoke:填充了hello
ParsePackage:对包解析,并做了一些防御性操作
InvokeTimeout:超时处理
46:proto:tcp
57:构建了TarsServer
58:开启Server
github.com/TarsCloud/TarsGo/tars/transport/examples/helloserver/client.go
构建了一个TarsClientProtocol接口,Myclient
Recv:接收数据的处理部分
ParsePackage:数据协议解析
45:proto:tcp
51:构建了TarsClient
57:调用TarsClient send发送数据
总结:
transport是整个tarsgo的底层部分,其模块设计简单,并且独立。是整个tarsgo架构的底层模块。
由于文章篇幅问题,本文只做transport的分析。后续还有更多的源码分析。
龚浩华
月牙寂道长
qq:29185807
2019年05月28日