In modern application architectures, microservices provide scalability, modularity, and ease of development. To manage communication between services and ensure security, an API Gateway is introduced as the single entry point for all client requests. Moreover, to protect backend services from overload and ensure fair usage, rate limiting is implemented.
This article discusses the system design of a microservices-based architecture using an API Gateway with rate limiting, implemented in Java, along with code examples.
Key Components of the System
- Client:
- This could be a web application, mobile application, or any service that consumes APIs.
- API Gateway:
- Acts as the single point of entry for all client requests.
- Handles tasks such as request routing, rate limiting, authentication, and response aggregation.
- Microservices:
- Independent services such as User Service, Order Service, and Payment Service. Each focuses on a specific functionality and has its own database.
- Rate Limiting:
- Protects the backend services by limiting the number of requests a client can make within a time window.
- Database:
- Each microservice has its own database to ensure data isolation and service independence.
- Monitoring and Logging:
- Provides insights into request patterns and system performance.
High-Level Architecture
+-------------------+
| Client |
| (Web/Mobile App) |
+--------+----------+
|
| HTTP/REST
v
+-------------------+
| API Gateway |
| - Rate Limiting |
| - Routing |
+--------+----------+
|
+------+-----+--------+
| | |
+v-----+ +--v----+ +--v----+
| User | | Order | |Payment|
|Service| |Service | |Service|
+-------+ +--------+ +-------+
Step-by-Step Implementation
Step 1: Setting Up the API Gateway
Use Spring Cloud Gateway as the API Gateway. It provides features like routing, rate limiting, and request/response filters.
Add dependencies in pom.xml
:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
Configure routes in application.yml
:
spring:
cloud:
gateway:
routes:
- id: user_service
uri: http://localhost:8081
predicates:
- Path=/users/**
- id: order_service
uri: http://localhost:8082
predicates:
- Path=/orders/**
Add rate limiting:
- Use Redis for managing tokens for rate-limiting logic.
- Add this to
application.yml
:
spring:
cloud:
gateway:
routes:
- id: user_service
uri: http://localhost:8081
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
predicates:
- Path=/users/**
Step 2: Microservices Development
Each microservice is an independent Spring Boot application.
Example: User Service
Add dependencies in pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Create a User Entity:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getters and Setters
}
Implement UserController:
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
Step 3: Integrate Redis for Rate Limiting
Add Redis dependency to pom.xml
in the API Gateway project:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Configure Redis in application.yml
:
spring:
redis:
host: localhost
port: 6379
Enable rate limiting:
- Spring Cloud Gateway uses
KeyResolver
to identify the client (e.g., by IP or user ID).
Example of a KeyResolver
:
@Component
public class UserKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
Register the KeyResolver
in application.yml
:
spring:
cloud:
gateway:
redis-rate-limiter:
enabled: true
default-filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
Testing the System
Start Redis: Make sure Redis is running on your local machine or server:
redis-server
Run Microservices: Start the API Gateway and individual microservices (User Service, Order Service).
Send Requests: Use a tool like Postman to test the system:
- Send a request to the API Gateway, e.g.,
http://localhost:8080/users
. - If you exceed the rate limit, you’ll receive an HTTP
429 Too Many Requests
response.
Key Benefits of This Design
- Scalability: Each microservice can scale independently based on demand.
- Enhanced Security: The API Gateway ensures secure and controlled access to microservices.
- Fair Usage: Rate limiting prevents abuse by limiting the number of requests from a single client.
- Centralized Management: API Gateway serves as a single entry point for logging, monitoring, and enforcing policies.
Conclusion
By designing a system using microservices, an API Gateway, and rate limiting, you create a scalable, secure, and robust architecture. This approach ensures fair usage and protects backend services from potential overload. With Spring Boot and Spring Cloud Gateway, implementing this system is straightforward and flexible.