Facebook's Parse team tells a great API success story in a recent blog post titled "How We Moved Our API From Ruby to Go and Saved Our Sanity." Parse started developing in Ruby on Rails, then hit scaling issues and switched to Google's Go — selecting the language over C#, Java, C++ and JRuby.
Parse enables mobile app developers to instantly add push notifications, data storage, social integration and more with SDKs that make API calls to Parse-hosted backend app infrastructure.
Parse built a successful API-based company but then had to rewrite its API server codebase in another language as it started to scale. Parse did indeed scale with the new code and was sold to Facebook. Facebook operates the Parse service at Web scale using Go today.
Parse's Early Development and Scaling Issues
Parse initially used Ruby on Rails as its main development language (Ruby) and Web framework (Rails). Rails helped Parse's small development team build lots of functionality and iterate quickly. Parse acknowledges that Ruby on Rails' huge community offered great support, its Gem packages enabled countless features to be added easily and its code libraries were solid.
Parse's service quickly grew to 60,000 mobile apps making 3,000 request per second. However, even at this early level of API usage, Parse saw that Rails created performance issues that would be unsustainable if the service experienced the "hockey stick" growth it was anticipating.
Parse's problem was that Ruby on Rails is synchronous by design. This meant that requests to the Parse API were handled one at a time, with the server waiting for the entire request to finish before freeing up new resources for a new request. This is OK for a basic HTTP response; however, any time the request had to wait for another component service, the whole API server got tied up very quickly. Also, Parse's DevOps team began to have more and more problems quickly rolling out new API server code bases, as the application became more complex.
These Rails performance issues meant that keeping the API up and stable required a lot of work by humans. Members of the ops team got regular pages that alerted them to come manually fix things and add more servers. Rails scaling issues happened more quickly than their cloud service's autoscaling could handle. So they had to figure it out themselves and spin up database and API servers manually to keep things stable. Also, DevOps had to carefully set up load balancing and fallback strategies every time it tried to deploy new code to its API servers, which run on Unicorn HTTP servers.
Parse anticipated massive scaling, based on the early popularity of its service. It decided it should rewrite its API server code in a new language that would both scale by design and require less human intervention. Parse knew it needed a development language that is asynchronous by design. It needed a language that would make it easy for large development teams to collaborate and write complex, multithreaded code bases.
Parse chose the Go programming language to solve its API scaling issues.
From Go's Wikipedia page:
Go, also commonly referred to as golang, is a programming language developed at Google in 2007 by Robert Griesemer, Rob Pike, and Ken Thompson. It is a statically-typed language with syntax loosely derived from that of C, adding garbage collection, type safety, some dynamic-typing capabilities, additional built-in types such as variable-length arrays and key-value maps, and a large standard library.
Selecting Go Over C#, Java, JRuby and C++
Parse carefully considered other programming languages when selecting Go. In fact, various components of its service were written in some of these languages, including Go (though most of its main code base was Ruby on Rails).
EventMachine and JRuby
The first technologies the team considered were EventMachine and JRuby. Both are Ruby-based and perhaps easier for a team to move to from a Ruby on Rails code base. However, EventMachine was already experiencing some scaling issues where it was used in Parse's push notification service. JRuby, a Java version of Ruby, offered multithreaded Java features, but the team didn't want to write in Java or deploy using the Java virtual machine. Finally, both EventMachine and JRuby had the same problem: They often had Ruby library dependencies that called on synchronous code — the very problem Parse was trying to avoid.
Java and C++
Java and C++ were also considered. Both languages are multithreaded and asynchronous by design. But the team did not want to work in either language. They are not Web-centric and do not offer many of the newer features of modern programming languages.
Microsoft's C# was the closest contender to Go. C# is asynchronous by design, offering low-level language features that make asynchronous coding easy. However, Microsoft technologies treat Linux as a second-class citizen. Given the number of open source technologies that Parse uses, Linux is its operating system of choice.
Struggling to use C# on Linux did not seem like a viable option.
Go Is Selected
Go had the best MongoDB driver of any language. MongoDB is core to Parse's infrastructure. MongoDB may have been the biggest reason for picking Go, but there was one more: The team loved writing in Go, and Parse believed it could attract more talented developers if it wrote in Go, as opposed to C#, Java or C++.
How Parse Implemented the API Rewrite
Parse initially rewrote its EventMachine-based push service in Go. The resulting Go performance benchmarks were great, and the team loved writing in Go. Parse then moved on to rewriting minor services in Go and writing new services in Go. This went well also. Finally, Parse rewrote its core API server in Go, endpoint by endpoint.
During the rewrite, Parse experienced a 10x lift in the number of app clients, requests and storage systems. It seems it switched just in time.
In Defense of Ruby on Rails
Parse exposes a REST API, and Rails does provide robust HTTP processing. Developers can send some strange, non-RFC-compliant API requests — and the Rails middleware code will accept and handle them. Rewriting in Go after using Rails required the team to figure out what Rails magically cleaned up behind the scenes, then writing new code to handle these special use cases.
Results of the API Rewrite
The blog post summarizes the experience by stating the following:
Was the rewrite worth it? Hell yes it was. Our reliability improved by an order of magnitude. More importantly, our API is not getting more and more fragile as we spin up more databases and backing services. Our codebase got cleaned up and we got rid of a ton of magical gems and implicit assumptions. Co-tenancy issues improved for customers across the board. Our ops team stopped getting massively burned out from getting paged and trying to track down and manually remediate Ruby API outages multiple times a week. And needless to say, our customers were happier too.
We now almost never have reliability-impacting events that can be tracked back to the API layer — a massive shift from a year ago.
Please read the full blog post by Charity Majors of the Parse engineering team. It is well-written, telling a great API success story using in-depth technical details.