Understanding the microservices architecture and data flow in Argos Mesh
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.
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:
Increment counter: Each sale event increments rate:ip:{ip} in Redis
Set TTL: First request sets a 10-second TTL on the key
Check threshold: If count exceeds 50, the IP is banned
Ban duration: Banned IPs are stored as blacklist:ip:{ip} with a 10-minute TTL
RedisService.java
@Servicepublic 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:
The Sentinel service defines all exchanges, queues, and bindings:
RabbitMQConfig.java
@Configurationpublic 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) {}