LogoTRUONG PHAM
Home
Projects
Blogs
YouTube
Contact

Newsletter

Stay updated with technical artifacts and engineering insights.

LogoTRUONG PHAM

Building scalable software and sharing insights on technology & life.

Sitemap

  • Home
  • Projects
  • Blogs
  • YouTube
  • Contact

Connect

  • GitHub
  • LinkedIn
  • Email
  • YouTube

© 2024 TRUONG PHAM. © All rights reserved.

Privacy PolicyTerms of Service
Back
REST, gRPC, or NATS? Don't Let Choice Bury Progress
Microservice Journey: Lessons & Trade-offs

REST, gRPC, or NATS? Don't Let Choice Bury Progress

When services need to talk to each other, we start debating between synchronous and asynchronous. What's the practical choice for a small team?

TP
Truong PhamSoftware Engineer
PublishedMarch 21, 2024
Stack
microservice ·communication ·backend

Inter-service communication is the backbone of microservices. But for a team of 2-3 people, choosing the wrong protocol can cost you weeks just... debugging connections instead of writing logic.


The Trap of "Technical Perfection"

When reading blog posts about microservice architecture, you'll see people praising gRPC for its speed, or Message Queues to ensure asynchronicity and scalability. I was the same. I started the project thinking: "If I'm doing microservices, I have to do it right!".

But reality gave me a sharp wake-up call.

1. REST: The Reliable "Old Friend"

We started with REST (HTTP/JSON). Pros: Extremely easy to debug. You just need curl or Postman to know exactly what the service is returning. Browsers support it extensively. Cons: More resource-intensive (JSON is quite heavy), lacks strict schemas, and most importantly: Cascading Failure. If Service A calls B, B calls C, and C is slow—A will hang too.

Trade-off: Accept slightly higher latency in exchange for ease of development and debugging. With initial traffic not being too large, REST is more than enough.

2. gRPC: Fast but "High Maintenance"

Next, I tried introducing gRPC into a few services that needed high performance. Problem: Having to manage .proto files. Every time an interface changes, you have to generate code and sync between services. Debugging is incredibly exhausting—you can't easily see binary data with your eyes like you can with JSON.

Lesson: Don't use gRPC just because it's "cool." Only use gRPC when you truly need extremely high performance and the team is already very familiar with managing shared schemas.

3. Message Queue (NATS/RabbitMQ): Asynchronous Salvation

This was the turning point. Instead of Service A calling B directly, A fires an "event" into NATS and forgets about it. B will pick it up and process it when it's free.

Why did it save us?

  • Decoupling: A doesn't need to know if B is alive.
  • Smoothing: When traffic spikes, NATS acts as a "buffer," holding tasks for services to process gradually, instead of crashing the whole system due to overload.

The Price Paid: The system becomes "event-driven," meaning you no longer know the result immediately (Eventual Consistency). Tracking a data flow (Tracing) becomes exponentially more difficult.


Advice for Small Teams

If I were to start over:

  1. Default to REST: For 80% of workflows. The ease of debugging is invaluable when you are racing against a deadline.
  2. Use Message Queue for background tasks: Sending emails, processing images, push notifications... things that don't need an immediate response to the user.
  3. Forget about gRPC (at least initially): A small team doesn't have enough resources to manage the complexity of gRPC interfaces between constantly changing services.

Remember: Your goal is to ship features, not to build a "Google-standard" system that never gets finished.


Lessons Learned

Internal communication isn't just about transmitting data; it's about managing expectations. Do you expect an immediate result (Sync) or do you just need to know it will be processed (Async)? Choosing the wrong protocol is choosing the wrong way to operate the entire system.

Series • Part 4 of 20

Microservice Journey: Lessons & Trade-offs

NextDistributed Transactions - Why 'Immediate Consistency' is a Luxury
Monorepo or Microservice? Lessons from a 2-Person Team
01Trade-offs Under Pressure02Microservices is Not Just About Splitting Services03Monorepo or Microservice? Lessons from a 2-Person Team04REST, gRPC, or NATS? Don't Let Choice Bury ProgressReading05Distributed Transactions - Why 'Immediate Consistency' is a Luxury06Authentication & Authorization - When API Gateway Carries the Team07Docker Compose is Not Enough - The Local Development Story08Database Separation - A Painful but Necessary 'Divorce'09BFF (Backend for Frontend) - The Savior of UX
TP

Written by Truong Pham

Software Engineer passionate about building high-performance systems and meaningful experiences.

Read more articles