Node.js is Good; Go is Better

Roger Chapman
SafetyCulture Engineering
2 min readJan 15, 2020

SafetyCulture has a microservice architecture deployed on Kubernetes (AWS EKS). When we started this architecture all our services were written, predominantly, in Node.js.

In the early days of our product, Node.js was great; it allowed teams to build services quickly and share a lot of common libraries. Data structures were stored as JSON, and Frontend/Backend development could all be done in a common language: JavaScript.

As time passed, our codebase grew, as well as our Engineering team. Cracks started to appear under the fast-paced growth of the company, product and our microservices. Schema-less JSON in a document store, once our friend, became hard to reason with; and flavours of JavaScript (CoffeeScript, ES5, ES6/7, TypeScript) added a lot of technical debt.

By no means a silver bullet, we decided to try Go, along with other technologies (Postgres, Protocol Buffers and gRPC). You can read more about this decision on: Why Go is a good language for microservices.

Refactor

Comparing a Node.js service to a Go service can be subjective, as no two distinct services have the same API, SLAs, network traffic, workload etc… unless it’s exactly the same service.

To improve the maintainability of one of our services; we decided to refactor the service from Node.js to Go. The API would have a new gRPC endpoint (for newer clients) but would still expose the existing HTTP/JSON API for backward compatibility.

NodeJS refactored to Go

Deploying the new Go service showed instant results in performance: the Grafana graph shows the metrics for the existing HTTP/JSON API; the gRPC endpoint may see a further improvement as it will remove the need to marshal/unmarashal the JSON (no data yet on this, but the JSON API calls the internal gRPC API).

Latency was reduced from 10ms (still really good) to 3ms (this service gets called multiple times per user request so every millisecond counts). CPU usage was cut in half (actually more) and Memory usage was reduced from 180MB to 40MB (per pod).

This refactor has improved the user experience (latency) and enabled the service to scale farther than before.

What’s your experience? Have you seen a performance change by migrating any of your services to Go?

--

--

Roger Chapman
SafetyCulture Engineering

Software Engineer helping teams build scalable microservices in Go and gRPC