- Java Microservices Tutorial
- Java Microservices - Home
- Microservices - Introduction
- Microservices vs Monolith vs SOA
- Java Microservices - Environment Setup
- Java Microservices - Advantages of Spring Boot
- Java Microservices - Design Patterns
- Java Microservices - Domain Driven Design
- Java Microservices - Decomposition by Business Capability
- Java Microservices - Decomposition by Subdomain
- Java Microservices - Backend for Frontend
- Java Microservices - The Strangler Pattern
- Java Microservices - Synchronous Communication
- Java Microservices - Asynchronous Communication
- Java Microservices - Saga Pattern
- Java Microservices - Centralized Logging (ELK Stack)
- Java Microservices - Event Sourcing
- Java Microservices - CQRS Pattern
- Java Microservices - Sidecar Pattern
- Java Microservices - Service Mesh Pattern
- Java Microservices - Circuit Breaker Pattern
- Java Microservices - Distributed Tracing
- Java Microservices - Control Loop Pattern
- Java Microservices - Database Per Service
- Java Microservices - Bulkhead Pattern
- Java Microservices - Health Check API
- Java Microservices - Retry Pattern
- Java Microservices - Fallback Pattern
- Java Microservices Useful Resources
- Java Microservices Quick Guide
- Java Microservices Useful Resources
- Java Microservices Discussion
Java Microservices - Synchronous Communication (REST/gRPC)
Introduction
Microservices architecture involves breaking down applications into independently deployable, loosely coupled services. For these services to work cohesively, they must communicate with each other-either synchronously or asynchronously.
This article focuses on the Synchronous Communication pattern, where services interact in real time, expecting immediate responses. The two most widely used technologies for synchronous communication are −
REST (Representational State Transfer)
gRPC (Google Remote Procedure Call)
We will explore both in detail-understanding their use cases, trade-offs, implementation techniques, and how they compare.
What Is Synchronous Communication?
Definition
Synchronous communication in microservices refers to a communication pattern where one service sends a request to another and waits for a response before proceeding.
This is akin to traditional function calls: Service A calls Service B, and waits for the result to continue its execution.
Characteristics of Synchronous Communication
| Sr.No. | Feature | Description |
|---|---|---|
| 1 | Real-time interaction | The client waits until the response is received |
| 2 | Simple error handling | Built-in status codes, retries, and fallbacks |
| 3 | Tightly coupled timing | Both services must be available during communication |
| 4 | Serialization | Data is serialized into formats like JSON (REST) or Protobuf (gRPC) |
Why Use Synchronous Communication?
Ideal for −
Real-time data requirements (e.g., payments, user authentication)
CRUD operations (e.g., read user profile)
Predictable and consistent APIs
Not Ideal for −
High-volume or event-driven scenarios
Long-running processes
Systems requiring decoupling and fault tolerance
Technology Options
| Sr.No. | Protocol | Description | Common Usage |
|---|---|---|---|
| 1 | REST | HTTP-based API using JSON/XML | Web, mobile, HTTP clients |
| 2 | gRPC | Binary protocol over HTTP/2 using Protobuf | Internal microservices, low-latency systems |
Architecture Overview
Service A makes a synchronous request to Service B
Service B processes and responds instantly
If B fails, A must retry or handle the failure
REST-Based Synchronous Communication with Spring Boot
Project Setup
Dependencies (Maven)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> <!-- Optional for async REST --> </dependency>
Service B: Profile Service
@RestController
@RequestMapping("/profiles")
public class ProfileController {
@GetMapping("/{id}")
public Profile getProfile(@PathVariable String id) {
return new Profile(id, "Alice", "alice@example.com");
}
}
Service A: User Service (REST Client)
@Service
public class ProfileClient {
@Autowired
private RestTemplate restTemplate;
public Profile getProfile(String userId) {
return restTemplate.getForObject("http://profile-service/profiles/" + userId, Profile.class);
}
}
Enable LoadBalanced RestTemplate
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
Configuration (application.yml)
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
gRPC-Based Synchronous Communication in Spring Boot
Why gRPC?
Feature REST gRPC Format JSON / XML Protocol Buffers (binary) Performance Moderate Very high Streaming Limited Full-duplex supported Language Support Wide Also wide HTTP Version HTTP/1.1 HTTP/2gRPC is ideal for internal service communication requiring low latency.
Setup: Add gRPC Dependencies
Use yidongnan's Spring Boot starter for gRPC −
Maven
<dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> <version>2.14.0.RELEASE</version> </dependency> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-client-spring-boot-starter</artifactId> <version>2.14.0.RELEASE</version> </dependency>
Define Proto File
profile.proto
syntax = "proto3";
package profile;
service ProfileService {
rpc GetProfile (ProfileRequest) returns (ProfileResponse);
}
message ProfileRequest {
string userId = 1;
}
message ProfileResponse {
string userId = 1;
string name = 2;
string email = 3;
}
Compile with the Protobuf plugin to generate Java classes.
Implement the gRPC Server
@GrpcService
public class ProfileServiceImpl extends ProfileServiceGrpc.ProfileServiceImplBase {
@Override
public void getProfile(ProfileRequest request, StreamObserver<ProfileResponse> responseObserver) {
ProileResponse response = ProfileResponse.newBuilder()
.setUserId(request.getUserId())
.setName("Alice")
.setEmail("alice@example.com")
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
gRPC Client
@Service
public class ProfileGrpcClient {
@GrpcClient("profile-service")
private ProfileServiceGrpc.ProfileServiceBlockingStub stub;
public ProfileResponse getProfile(String userId) {
return stub.getProfile(ProfileRequest.newBuilder().setUserId(userId).build());
}
}
Synchronous Communication Best Practices
| Sr.No. | Practice | Description |
|---|---|---|
| 1 | Circuit Breakers | Use Resilience4j or Hystrix to avoid cascading failures |
| 2 | Timeouts | Set request timeouts to avoid hanging requests |
| 3 | Retries | Automatically retry transient failures |
| 4 | Load Balancing | Use Ribbon, Eureka, or Kubernetes for distributing traffic |
| 5 | Monitoring & Tracing | Use Sleuth, Zipkin, Prometheus for observability |
| 6 | Fallback Mechanisms | Provide alternative responses if a service fails |
Pros and Cons of Synchronous Communication
| Sr.No. | Pros | Cons |
|---|---|---|
| 1 | Simpler to implement and debug | Coupling in availability |
| 2 | Easier data consistency | Not suitable for large-scale, event-driven systems |
| 3 | Familiar request/response model | Latency increases with each network hop |
| 4 | Ideal for chained workflows | Prone to cascading failures |
Use Cases Comparison: REST vs. gRPC
| Sr.No. | Use Case | Recommended Approach |
|---|---|---|
| 1 | Internal microservice communication | gRPC (performance critical) |
| 2 | Mobile/Web communication | REST (browser/client friendly) |
| 3 | Streaming large datasets | gRPC with streaming |
| 4 | Public APIs | REST (easy integration) |
Real-World Example: Netflix
Netflix uses gRPC extensively for internal communications between services like recommendation engines and playback servers, due to its high performance and contract-first development.
However, for public APIs, Netflix still uses REST with GraphQL for client flexibility.
When to Use Synchronous Communication
Use When
Real-time responses are required
Workflow depends on sequential execution
Systems are under control in terms of scale
Avoid When
Services are frequently unavailable
High-volume traffic or long processing is involved
Decoupling and resilience are key priorities
Conclusion
Synchronous communication is a core pattern in microservices that enables real-time, request-response interaction between services. With REST and gRPC as the leading technologies, you can choose based on −
Performance needs (gRPC)
Interoperability (REST)
Use case complexity
For mission-critical, performance-sensitive applications, gRPC is highly effective. For client-facing and public APIs, REST remains the default choice.
Design your system based on communication patterns that align with business and technical requirements.