腾讯 TarsGo 服务 Hello World——RPC 通信

2020-10-23 10:41:42 浏览数 (1)

上一篇文章(文末附链接)介绍了如何创建安装 TarsGo,同时也阐述了如何开始一个 TarsGo HTTP 服务。本文就要开始 TarsGo 的主力业务了:基于 TARS 自带的 RPC 协议,设计 TarsGo 服务。本文的内容大致思路与官方Quick Start (文末附链接)相同,但例子会有所不同,同时对于一些坑也会解释得详细点。本文的代码可以在我的 GitHub repo(文末附链接)中找到。

上一篇文章(文末附链接)中,我的 HTTP 服务器向前端返回一串 Json 字符串,其中包含了服务器时间。这一次,我设计一个服务(命名为amc.GoTarsServer.GoTarsObj)来提供服务器时间。HTTP 服务则向这个新服务请求时间之后再返回给用户。前文提到 HTTP 服务的实例名称相对不太重要,但是供内部 RPC 调用的服务,其名称就很重要了,它是其他服务进行寻址的重要依据。

TARS 框架的原生 RPC 调用是使用专门设计的 tars 协议(文件后缀名 .tars)进行通信的。这个协议其实也不神秘,读者可以自行尝试一下、多看一些示例,很快就可以了解了。这里我按照我自己写的协议文件来说明吧:

协议解析

上面的协议中,其实包含了几个部分:

• 文件名:是协议的一部分。协议文件名其实也就是这个协议包的名称,转换工具会将其转为同名的源文件。

• 模块名:参考 C 的命名空间,开发者可以自由利用这个模块名。我个人喜欢维持和 App 同名。

• 接口和方法:接口(interface)内可以定义多个 RPC 方法

• 复合数据类型:使用 `struct` 定义复合数据类型

所以,解读上面的协议,如下:

• 在接口 `DateTime` 下,定义了一个方法:`GetTime`

• GetTime 方法包含两个参数,分别是两个结构体。

• 入参中包含了变量名 `timeFmt` ,表示以什么样的格式返回时间信息

• 出参包含了 `UTC` 时间戳、本地时间戳和时间字符串

个人建议

• 在创建协议的时候,我喜欢以 `int MethodName(MethodReq req, out MethodRsq rsp)` 的模式来命名,不论是否有入参和出参,方法中的 `req` 和 `rsp` 都会存在。这种设计方式比较适合未来的扩展,如果需要添加参数或返回信息,只需要在两个 `struct` 中添加即可。

• 第一次创建协议的时候,如果入参都是必要的,那么建议均设置为 `require` 属性,表示该参数是必须的;但是在以后扩展协议时,新增参数应设置为 `optional` 属性,保证还未升级到新版本协议的 clients 仍能正常调用。

创建源码模板

首先,我们可以用 TarsGo 自带的工具首先生成工程模版:

执行脚本后,在相应目录下会生成必要的源文件:

其中 GoTars.tars 文件,我们就不需要了,用上面的 DateTime.tars 文件替换之。接着,我们使用 TarsGo 的工具,将协议文件转换为源文件:

执行后,tars2go 会在当前目录下,根据 .tars 文件中指定的 module 字段,生成一个新的目录。比如上面的协议文件,module 是 amc,那么 tars2go 就生成 amc 目录。读者可以自行查看目录下的文件,如果 .tars 文件更新的话,需要再次执行 tars2go 命令刷新相应的文件——当然,我觉得完全可以调整 makefile 的逻辑来自动实现这一点。

实现协议

协议的实现,在 gotars_imp.go 文件中实现。下面我只列出该文件中实现的主要部分:

针对代码里的几个注释说明如下:

1. 这里导入的包,就是前文 `tars2go` 所生成的 `amc` 目录下的 `go` 文件。通过导入该包,我们就可以 access 到我们在前面的 `.tars` 文件中所定义的结构体和方法。这里其实是写了一个基于 `$GOPATH` 的绝对路径来存取该包。

2. 定义了该 servant 的对象,供 server 调用——这个后文讲到 server 时会再提到。

3. 使用 TARS 自带的服务器本地日志模块。该模块需要传入一个文件名参数,模块会根据该文件名,在 `/usr/local/app/tars/app_log/amc/GoTarsServer/` 目录下生成日志文件。比如我用的 log 文件名就是:`amc.GoTarsServer_logic.log`。

4. 这是 `.tars` 文件中 `GetTime` 的实现,它作为 `GoTarsImp` 对象的一个方法来实现。从返回值的角度,TarsGo RPC 方法的返回值除了协议中定义的(本例中是 `int`,对应于 Go 的 `int32`)之外,还有一个 `error`,如果需要的话,读者可以利用。

变量 / 方法名转换

细心的读者可能会发现,在上面的实现中,数据变量名和协议中定义的并不相同。是的,这就是刚转 Go 的开发者很容易遇到的坑之一:Go 语言是使用变量 / 方法 / 常量的命名方式来决定其可见性的,只有在首字母为大写的时候,该元素才能供外部访问。

笔者特意在 `.tars` 文件中,变量名采用了首字母小写的驼峰式命名法。读者可以看到,`tars2go` 会自动将变量名和方法名的首字母改为大写,以保证其可见性。请开发者注意,否则会在编译时遇到未定义错误。

server 代码调用

现在让我们回到 `main.go` 文件。其实工具自动生成的代码就差不多了,需要修改的是包导入的部分和新建`app`对象语句,改为如下所示:

其他不变。

这里我选择了上一篇文章中提到的 GoWebServer 来调用这个 TARS 服务。这里我们就需要将已有的代码进行改造了。需要改造的代码是 goweb_imp.go 文件 :

主要逻辑的说明如下:

1. 选择路由,这里读者可以参照官方Quick Start(文末附链接)文档的说明来解释。这里笔者就只采用正式用法。其中 `192.168.211.128` 和 `17890` 是 TARS 主控 `tarsregistry` 的地址,可以通过TarsWeb界面查看

2. 准备用于承载参数和返回值的结构体

3. 这两行就是实际的 RPC 调用

服务发布的方法在前一篇文章已经说明了。GoWebServer 只需要在原有基础上做更新操作即可。本文的 GoTarsServer 也同理。不同的是在 协议 选项,应该选择 TARS。

服务发布、一切正常后,参照上一篇文章,再次访问 HTTP 服务,然后我们再查看 GoTarsServer 的 log,我们就可以看到两者已经成功地联系起来啦。

TARS可以在考虑到易用性和高性能的同时快速构建系统并自动生成代码,帮助开发人员和企业以微服务的方式快速构建自己稳定可靠的分布式应用,从而令开发人员只关注业务逻辑,提高运营效率。多语言、敏捷研发、高可用和高效运营的特性使 TARS 成为企业级产品。

附文中所有链接:

上一篇文章:https://mp.weixin.qq.com/s?__biz=Mzg3MjE0MDgyNA==&mid=2247486329&idx=1&sn=f89ea6683f8d1bdd380228425ffc7bd0&chksm=cef2920ef9851b18c639bcf1edd0b487b00efff3f29ab66b345fc60782bb0ac0f124d4761df6&token=1062688208&lang=zh_CN#rd

Quick Start:https://tarscloud.github.io/TarsDocs/hello-world/tarsgo.html

GitHub repo:https://github.com/Andrew-M-C/tencent-tars-demo


TARS基金会是Linux基金会下的非营利性、微服务基金会,致力于建设一个强大而灵活的微服务生态系统。无论你在哪个行业,无论你使用什么技术栈,这里能助你快速实现你的创意。

0 人点赞