DEV Community

Cover image for Building Scalable Microservices with GoLang: Lessons from Real-World Implementations
Mukhil Padmanabhan
Mukhil Padmanabhan

Posted on

Building Scalable Microservices with GoLang: Lessons from Real-World Implementations

In today’s fast-paced tech landscape, the need to build scalable, maintainable applications has never been greater. Monolithic architectures were fine in the past but as we can see in many large scale applications ourselves, they soon become a bottleneck for performance, flexibility and development speed. This is why microservices architecture have become the industry best practice for scaling modern applications.

Through multiple projects we have used GoLang to architect and deploy high-performance microservices that will be handling loads of concurrent traffic. In this blog post, we will traverse through real-world use-cases where the core strengths of GoLang i.e concurrency, simplicity and performance – came really handy.

Now let’s get into some of the nitty-gritty things we’ve learned along the way and that you can use in your own work.

The Microservices Shift: Why GoLang Made Sense for Us

When we moved from a monolithic to microservices it was all about Scalability and Modularity, yes we were an ecommerce Platform, so we needed to scale our Payment Gateway or Order Management or User Authentication Service independently. When we did this first time, I evaluated lot of Languages/FW’s, but GoLang make the most sense to us for following reasons –

High-Concurrency API Handling

The existing platform had to handle tens of thousands of API requests per second during peak traffic and it wasn't but. Monolithic architecture resulted in bottlenecks, slow response times and high resource consumption.

I chose GoLang as:

  • Concurrency Model: We were able to spawn thousands of lightweight threads with Go’s goroutines, which processed API requests concurrently. These were highly memory-efficient compared to thread-based systems of the old world, and this gave us a lot of performance.
  • Low Latency: Being compiled we could serve requests with very low latency, as opposed to interpreted languages.
  • Portability: Golang compiles down to a single binary with no external dependencies which made it easier for us to deploy on our kubernetes cluster especially when scaling up for peak loads.

Our Journey from Monolith to Microservices

Breaking Down the Monolith

One of the biggest challenges we had, was how to break down our monolithic application into microservices. And for that, we have started with the most critical component - user authentication.

Why so? Because that’s the most high-traffic, mission-critical service in the platform. Thousands of users logging in every minute. Any downtime or latency in authentication, and we are dead.

Step 1: Rebuilding Authentication as a Microservice in GoLang

Our first challenge was to rebuild the authentication service using GoLang, where we would get a login request, read the credentials and provide JWT token for further API requests.

Image description

Key Insights:

  • We kept the authentication service stateless. This made it very easy for us to horizontally scale by spinning up new instances of the service when we had a higher traffic.
  • Goroutines are fantastic! We were able to process each request concurrently. We’re talking tens of thousands of requests per second effortless.

Step 2: Optimizing Database Connections

Shortly after launch we discovered that our PostgreSQL database couldn’t keep up with load during peak login times. We resolved this issue by adding connection pooling so that we could more efficiently manage and reuse connections to the database across multiple requests.

Image description

This reduced the strain on our database and allowed the microservice to scale alongside increasing user traffic.

Lessons Learned from Scaling with GoLang

Real-World Scaling Scenario: 1 Million Daily Logins

During one of the holiday shopping event our authentication service handled more than 1 million login requests per day. We were able to horizontally scale the traffic using GoLang’s goroutines and with few optimizations in database connection pool, we could easily horizontally scale our service to multiple instances.

Below are the few takeaways from this experience:

  • Statelessness is Critical: By keeping the microservice stateless we didn’t have to deal with session management issues and were able to scale it without any friction.
  • Horizontal Scaling with Kubernetes: We used Kubernetes spawn up additional instances of authentication service as traffic increases. GoLang’s small binary footprint made this super easy.
  • Graceful Shutdowns: One issue we faced was that few incoming requests were missing during deployments. We implemented graceful shutdowns so that ongoing requests would complete before service is brought down.

Image description

Best Practices for Building Scalable Microservices

Essentially, here are the key things we learned while doing that and what you can use as advice if you ever need to build scalable microservices with GoLang:

  • Stateless Services: Try to make them stateless and your services will be much easier horizontally scalable.
  • Decouple with Message Queues: To start off we decoupled interactions between services, for that we have used RabbitMQ and AWS SQS so that we can use request queue mechanism and failures won’t cascade.
  • Observability is Key: We used Prometheus for monitoring and Grafana to visualize the real time performance of the system. We also setup alarms to alert us when response times are beyond threshold values.
  • Graceful Shutdowns: As we increased instances and started doing rolling deployments, it became important to handle requests coming in while shutting down. Implementing graceful shutdown made sure users never saw any downtime during a deployment.

Conclusion: GoLang’s Superpower for Microservices

Throughout our journey of building and scaling microservices, GoLang was proven to be worthy again and again. It’s concurrency model, low memory footprint and ease of deployment, GoLang is the perfect language when it comes to scaling services such as user authentication for millions of requests without any loss of performance.

So if you’re just starting to break down your monolithic application or trying to get the best out of your microservices architecture, GoLang got you covered on both fronts.

Call to Action: Keen to build your own microservice with GoLang? Head over to our GitHub repository for the full authentication service example and have a go at building your own scalable microservice today!

Top comments (2)

Collapse
 
alejandrogih profile image
Alejandro Giraldo

Excellent , thanks for this

Collapse
 
mukhilpadmanabhan profile image
Mukhil Padmanabhan • Edited

@alejandrogih Glad you found it helpful!