dubbo-go icon indicating copy to clipboard operation
dubbo-go copied to clipboard

Lightweight HTTP1&2 Protocol to avoid direct depend on grpc-go library.

Open chickenlj opened this issue 1 year ago • 5 comments

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.

chickenlj avatar Mar 24 '23 08:03 chickenlj

这个工作建议跟李志信沟通下,知道下当年选用 grpc-go 的背景,然后再讨论。

AlexStocks avatar Mar 24 '23 09:03 AlexStocks

这个工作建议跟李志信沟通下,知道下当年选用 grpc-go 的背景,然后再讨论。

Actually, we had a brief discussion and reached the above conclusion. So let's see what others think about it.

chickenlj avatar Mar 24 '23 09:03 chickenlj

@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.

pyh4 avatar Mar 31 '23 14:03 pyh4

I am very interested in this issue and will submit a proposal. I look forward to further communicating with the community about this issue.

106umao avatar Apr 01 '23 17:04 106umao

Temporary triple design documentation:

Triple-go

设计目标

  1. 在完全兼容Grpc,保证与老应用正常通信的基础上,支持h1和h2下采用curl,浏览器等web方式直接访问服务,无需任何配置
  2. 剥除对grpc-go的依赖,使用net/http
  3. 保持 编写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

  1. 额外Header: triple-timeout-ms, triple-version

  2. 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"`
    }
    
  3. 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
    
  4. 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!"}

  5. 只支持unary,不支持stream

  6. 对于具有幂等性的调用,才支持GET(ignore)

Grpc

  1. 参照https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md进行实现,完全使用net/http
  2. 需要性能测试得出与grpc-go的具体差距
  3. 需要cross-test,triple client -> grpc-go server, grpc-go client -> triple server,可考虑新起一个项目保证triple本身足够轻量

protoc-gen-triple-go

  1. 为了兼容dubbo-go,引入ClientImpl和ProviderBase

    对于用户端,var cli = new(ClientImpl);config.SetConsumerService(cli);config.Load()后直接使用cli即可

    对于服务端,用户编写的struct需要wrap一下ProviderBase

  2. 目前triple-go和protoc-gen-triple-go为泛型版本,需要考虑是否更改为非泛型版本。对于用户来说,除了版本升级问题,接口处的请求参数也需要NewRequest wrap一下。

DMwangnima avatar Jun 14 '23 04:06 DMwangnima