DEV Community

JongHwa
JongHwa

Posted on

Step 2. Optimizing Feed Performance: DB Indexing & Rate Limiting

Following the user registration feature in Step 1, I moved on to the core feature of any SNS: The Feed.

However, simply storing and retrieving data isn't enough. I had to consider performance (how fast can we retrieve feeds?) and stability (how do we prevent abuse?).

In this post, I will share how I optimized database queries using Composite Indexes and implemented a custom Rate Limiter in Spring Boot.


1. Database Indexing Strategy

The most common query for a feed is: "Show me the latest posts written by User A."

Without an index, the database performs a Full Table Scan, checking every single row. To optimize this, I applied a Composite Index.


@Entity
@Table(name = "feeds", indexes = {
    @Index(name = "idx_user_created_at", columnList = "user_id, created_at")
})
public class Feed { ... }

Enter fullscreen mode Exit fullscreen mode
  • Why user_id? To filter posts by the specific user.
  • Why created_at? To sort them in descending order (latest first).
  • Result: The database can now jump directly to the user's data and read it sequentially, significantly reducing query time.

2. Protecting the Server: Rate Limiting

One of the requirements was to limit users to 5 requests per minute to prevent spamming or DDoS-like behavior.

Instead of using heavy external tools like Redis immediately, I implemented a lightweight In-Memory Rate Limiter using Java's ConcurrentHashMap.

How it works:

  1. Storage: A Map stores the request count for each user ID.
  2. Check: Before processing a request, check if the count exceeds 5.
  3. Reset: A @Scheduled task clears the map every minute.

@Component
public class RateLimiter {
    private final Map<Long, Integer> requestCounts = new ConcurrentHashMap<>();

    public boolean isAllowed(Long userId) {
        int count = requestCounts.getOrDefault(userId, 0);
        if (count >= 5) return false; // Block request
        requestCounts.put(userId, count + 1);
        return true;
    }

    @Scheduled(cron = "0 * * * * *") // Reset every minute
    public void resetCounts() {
        requestCounts.clear();
    }
}

Enter fullscreen mode Exit fullscreen mode

3. Frontend Integration (React)

On the frontend, I handled the 429 Too Many Requests error gracefully. If the server rejects a request due to the rate limit, the user sees a friendly alert message instead of a crash.


} catch (error) {
  if (error.response?.status === 429) {
    alert("You are posting too fast! Please wait a moment. 🛑");
  }
}

Enter fullscreen mode Exit fullscreen mode

4. Conclusion

In this step, I learned that backend development is not just about logic, but about resource management.

  • Indexes save CPU and I/O.
  • Rate Limiters save the server from being overwhelmed.

Top comments (0)