Thriftgo IDL 裁切工具
简介
Thriftgo 是 Go 语言实现的 Thrift IDL 解析和代码生成器,支持完善的 Thrift IDL 语法和语义检查。相较 Apache Thrift 官方的 Golang 生成代码,Thriftgo 做了一些问题修复且支持插件机制,用户可根据需求自定义生成代码。Kitex 的代码生成工具就是 Thriftgo 的插件实现之一。
一些 IDL 仓库可能会因为没有及时维护清理废弃的内容,随着版本迭代,无关内容越来越多,造成了生成的 Golang 代码仓库变得很大,IDL 的可读性也下降。也可能由于引用或者间接引用了过多的IDL,导致很多无关的结构被纳入生成代码中,导致生成代码体积过大或生成过程产生异常。这些问题在复杂项目实践中出现较为频繁,可能阻塞业务的开发流程。
Thriftgo 在 v0.3.1+ 版本提供了 Thrift IDL 裁切功能,用于针对不会被 service 引用到的结构进行裁剪,以删除对 RPC 无影响和依赖的结构,从而减少没有用的生成代码。
该功能可以直接通过 Thriftgo 项目下提供的 Trimmer 工具单独使用,生成裁切过后的 IDL,也可以配合 Thriftgo/Kitex 命令行使用,在代码生成时直接过滤掉无用的内容。
裁切原理
- 遍历给定 IDL 文件中包含的所有 service,找到 service 和 method 里所有直接或者间接引用的 struct 结构体,将他们标记为“有用”
- 扫描该项目直接或间接引用的所有 IDL,对于所有的 struct 结构体,如果没有被标记为“有用”,就裁切掉
- 由于业务开发往往通过 IDL 来引入枚举和常数,所以工具不对 IDL 中的typedef、枚举和常数进行裁切
- 将裁切后的结果重新输出为 .thrift 结尾的 IDL 文件,或者生成 Golang 代码
下面是一个示意图,裁切前,这组 IDL 文件以及内容如下:
使用裁切工具后,会根据 IDL A 里的 service A 遍历所有结构体,将用不到的 struct 结构体删除,最终输出如下:
使用 Trimmer 工具
Trimmer 工具支持处理 thrift IDL 文件,并将裁切后的结果重新以 thrift IDL 文件的形式输出
安装 Trimmer 工具:
go install github.com/cloudwego/thriftgo/tool/trimmer@latest
查看版本/验证工具安装:
trimmer -version
使用格式:
trimmer [options] file
Options:
--version 打印版本信息
-h, --help 打印帮助信息
-o, --out [file/dir name] 指定输出IDL的文件名/输出目录
-r, --recurse [dir] 指定一个根目录,复制其目录结构到输出目录并递归地输出指定IDL及其引用IDL到相应位置。如指定-o,必须为一个目录
-m, --method [service.method] 指定只保留某个或多个 Method 进行裁切
单文件处理
当想对单个 IDL 文件进行裁切时,可执行如下命令:
trimmer sample.thrift
执行成功后,会输出裁切后的 IDL 文件位置,你会看到如下提示:
success, dump to example_trimmed.thrift
默认的命名为原名 + trimmed 后缀,如果想把裁切的 IDL 输出到指定目录或者重命名,可带上 -o 参数:
trimmer -o abc/my_sample.thrift sample.thrift
递归裁切
如果想对某个 IDL 进行裁切的同时裁剪和输出其引用到的相关 IDL,可以使用 -r 参数:
trimmer -r test_cases/ test_cases/my_idl/a.thrift
注意,当使用 -r 时,需要在 -r 参数后面指定 IDL 文件目录,工具会在这个文件夹内寻找依赖的 IDL 并裁切后维持目录结构输出(裁切依据是指定 IDL 的依赖性),默认的输出位置是 trimmed_idl
文件夹下。可以通过 -o 来设置输出的文件夹名称。
输出后的目录结构如下:
.
├── test_cases // 原 IDL 文件目录
│ ├── my_idl
│ │ └── a.thrift
│ ├── b.thrift
│ ├── c.thrift
└── trimmed_idl // 输出后的 IDL 文件目录
├── my_idl
│ └── a.thrift
└── c.thrift
注意,由于 IDL 定义本身不记录缩进、换行、顺序等,输出的新 IDL 文件的字段顺序可能与原版本不同。
指定 Method 裁切
在「裁切原理」部分提到,默认情况下,Trimmer 工具是查找所有 Service 的所有 Method 来裁切结构体。如果想将裁切逻辑精确到某个或多个 Method,可以使用 -m 参数,以 [service_name.method_name]
的方式指定
trimmer -m MyService.MethodA -m MyService.MethodB example.thrift`
当目标 IDL 只有一个 Service 时,可以忽略 Service 名:
trimmer -m MethodA -m MethodB example.thrift
执行后,其他的 Service 以及 Method 将会被裁切掉,只有当前指定的 Method 以及其依赖的结构体会被保留。
在 Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)中,指定 method 裁切功能支持了正则表达式的 method 匹配方式。用户可以构造正则表达式来匹配[serviceName].[methodName]
的方法名,精确指定一个或多个方法。例如:
trimmer -m 'Employee.*\..*' test_cases/sample1.thrift
可以匹配 “Employee” 开头的 service 下的全部方法。(注:"." 在正则表达式有意义,最好使用 “.” 来匹配)
也可以使用一些 perl 风格的表达式进行一些高级裁切操作,例如:
trimmer -m '^(?!EmployeeService.getEmployee).*$' test_cases/sample1.thrift
可以匹配除了 EmployeeService.getEmployee
外的所有方法。执行这条命令,可以单独从 IDL 中删除该方法及其依赖(且其他方法无依赖)的结构。
保护结构不被裁切
基于特定开发需要,可能希望裁切工具保留一些结构不被裁切,从而利用对应的生成代码。可以在想要保护的 struct、union、exception 的上方使用注释 @preserve
进行标注,裁剪时将无条件将其保留。可以和其他注释共存,但需要确保 @preserve
注释位于单独的一行内。
例如:
// @preserve
struct Useless{
}
即使该结构没有被引用,其仍然会在裁剪后被保留。
本功能默认开启,可以通过设置 -p 或 -preserve 参数为 false 将其禁用。例如:
trimmer -p false sample.thrift
此时 Trimmer 工具将无视 @preserve 注释进行裁剪。
在 Kitex Tool 中集成
Trimmer 功能也可以直接集成在 Thriftgo/Kitex 生成代码中,但首先确保 Thriftgo 版本不低于 v0.3.1
以 Kitex 为例,使用时添加 -thrift trim_idl
参数,例如:
kitex -module xx -thrift trim_idl xxx.thrift`
使用该参数时,命令行会额外输出额外提示:
[WARN] You Are Using IDL Trimmer
代码生成时,将会对所用到 IDL 进行裁切,最终生成的 Golang 代码就不会有无用的 Struct 结构体了。
使用 yaml 进行配置
为了方便通过 Kitex/Thriftgo 集成方法进行裁切时使用 trimmer tool 的参数配置,Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)为 trimmer 工具提供了 yaml 配置文件支持。在集成 Kitex/Thriftgo 或直接使用 trimmer 工具时,trimmer 都会自动扫描并应用当前执行的目录(os.Getwd())下的 trim_config.yaml 配置文件。
在启用 yaml 配置文件时,你会收到类似提示:
using trim config: /xxx/trim_config.yaml
除了为集成 Kitex/Thriftgo 提供一种配置参数的方法,通过书写 yaml 配置文件,IDL 作者可以向用户或代码维护者提前圈定裁切的保留内容等,IDL 使用者也可以以此作为模板方便批量裁切或传递给其他人。
Yaml 配置示例:
methods:
- "TestService.func1"
- "TestService.func3"
preserve: true
preserved_structs:
- "usefulStruct"
配置格式
目前可通过 yaml 配置的选项如下:
- methods:字符串数组,和 -m 参数等效,表示使用指定 method 裁切功能。格式和功能请参考“指定 Method 裁切”部分。如果命令行参数指定了 -m 参数,会覆盖此处 yaml 配置。
- preserve:bool 型,和 -p 参数等效,置为 false 表示禁用 @preserve 注释等保护结构不被裁剪的功能,默认为 true。如果命令行参数指定了 -p 参数,会覆盖此处 yaml 配置。
- preserved_structs:字符串数组,表示需要保护的结构名。如果 preserve 或 命令行的 -p 参数设置为 true,trimmer 将无条件对指定名字的结构进行保留。可以用于 struct、union、exception 结构。