Rate Limiting의 개념과 중요성
Rate Limiting이란?
Rate Limiting은 특정 시간 동안 허용되는 요청 수를 제한하는 기법입니다.
이는 서버에 대한 과도한 요청으로부터 보호하고, 서비스의 안정성을 유지하기 위해 필수적입니다.
예를 들어, 사용자가 1분에 100번의 요청만 할 수 있도록 제한할 수 있습니다.
Rate Limiting의 중요성
- 서버 보호: 과도한 요청으로부터 서버를 보호하여 다운타임을 방지합니다.
- 자원 관리: 서버의 CPU, 메모리, 네트워크 자원을 효율적으로 관리할 수 있습니다.
- 공정한 사용자 경험: 모든 사용자가 공정하게 서비스에 접근할 수 있도록 합니다. 특정 사용자가 과도한 요청을 보내면 다른 사용자에게 피해를 줄 수 있습니다.
- 보안 강화: 악의적인 공격(예: DDoS 공격)으로부터 서버를 보호하는 데 도움을 줍니다.
Dart에서 Rate Limiting 구현하는 방법
Dart에서 Rate Limiting을 구현하는 방법에는 여러 가지가 있지만, 가장 흔하게 사용되는 방법은 Redis와 메모리 기반 Rate Limiting입니다.
1. Redis 기반 Rate Limiting
Redis는 빠른 성능의 인메모리 데이터베이스로, Rate Limiting을 구현하는 데 매우 유용합니다. 아래는 Dart에서 Redis를 사용한 간단한 Rate Limiting 예제입니다.
필요 패키지
먼저 redis 패키지를 사용해야 합니다. pubspec.yaml에 추가합니다.
dependencies:
redis: ^2.0.0
코드 예제
import 'dart:async';
import 'package:redis/redis.dart';
class RateLimiter {
final int limit;
final Duration window;
final Command redisCommand;
RateLimiter(this.limit, this.window, this.redisCommand);
Future<bool> allowRequest(String key) async {
final now = DateTime.now().millisecondsSinceEpoch;
final windowStart = now - window.inMilliseconds;
// Redis에서 요청 수 가져오기
final currentCount = await redisCommand.get(key) ?? '0';
final count = int.parse(currentCount);
// 요청 수가 제한을 초과했는지 확인
if (count < limit) {
await redisCommand.incr(key);
// TTL 설정 (시간이 지나면 자동으로 삭제)
await redisCommand.expire(key, window.inSeconds);
return true; // 요청 허용
}
return false; // 요청 거부
}
}
Future<void> main() async {
final connection = RedisConnection();
final command = await connection.connect('localhost', 6379);
final rateLimiter = RateLimiter(5, Duration(minutes: 1), command);
// 예시 사용자 키
final userKey = 'user:123';
for (var i = 0; i < 10; i++) {
final allowed = await rateLimiter.allowRequest(userKey);
print('Request ${i + 1}: ${allowed ? 'Allowed' : 'Denied'}');
await Future.delayed(Duration(seconds: 10)); // 요청 간 간격
}
}
코드 설명
- RateLimiter 클래스: 요청 수를 관리하는 클래스입니다. limit은 허용된 요청 수, window는 시간 창을 나타냅니다.
- allowRequest 메소드: 요청을 허용할지 여부를 결정합니다. Redis에서 현재 요청 수를 가져와 제한을 초과하지 않으면 허용합니다.
- TTL 설정: 요청 수가 일정 시간 후에 자동으로 삭제되도록 설정합니다.
2. 메모리 기반 Rate Limiting
메모리 기반 Rate Limiting은 서버의 메모리를 사용하여 요청 수를 관리하는 방법입니다. Redis보다 간단하지만, 여러 서버에서 실행하는 경우 데이터 공유가 어려울 수 있습니다.
코드 예제
import 'dart:async';
import 'dart:collection';
class MemoryRateLimiter {
final int limit;
final Duration window;
final Map<String, Queue<int>> _requests = {};
MemoryRateLimiter(this.limit, this.window);
bool allowRequest(String key) {
final now = DateTime.now().millisecondsSinceEpoch;
// 요청 큐 초기화
if (!_requests.containsKey(key)) {
_requests[key] = Queue<int>();
}
final queue = _requests[key]!;
// 시간 창에 맞는 요청 삭제
while (queue.isNotEmpty && now - queue.first > window.inMilliseconds) {
queue.removeFirst();
}
// 요청 수가 제한을 초과했는지 확인
if (queue.length < limit) {
queue.add(now);
return true; // 요청 허용
}
return false; // 요청 거부
}
}
void main() {
final rateLimiter = MemoryRateLimiter(5, Duration(minutes: 1));
final userKey = 'user:123';
for (var i = 0; i < 10; i++) {
final allowed = rateLimiter.allowRequest(userKey);
print('Request ${i + 1}: ${allowed ? 'Allowed' : 'Denied'}');
Future.delayed(Duration(seconds: 10)); // 요청 간 간격
}
}
코드 설명
- MemoryRateLimiter 클래스: 메모리를 사용하여 요청 수를 관리합니다.
- allowRequest 메소드: 현재 시간을 기반으로 요청 수를 관리하고, 시간 창에 맞지 않는 요청을 삭제합니다.
- Queue 사용: 요청 시간을 저장하는 큐를 사용하여 요청 수를 효율적으로 관리합니다.
Rate Limiting은 서버를 보호하고, 안정성을 유지하는 중요한 기법입니다.
Dart에서는 Redis나 메모리 기반의 방법을 사용하여 쉽게 구현할 수 있습니다.
이러한 기법들을 통해 여러분의 서버를 보다 안전하고 효율적으로 운영할 수 있습니다! 추가 질문이 있다면 언제든지 물어보세요.
구독!! 공감과 댓글은 저에게 큰 힘이 됩니다.
Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.
'Dart > Dart Server' 카테고리의 다른 글
[추가학습] Dart 서버/ API Throttling 기법 / Dart에서 API Throttling 구현하기: 다양한 전략 (토큰 버킷, 누적 버스트 등) (0) | 2024.09.22 |
---|---|
[추가학습] Dart 서버/ API Throttling 기법 / Throttling과 Rate Limiting의 차이점 (0) | 2024.09.22 |
[고급] Dart 서버 실시간 애플리케이션 구현 / Push Notification을 활용한 실시간 알림 시스템 (0) | 2024.09.19 |
[고급] Dart 서버 실시간 애플리케이션 구현 / 실시간 채팅 애플리케이션 구축 (1) | 2024.09.19 |
[고급] Dart 서버 실시간 애플리케이션 구현 / WebSocket을 사용한 실시간 통신 구현 (0) | 2024.09.19 |