Skip to main content

Overview

Argos Mesh uses Redis as an in-memory data store for high-performance rate limiting and IP blacklisting. The Sentinel service leverages Redis to track request patterns and block malicious IPs in real-time.

Connection Configuration

Basic Connection Settings

spring.data.redis.host
string
required
Redis server hostnameDefault: redis_db (Docker service name)Production: Use FQDN or IP address of Redis cluster
spring.data.redis.port
number
required
Redis server portDefault: 6379
spring.data.redis.password
string
Redis authentication password (optional)Default: Not set in development
Always use authentication in production environments!

Application Properties Example

spring.data.redis.host=redis_db
spring.data.redis.port=6379

Docker Configuration

Redis runs as a Docker container with persistence enabled:
docker-compose.yml
redis_db:
  image: redis:7.2-alpine
  container_name: black_list
  restart: always
  ports:
    - "6379:6379"
  command: ["redis-server", "--appendonly", "yes"]
  volumes:
    - redis_data:/data
  healthcheck:
    test: ["CMD", "redis-cli", "ping"]
    interval: 5s
    timeout: 3s
    retries: 5
  networks:
    - argos-network

volumes:
  redis_data:
Append-Only File (AOF): The --appendonly yes flag enables persistence. Redis logs every write operation, allowing data recovery after restart.

Rate Limiting Implementation

The Sentinel service implements a sliding window rate limiter using Redis counters.

Rate Limiter Configuration

LIMIT
number
Maximum requests allowed per time windowDefault: 50Location: TrafficAnalyzer.java:13
Adjust this value based on your expected traffic patterns and capacity.
WINDOW_SECONDS
number
Time window for rate limiting (in seconds)Default: 10Location: TrafficAnalyzer.java:14
RATE_PREFIX
string
Redis key prefix for rate limit countersDefault: rate:ip:Key Pattern: rate:ip:{ip_address}Example: rate:ip:192.168.1.100

Rate Limiting Algorithm

The system tracks requests per IP address using Redis INCREMENT operations:
TrafficAnalyzer.java
@Component
public class TrafficAnalyzer {

    private final RedisService redisService;
    private final StringRedisTemplate redisTemplate;

    private static final int LIMIT = 50; 
    private static final int WINDOW_SECONDS = 10;
    private static final String RATE_PREFIX = "rate:ip:";

    public boolean processAndCheckLimit(String ip) {
        // Check if IP is already banned
        if (redisService.isBanned(ip)) return true;

        String key = RATE_PREFIX + ip;
        
        // Increment counter for this IP
        Long currentCount = redisTemplate.opsForValue().increment(key);

        // Set TTL on first request
        if (currentCount != null && currentCount == 1) {
            redisTemplate.expire(key, Duration.ofSeconds(WINDOW_SECONDS));
        }

        // Ban IP if limit exceeded
        if (currentCount != null && currentCount > LIMIT) {
            redisService.banIp(ip, 10);
            return true;
        }

        return false;
    }
}

How It Works

1

First Request

When an IP makes its first request, Redis creates a counter key (rate:ip:192.168.1.100) and sets it to 1 with a 10-second TTL.
2

Subsequent Requests

Each additional request increments the counter. The TTL remains unchanged (sliding window).
3

Limit Exceeded

If the counter exceeds 50, the IP is immediately banned for 10 minutes.
4

Window Reset

After 10 seconds, the key expires and the counter resets to 0.
Advantages:
  • O(1) complexity: INCREMENT is atomic and very fast
  • No cleanup needed: Keys automatically expire via TTL
  • Distributed: Works across multiple Sentinel instances
  • Simple: Easy to understand and maintain
Trade-offs:
  • Fixed window behavior (not true sliding window)
  • Potential burst at window boundaries
  • Consider using more sophisticated algorithms (token bucket, sliding log) for stricter control

IP Blacklist Implementation

The Sentinel service maintains a dynamic IP blacklist with automatic expiration.

Blacklist Configuration

BLACKLIST_PREFIX
string
Redis key prefix for blacklisted IPsDefault: blacklist:ip:Key Pattern: blacklist:ip:{ip_address}Example: blacklist:ip:192.168.1.100
durationMinutes
number
Ban duration in minutesDefault: 10 minutesConfigurable: Can be adjusted per ban event

Blacklist Service

RedisService.java
@Service
public class RedisService {
    private final StringRedisTemplate redisTemplate;
    private static final String BLACKLIST_PREFIX = "blacklist:ip:";

    public RedisService(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // Ban an IP address for specified duration
    public void banIp(String ipAddress, long durationMinutes) {
        redisTemplate.opsForValue().set(
            BLACKLIST_PREFIX + ipAddress,
            "BANNED",
            Duration.ofMinutes(durationMinutes)
        );
    }

    // Check if an IP is currently banned
    public boolean isBanned(String ipAddress) {
        return Boolean.TRUE.equals(
            redisTemplate.hasKey(BLACKLIST_PREFIX + ipAddress)
        ); 
    }
}

Ban Workflow

1

Detection

TrafficAnalyzer detects that an IP exceeded the rate limit (>50 requests in 10 seconds).
2

Blacklist

The IP is added to Redis with key blacklist:ip:192.168.1.100 and value "BANNED".
3

TTL Set

Redis sets a 10-minute TTL on the key. The ban expires automatically.
4

Enforcement

All subsequent requests from this IP are rejected immediately by checking isBanned().
5

Automatic Unban

After 10 minutes, Redis deletes the key and the IP can make requests again.

Redis Key Patterns

Key Naming Convention

Key PatternPurposeTTLValue
rate:ip:{ip}Rate limit counter10 secondsInteger (request count)
blacklist:ip:{ip}IP ban flag10 minutesString ("BANNED")

Key Expiration Strategy

# Key automatically expires after window
KEY: rate:ip:192.168.1.100
VALUE: 45
TTL: 7 seconds remaining
Automatic Cleanup: Redis handles all key expiration automatically. No manual cleanup required.

Monitoring Redis

Using Redis CLI

Connect to the Redis container:
docker exec -it black_list redis-cli

Useful Commands

# List all rate limit keys
KEYS rate:ip:*

# List all blacklisted IPs
KEYS blacklist:ip:*

Performance Considerations

Key Size: Each IP address entry uses approximately 50-100 bytesEstimated Usage:
  • 10,000 active IPs: ~1 MB
  • 100,000 active IPs: ~10 MB
  • 1,000,000 active IPs: ~100 MB
Redis’s in-memory nature makes this extremely fast, even with millions of keys.
INCREMENT: O(1) - Constant timeSET with TTL: O(1) - Constant timeHASKEY: O(1) - Constant timeAll rate limiting and blacklist operations are extremely fast.
AOF (Append-Only File): Enabled in docker-composePros:
  • Data survives Redis restarts
  • Blacklists persist across deployments
Cons:
  • Slight performance overhead
  • Disk I/O required
Alternative: Use RDB snapshots for better write performance
For high-traffic production deployments:
  • Use Redis Cluster for horizontal scaling
  • Use Redis Sentinel for high availability
  • Consider Amazon ElastiCache for managed Redis
  • Implement connection pooling (Lettuce handles this automatically)

Troubleshooting

Symptoms: Services can’t connect to RedisSolutions:
  • Verify Redis container is running: docker ps
  • Check health: docker logs black_list
  • Test connection: docker exec black_list redis-cli ping
  • Verify network connectivity between services
Symptoms: Blacklisted IPs never unbanSolutions:
  • Check TTL: redis-cli TTL blacklist:ip:192.168.1.100
  • Verify expire() is called after increment()
  • Check Redis memory policy: redis-cli CONFIG GET maxmemory-policy
  • Ensure Redis has sufficient memory
Symptoms: Redis consuming excessive memorySolutions:
  • Monitor key count: redis-cli DBSIZE
  • Check for keys without TTL: redis-cli KEYS * | xargs redis-cli TTL
  • Implement key eviction policy
  • Reduce rate limit window or ban duration

Production Recommendations

Enable Authentication

Set requirepass in redis.conf or use --requirepass flag

Configure Persistence

Choose between AOF (durability) or RDB (performance)

Set Memory Limits

Configure maxmemory and eviction policy

Use Connection Pooling

Spring Data Redis uses Lettuce with built-in pooling

Build docs developers (and LLMs) love