dubbo-go
dubbo-go copied to clipboard
Lightweight HTTP1&2 Protocol to avoid direct depend on grpc-go library.
According to the Dubbo3 architecture, Triple protocol should be defined as a slim HTTP-based protocol for building browser and gRPC-compatible, high-performance web and rpc services.
With the above goal in mind, the Triple implementation in Dubbo-go should be able to do the following:
- Communicate with original gRPC servers seamlessly.
- Being able to be consumed by the browser directly
- Can be easily integrated with all kinds of Dubbo features such as Filter, Router, Registry, etc. with low maintenance efforts and good user experience.
- Lightweight enough with only a few hundred or thousands of lines of code.
- Introduce as less third-party libraries as possible.
- Generated stub should have a gopher-friendly programming API.
But the current implementation is still far away or even impossible to meet those requirements. The current implementation depends directly on grpc-go library to fulfill data exchange purpose and is a way proven to have many drawbacks:
- Hard to integrate with the extensions and features defined by Dubbo.
- Hard to upgrade the grpc-go library since the new version might bring breaking changes.
- The whole grpc-go binary package is introduced in the dependency tree but only the RPC protocol part is used.
- It's hard to support HTTP based programming model directly on grpc-go, so the only option is proxy-based grpc-web.
- We have our own stub generator which has nothing to do with protoc-gen-grpc.
So, I think we should provide our lightweight HTTP/2 rpc protocol implementation, and to achieve that, a very similar one provided by Buf Connect Go can be a very good reference to start.
这个工作建议跟李志信沟通下,知道下当年选用 grpc-go 的背景,然后再讨论。
这个工作建议跟李志信沟通下,知道下当年选用 grpc-go 的背景,然后再讨论。
Actually, we had a brief discussion and reached the above conclusion. So let's see what others think about it.
@chickenlj Hi, there! I am a graduate student in software engineering at Zhejiang University. I have experience in Golang. I have contributed to open source project before and I am interested in this issue.
I have gone through the details and here are my understandings of the issue:
- Triple protocol is based on HTTP/2 + gRPC and is fully compatible with gRPC over HTTP/2.
- dubbo-go is currently using grpc-go to fulfill data exchange and leads to many drawbacks.
- Implement a lightweight HTTP/2 RPC protocol instead of introducing grpc-go as a dependency.
- Refer to protocol "Connect" in bufbuild/connect-go, which works over HTTP/2.
Any further advice and guidance would be appreciated.
I am very interested in this issue and will submit a proposal. I look forward to further communicating with the community about this issue.
Temporary triple design documentation:
Triple-go
设计目标
- 在完全兼容Grpc,保证与老应用正常通信的基础上,支持h1和h2下采用curl,浏览器等web方式直接访问服务,无需任何配置
- 剥除对grpc-go的依赖,使用net/http
- 保持 编写IDL文件->protoc编译自动生成stub代码->实现业务逻辑 的工作模式,stub代码结构与接口向Grpc靠近(暂定)
设计细节
组成
Rest + Grpc,服务端在单端口上同时支持这两种协议,客户端由用户选择调用方式,默认为Grpc
协议区分
统一进入ServeHTTP(responseWriter http.ResponseWriter, request *http.Request)后,
POST/GET? + content-type: application/ -> Rest
POST + content-type: application/grpc -> Grpc
Rest
-
额外Header: triple-timeout-ms, triple-version
-
rpc错误信息: json编码的Error
type WireError struct { Code Code `json:"code"` Message string `json:"message,omitempty"` // google.golang.org/genproto/googleapis/rpc/errdetails Details []*ErrorDetail `json:"details,omitempty"` }
-
Triple Error Code与HTTP Code映射:
switch code { case CodeCanceled: return 408 case CodeUnknown: return 500 case CodeInvalidArgument: return 400 case CodeDeadlineExceeded: return 408 case CodeNotFound: return 404 case CodeAlreadyExists: return 409 case CodePermissionDenied: return 403 case CodeResourceExhausted: return 429 case CodeFailedPrecondition: return 412 case CodeAborted: return 409 case CodeOutOfRange: return 400 case CodeUnimplemented: return 404 case CodeInternal: return 500 case CodeUnavailable: return 503 case CodeDataLoss: return 500 case CodeUnauthenticated: return 401
-
GET query params(ignore)
triple=v1 // 协议版本
encoding=json //编码方式,等同于content-type
message=... //编码后的请求参数,还需要经过base64序列化
compression=gzip //压缩方式,等同于content-encoding
eg:
GET /buf.greet.v1.GreetService/Greet?triple=v1&encoding=json&msg=%7B%22name%22%3A%22Buf%22%7D HTTP/1.1 Host: demo.connect.build
< HTTP/1.1 200 OK < Content-Type: application/json < < {"greeting": "Hello, Buf!"}
-
只支持unary,不支持stream
-
对于具有幂等性的调用,才支持GET(ignore)
Grpc
- 参照https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md进行实现,完全使用net/http
- 需要性能测试得出与grpc-go的具体差距
- 需要cross-test,triple client -> grpc-go server, grpc-go client -> triple server,可考虑新起一个项目保证triple本身足够轻量
protoc-gen-triple-go
-
为了兼容dubbo-go,引入ClientImpl和ProviderBase
对于用户端,var cli = new(ClientImpl);config.SetConsumerService(cli);config.Load()后直接使用cli即可
对于服务端,用户编写的struct需要wrap一下ProviderBase
-
目前triple-go和protoc-gen-triple-go为泛型版本,需要考虑是否更改为非泛型版本。对于用户来说,除了版本升级问题,接口处的请求参数也需要NewRequest wrap一下。