Microservices
01 What is microservices architecture?
Solution and explanation
Solution:
Suppose a large job portal contains:
- User management
- Company management
- Job management
- Applications
- Interviews
- Notifications
- Payments
- Search
- Analytics
Instead of putting everything into one independently deployable service, business capabilities can be separated.
Example:
Identity Service Company Service Job Service Application Service Interview Service Notification Service Payment Service Analytics Service
Suppose 5 million users search jobs every day.
The Job Search functionality may need much more capacity than the interview service.
With independently deployable services, job search can be scaled separately.
However, microservices introduce additional problems:
- Network failures
- Distributed tracing
- Service discovery
- Data consistency
- Message delivery
- Deployment complexity
- Monitoring
- Authentication between services
Therefore microservices are not simply "many Spring Boot projects".
They require clear ownership and communication boundaries.
Client
|
API Gateway
|
+---- Identity Service
|
+---- Company Service
|
+---- Job Service
|
+---- Application Service
|
+---- Interview Service
|
+---- Notification Service
|
+---- Analytics Service
Define service boundaries for the job portal and identify which service owns application status.
Quick check
Which statement is correct?
02 What is an API Gateway?
Solution and explanation
Solution:
The API Gateway is normally the entry point between clients and backend services.
Instead of React directly calling:
user-service job-service application-service company-service
the frontend can call:
api.example.com
The gateway routes requests.
Example:
GET /api/jobs
v Job Service
POST /api/applications
v Application Service
GET /api/companies/100
v Company Service
The gateway can also participate in:
- Authentication integration
- Rate limiting
- Routing
- Request correlation
- Logging
- TLS termination
- Header forwarding
Business rules such as "whether candidate can apply to this job" should remain inside the Application Service.
The gateway should not become a giant business-logic service.
spring:
cloud:
gateway:
routes:
- id: job-service
uri: lb://JOB-SERVICE
predicates:
- Path=/api/jobs/**
- id: application-service
uri: lb://APPLICATION-SERVICE
predicates:
- Path=/api/applications/**
- id: company-service
uri: lb://COMPANY-SERVICE
predicates:
- Path=/api/companies/**
Route jobs, applications and company requests to separate Spring Boot services.
Quick check
Which statement is correct?
03 What is service discovery?
Solution and explanation
- Solution:
- Imagine Job Service has three running instances:
- job-service-1
- job-service-2
- job-service-3
- The IP address of each instance can change.
- A client should not permanently store:
- http://10.10.20.31:8080
- Instead, it can call:
- http://job-service/api/jobs
- The platform resolves the logical service name to available instances.
- In Kubernetes, Services and DNS commonly provide this capability.
- The important idea is:
- Client knows the service name.
- Infrastructure knows where healthy instances currently exist.
- When one instance fails, traffic can be sent to another healthy instance.
@RestController
@RequestMapping("/api/jobs")
public class JobController {
@GetMapping
public List<JobDto> jobs() {
return jobService.findJobs();
}
}
// Internal logical destination:
//
// http://job-service/api/jobs
Run three Job Service instances and route requests through the logical service name.
Quick check
Which statement is correct?
04 What is OpenFeign?
Solution and explanation
Solution:
Suppose Application Service needs company information.
Without Feign, developers repeatedly write HTTP client code.
With OpenFeign, the remote API can be represented as a Java interface.
Example:
Application Service:
GET /applications/100
needs:
GET /companies/50
The Feign client performs the HTTP call.
However, Feign does not remove network failure.
Production configuration still needs:
- Connect timeout
- Read timeout
- Error handling
- Retry policy where safe
- Circuit breaker where appropriate
- Authentication between services
@FeignClient(name = "company-service")
public interface CompanyClient {
@GetMapping("/api/companies/{id}")
CompanyDto findCompany(
@PathVariable("id") Long id
);
}
@Service
public class ApplicationService {
private final CompanyClient companyClient;
public ApplicationService(
CompanyClient companyClient
) {
this.companyClient = companyClient;
}
public CompanyDto getCompany(Long companyId) {
return companyClient.findCompany(companyId);
}
}
Create a Feign client from Application Service to Company Service and configure timeouts.
Quick check
Which statement is correct?
05 What is a circuit breaker?
Solution and explanation
- Solution:
- Suppose Application Service calls Company Service.
- Normally:
- Application Service
- |
- v
- Company Service
- |
- v
- Database
- Now Company Service becomes unavailable.
- If Application Service continues making thousands of requests:
- Request 1 -> timeout
- Request 2 -> timeout
- Request 3 -> timeout
- ...
- Request 100000 -> timeout
- Threads can become exhausted.
- This can cause failure to spread to other services.
- A circuit breaker changes this behavior.
- Closed:
- Requests are allowed.
- If failures exceed a threshold:
- Open:
- Requests fail fast without repeatedly calling the unhealthy service.
- After a waiting period:
- Half-open:
- A limited request is allowed to test recovery.
- If successful:
- Closed.
- If unsuccessful:
- Open again.
@CircuitBreaker(
name = "companyService",
fallbackMethod = "companyFallback"
)
public CompanyDto getCompany(Long id) {
return companyClient.findCompany(id);
}
public CompanyDto companyFallback(
Long id,
Throwable exception) {
return CompanyDto.unavailable(id);
}
Simulate Company Service timeouts and observe CLOSED -> OPEN -> HALF_OPEN -> CLOSED.
Quick check
Which statement is correct?
