This article also has a Chinese version.
This article will introduce the design and implementation of a Rust FFI (Foreign Function Interface) framework that I created for calling Golang code from Rust. It will cover the design from the perspective of a designer and implementer, considering various options and explaining the choices made and the reasons behind them. It will also cover some implementation details.
The project is open-sourced on GitHub: https://github.com/ihciah/rust2go. It is a personal hobby project from the beginning, but it is also used in my current company. I will share this topic at this year’s Rust Conf China(2024) and welcome to attend.
Compared to Golang, Rust programs are not garbage-collected and have stronger compile-time checks. Also thanks to LLVM, Rust gets the best possible compiler optimizations, which results in better performance and safety.
At ByteDance, to drive cost optimization, I developed from scratch multiple business-critical Rust SDKs, including service discovery, metrics, log, and dynamic configuration. I initiated and participated in the development of a Rust RPC framework, as well as provided compilation and runtime images, internal crates sources, and a public mirror (rsproxy.cn). Built on top of these infrastructural projects, several core services were migrated to Rust, achieving significant performance gains: a reduction of over 30% in CPU usage and a notable decrease in the P99 latency for some latency-sensitive services. However, many of these services are such that they do not require active maintenance—like proxy and caching services—and hence were easier to migrate. Services with more complex and actively iterative business logic proved more challenging to shift to Rust.
In theory, we could rewrite all Golang programs in Rust to achieve better performance, but in practice, this is met with considerable difficulties: First, rewriting all Golang dependencies may not be feasible; second, completing the rewrite all at once is difficult. If we could provide an efficient way of calling Golang from Rust, it would allow businesses to gradually make the switch to Rust, thereby addressing both issues.
This article covers a lot of ground. The overall narrative flow is as follows: first, I’ll discuss the overall solution selection and provide a minimal PoC; then, starting from this minimal PoC, I’ll expand and refine the solution to support the necessary features; finally, I’ll discuss some implementation details of interest from a framework implementation perspective.
I shared this topic at the 2024 RustChinaConf. If you are interested, feel free to check out the video replay or the PPT(video link, PPT link).
Please note these sharings are in Chinese. But if you have any question, feel free to reach me in any way(you can find my email and telegram in about page).