1. Background 1.1 Problem to be solved
More and more cloud-native applications are adopting gRPC as their API standard, such as etcd, Dapr, and Envoy. In some cases, only the gRPC API is available. Apache APISIX currently does not support access to the API exposed by the gRPC service, and can only go through the HTTP interface or develop a separate service to act as a proxy. 1.2 The benefits of solving this problem 1. Allow user to connect with their own gRPC services. 2. Embrace the ecosystem of Envoy and Dapr 3. Show our leadership of the popular technology and provide something the rival is missing. 2. How to solve the problem We will create a new Nginx module called ngx-grpc-client-module so that we can interact with Nginx's event system. We choose to use a mature gRPC implementation and write Lua/C binding for it. Hence we study multiple gRPC clients: Language: C++ Repo: https://github.com/grpc/grpc Pro: 1. High performance 2. Widely used Con: 1. Require nearly 2GB dependencies 2. Not easy to compile unless you are a C++ developer Language: Go Repo: https://github.com/grpc/grpc-go Pro: 1. Written in pure Go 2. Widely used 3. Familiar to me Con: 1. Low performance (We also study connect-go, but it has worse performance) Language: Rust Repo: https://github.com/hyperium/tonic Pro: 1. Written in pure Rust 2. High performance Con: 1. Not familiar to me so I can't make sure it is mature enough If APISIX is a company-inside project, I will choose to use C++. However, APISIX is an open source project, and it is important to lower the threshold for participation. People used to complain it is hard to build APISIX from source, so we can't choose C++. We can use Go first and switch to Rust in the future if the performance is critical. Changing the underneath gRPC implementation won't break the Lua API provided by this module. The process of unary request can be done in the steps below: 1. Encode the proto message and start gRPC call 2. Create task ctx, call the Go code and suspend Lua thread 3. Execute gRPC code, put the task ctx and final result to the task done queue 4. Wait on the task done queue 5. Remove the data from task done queue 6. Add the task ctx to Nginx's posted event queue and re-wait on the task done queue 7. Resume Lua thread 8. Finish the gRPC call and decode proto message Step 1/8 are done in the Lua. Step 2/4/6/7 are done in the C code. Step 3/5 are done in the Go (or other gRPC implementation) Client / Server stream requests can be considered as one initial call plus several unary read/write operations.