Skip to main content
Argos Mesh is built on a modern microservices architecture designed to detect and prevent DDoS attacks in real-time. The system leverages event-driven patterns, distributed caching, and Java 21’s Virtual Threads for high-performance traffic analysis.

System Overview

Argos Mesh consists of three core microservices and three supporting infrastructure components:

Orders Service

E-commerce API with product management and sales endpoints

Sentinel Service

Real-time traffic analyzer and DDoS detection engine

Notify Service

Alert notification worker for security events

PostgreSQL

Persistent storage for product catalog

RabbitMQ

Message broker for event-driven communication

Redis

In-memory cache for IP blacklist and rate limiting

Architecture Diagram

Data Flow

Understanding how data flows through Argos Mesh is crucial for grasping its DDoS prevention capabilities.

Normal Traffic Flow

When a legitimate user makes a purchase, the system follows this flow:
1

Client Request

User sends a POST request to /orders/products/{id}/sell with the quantity to purchase.
POST /orders/products/1/sell HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{
  "quantity": 1
}
2

IP Extraction

The Orders service extracts the client’s IP address from the HTTP request:
ProductController.java
@PostMapping("/{id}/sell")
public ResponseEntity<Void> sellProduct(
        @PathVariable Long id,
        @RequestBody BuyRequest buyRequest,
        HttpServletRequest request) {
    String clientIp = request.getRemoteAddr();
    productService.sellProduct(id, clientIp, buyRequest.quantity());
    return ResponseEntity.accepted().build();
}
3

Stock Update

The service updates the product stock in PostgreSQL and publishes a sale event to RabbitMQ with the client’s IP address.
4

Event Consumption

The Sentinel service consumes the ProductSoldInternalEvent from the argos.sales.queue:
SalesListener.java
@RabbitListener(queues = "argos.sales.queue")
public void processSalesEvents(ProductSoldInternalEvent data) {
    String ip = data.ipAddress();
    
    if (redisService.isBanned(ip)) {
        return; // Ignore events from banned IPs
    }
    
    if (analyzer.processAndCheckLimit(ip)) {
        // Suspicious activity detected
        AlertInternalEvent event = new AlertInternalEvent(
            "Suspicious behavior", 
            ip, 
            "CRITICAL", 
            LocalDateTime.now()
        );
        rabbitTemplate.convertAndSend(
            RabbitMQConfig.ALERT_EXCHANGE,
            "argos.alert.security",
            event
        );
    } else {
        System.out.println("[ Sentinel🛡️ ] Normal traffic of the IP: " + ip);
    }
}
5

Rate Limit Check

The TrafficAnalyzer checks if the IP has exceeded the rate limit (50 requests per 10 seconds):
TrafficAnalyzer.java
public boolean processAndCheckLimit(String ip) {
    if (redisService.isBanned(ip)) return true;
    
    String key = "rate:ip:" + ip;
    Long currentCount = redisTemplate.opsForValue().increment(key);
    
    if (currentCount != null && currentCount == 1) {
        redisTemplate.expire(key, Duration.ofSeconds(10));
    }
    
    if (currentCount != null && currentCount > 50) {
        redisService.banIp(ip, 10); // Ban for 10 minutes
        return true;
    }
    
    return false;
}

Attack Detection Flow

When a DDoS attack is detected, the system responds immediately:

Component Deep Dive

Orders Service

The Orders service is the public-facing API that handles all product operations. Technology Stack:
  • Spring Boot 4.0.3
  • Java 21
  • Spring Data JPA
  • PostgreSQL Driver
  • Spring AMQP (RabbitMQ)
  • Spring Data Redis
  • MapStruct for DTO mapping
Key Components:
@RestController
@RequestMapping("/orders/products")
public class ProductController {
    private final IProductService productService;
    
    @PostMapping("/{id}/sell")
    public ResponseEntity<Void> sellProduct(
            @PathVariable Long id,
            @RequestBody BuyRequest buyRequest,
            HttpServletRequest request) {
        String clientIp = request.getRemoteAddr();
        productService.sellProduct(id, clientIp, buyRequest.quantity());
        return ResponseEntity.accepted().build();
    }
}
Environment Configuration:
application.properties
spring.application.name=argos-orders

# PostgreSQL
spring.datasource.url=jdbc:postgresql://db:5432/shop_db
spring.datasource.username=user_shop
spring.datasource.password=secretPassword
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update

# RabbitMQ
spring.rabbitmq.host=message_broker
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin123
spring.rabbitmq.listener.simple.prefetch=1

Sentinel Service

The Sentinel is the heart of Argos Mesh’s DDoS prevention system. It uses Java 21’s Virtual Threads for efficient concurrent processing of high-traffic events. Technology Stack:
  • Spring Boot 4.0.3
  • Java 21 with Virtual Threads enabled
  • Spring Data Redis
  • Spring AMQP (RabbitMQ)
  • Jackson for JSON serialization
Key Features:
  • Real-time rate limiting using Redis counters
  • Sliding window algorithm (50 requests per 10 seconds)
  • Automatic IP blacklisting for 10 minutes
  • Event-driven alert publishing
Rate Limiting Algorithm: The Sentinel uses a simple but effective sliding window counter stored in Redis:
  1. Increment counter: Each sale event increments rate:ip:{ip} in Redis
  2. Set TTL: First request sets a 10-second TTL on the key
  3. Check threshold: If count exceeds 50, the IP is banned
  4. Ban duration: Banned IPs are stored as blacklist:ip:{ip} with a 10-minute TTL
RedisService.java
@Service
public class RedisService {
    private final StringRedisTemplate redisTemplate;
    private static final String BLACKLIST_PREFIX = "blacklist:ip:";
    
    public void banIp(String ipAddress, long durationMinutes) {
        redisTemplate.opsForValue().set(
            BLACKLIST_PREFIX + ipAddress,
            "BANNED",
            Duration.ofMinutes(durationMinutes)
        );
    }
    
    public boolean isBanned(String ipAddress) {
        return Boolean.TRUE.equals(
            redisTemplate.hasKey(BLACKLIST_PREFIX + ipAddress)
        ); 
    }
}
Virtual Threads Configuration: Virtual Threads are enabled via environment variable in docker-compose.yml:
docker-compose.yml
sentinel:
  environment:
    - SPRING_THREADS_VIRTUAL_ENABLED=true
This allows the Sentinel to handle thousands of concurrent event processing tasks with minimal overhead.

Notify Service

The Notify service is a worker that consumes security alerts and sends notifications to system administrators. Technology Stack:
  • Spring Boot 4.0.3
  • Java 21
  • Spring AMQP (RabbitMQ)
Alert Processing:
AlertNotifier.java
@Service
public class AlertNotifier {
    
    @RabbitListener(queues = "argos.alert.queue")
    public void sendNotification(AlertInternalEvent alert) {
        System.out.println("[ Alert ] - " + alert.timeStamp());
        System.out.println("The IP: " + alert.sourceIp());
        System.out.println("Is suspicious of try an: " + alert.type());
        System.out.println("This is: " + alert.severity());
    }
}
In production, this service would integrate with email, SMS, or incident management systems like PagerDuty or Opsgenie.

Message Broker Configuration

RabbitMQ acts as the central nervous system of Argos Mesh, coordinating communication between microservices.

Exchange and Queue Topology

RabbitMQ Configuration

The Sentinel service defines all exchanges, queues, and bindings:
RabbitMQConfig.java
@Configuration
public class RabbitMQConfig {
    public static final String QUEUE_ALERT = "argos.alert.queue";
    public static final String ALERT_EXCHANGE = "alert.exchange";
    public static final String RK_ALERT = "argos.alert.#";
    
    public static final String QUEUE_SALE = "argos.sales.queue";    
    public static final String EXCHANGE_SOLD = "shop.exchange";
    public static final String RK_SALES = "shop.event.sold";
    
    @Bean
    public Queue alertQueue() {
        return new Queue(QUEUE_ALERT, true);
    }
    
    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(ALERT_EXCHANGE);
    }
    
    @Bean
    public Binding binding(Queue alertQueue, TopicExchange exchange) {
        return BindingBuilder.bind(alertQueue).to(exchange).with(RK_ALERT);
    }
    
    @Bean
    public MessageConverter jsonMessageConverter(ObjectMapper objectMapper) {
        return new Jackson2JsonMessageConverter(objectMapper);
    }
}
Message Format:
public record ProductSoldInternalEvent(
    Long productId,
    String ipAddress,
    Integer quantity,
    LocalDateTime soldAt
) {}

Redis Data Model

Redis serves two critical functions in Argos Mesh:

1. Rate Limiting Counters

Ephemeral counters with automatic expiration:
Key: rate:ip:192.168.1.100
Value: 45
TTL: 7 seconds

2. IP Blacklist

Banned IPs with TTL-based automatic unbanning:
Key: blacklist:ip:192.168.1.100
Value: BANNED
TTL: 600 seconds (10 minutes)

Redis Operations

redis-cli INCR rate:ip:192.168.1.100
# Returns: 1

redis-cli EXPIRE rate:ip:192.168.1.100 10
# TTL set to 10 seconds

Multi-Stage Docker Builds

All three microservices use multi-stage Docker builds for optimized image sizes:
Dockerfile
# Stage 1: Build
FROM maven:3.9.6-eclipse-temurin-21-alpine AS build
WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline

COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: Runtime
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

COPY --from=build /app/target/*.jar app.jar

EXPOSE 8080

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

ENTRYPOINT ["java", "-jar", "app.jar"]
Benefits:
  • Smaller runtime images (JRE only, no Maven or build tools)
  • Faster deployments
  • Improved security (non-root user)
  • Build cache optimization

Scalability Considerations

Argos Mesh is designed to scale horizontally:

Stateless Services

All three microservices are stateless, allowing multiple instances to run behind a load balancer:
docker-compose.yml
sentinel:
  deploy:
    replicas: 3

Redis as Shared State

Redis provides a centralized state store for:
  • Rate limiting counters (shared across Sentinel instances)
  • IP blacklist (accessible by all Orders instances)

RabbitMQ Queue Consumers

Multiple Sentinel instances can consume from the same queue with automatic load balancing:
spring.rabbitmq.listener.simple.prefetch=1
This ensures fair distribution of events across consumer instances.

Security Features

IP Blacklisting

Automatic 10-minute ban for IPs exceeding rate limits

Rate Limiting

50 requests per 10-second sliding window

Non-Root Containers

All services run as non-root users

Health Checks

Automatic container restart on failure

Performance Optimizations

Java 21 Virtual Threads

The Sentinel service leverages Virtual Threads for efficient concurrent processing:
  • Traditional Threads: 1 OS thread per request (expensive, limited scalability)
  • Virtual Threads: Millions of lightweight threads (cheap, massive scalability)
This allows Sentinel to process thousands of concurrent events without thread pool exhaustion.

Redis In-Memory Storage

Using Redis for rate limiting provides:
  • Sub-millisecond read/write operations
  • Automatic TTL-based cleanup
  • Atomic increment operations

Event-Driven Architecture

Asynchronous message processing decouples services:
  • Orders service doesn’t wait for Sentinel processing
  • Non-blocking I/O for better throughput
  • Natural backpressure via message queues

Monitoring and Observability

RabbitMQ Management UI

Access real-time metrics at http://localhost:15672:
  • Message rates
  • Queue depths
  • Consumer connections
  • Exchange bindings

Container Logs

View service logs in real-time:
docker logs -f sentinel_app
docker logs -f shop_app
docker logs -f notify_app

Redis Monitoring

Monitor Redis operations:
docker exec black_list redis-cli MONITOR

Next Steps

API Reference

Explore the REST API endpoints

Configuration

Customize detection thresholds

Deployment

Deploy to production

Security

Learn about DDoS protection

Build docs developers (and LLMs) love