go-micro的api版本机制看example的时候感觉很简单,但是实际要是用的时候,还是有好几个点费了不少时间,最终通过扒code弄的差不多了,这里记录下。
go-micro可以提供同时提供http和grpc的访问,如果不是用自定义的EndPoint时,这两种的api版本控制没有区别,下面分别说下这几种情况下的版本控制机制。
grpc
grpc的访问主要是通过protobuf文件生成的对应语言的文件来访问,所以版本控制是通过protobuf中的package定义来控制的,只需要在package的定义中加入版本信息即可,比如:
1 | //v1 |
这里我理解只要package定义不一样,可以区别出具体的服务即可,v1和v2主要是语义上好理解
版本号建议加载api之后,这样可以保持和http访问时的一致(go-micro api gateway可自动转换grpc到http,下边会详细说)
http
go-micro的http访问主要是通过micro的api网关实现的,目前有两种形式:
/[service]/[method]
http的url按照上面的规则解析,动态转化为rpc的访问,以上面的package定义为例
1 | //v1 |
下面还有几个url解析的官方example更明了一点
Path | Service | Method |
---|---|---|
/foo/bar | go.micro.api.foo | Foo.Bar |
/foo/bar/baz | go.micro.api.foo | Bar.Baz |
/foo/bar/baz/cat | go.micro.api.foo.bar | Baz.Cat |
Versioned API URLs can easily be mapped to service names:
Path | Service | Method |
---|---|---|
/foo/bar | go.micro.api.foo | Foo.Bar |
/v1/foo/bar | go.micro.api.v1.foo | Foo.Bar |
/v1/foo/bar/baz | go.micro.api.v1.foo | Bar.Baz |
/v2/foo/bar | go.micro.api.v2.foo | Foo.Bar |
/v2/foo/bar/baz | go.micro.api.v2.foo | Bar.Baz |
code中的实现逻辑是:
- 分割url为数组
根据数组的长度来构建service和method
少于等于2,第一个作为service,整体作为method
1
2
3
4
5
6
7// If we've got two or less parts
// Use first part as service
// Use all parts as method
if len(parts) <= 2 {
name := parts[0]
return name, methodName(parts)
}等于3,前面2个作为service,后边2个为method
1
2
3
4
5// Treat /v[0-9]+ as versioning where we have 3 parts
// /v1/foo/bar => service: v1.foo method: Foo.bar
if len(parts) == 3 && versionRe.Match([]byte(parts[0])) {
name := strings.Join(parts[:len(parts)-1], ".")
r大于3,最后两个作为method,其余所有作为service
1
2
3
4// Service is everything minus last two parts
// Method is the last two parts
name := strings.Join(parts[:len(parts)-2], ".")
return name, methodName(parts[len(parts)-2:])
EndPoint
endpoint是上面不同的是,因为url是自己定义的,所以上面的方式解析出来的结果是错误的,所以必须在用url比对路由的地址的时候,就成功,否则就会报错
我这边想到的版本就是在设置EndPoint的时候加入版本号(客户端请求会带版本后,为了在比对的时候保持一致来保证成功找到注册的EndPoint),找到endpoint之后的流程就相同了,这里不过多描述。
之后我会在专门写一篇文章,从code追踪下整个url的解析过程,就会清楚为什么需要保证url一致,比对成功
1 | func registerUser(server server.Server) error { |
这里的版本号需要和**protobuf文件中的package定义的一致,否则还是服务找到对应的服务(上边提到了version添加的位置),因为最终还是需要通过rpc来访问具体的服务的。
其他
这里还有个问题,就是在main中,初始化micro服务的时候,设置的version到目前为止都没有用到,我好奇搜索了下version关键字,有发现client/selector/filter.go
中有对应version的使用,看位置应该是client用来过滤服务的,不过没细看,留个坑,之后来填。