-
Notifications
You must be signed in to change notification settings - Fork 0
사용자별 쿼리 실행 요청 제한
현재 서비스는 다음과 같이 여러 유저가 하나의 DB 서버를 공유하고 있습니다.
해당 상황에서 한 유저가 부하가 많이 가는 쿼리를 악의적으로 많이 실행시킬 시 다른 유저에게 피해를 줄 위험이 있습니다.
이를 위해 다음과 같은 방법으로 쿼리 실행을 제한을 두었습니다.
기존 서비스에서도 동시에 많은 쿼리 실행 요청을 보낼 수 없게 클라이언트단에서 실행중에는 해당 쉘 버튼을 비활성화하였습니다.
하지만 쉘을 많이 생성하면 동시에 실행시킬 수 있고, 서버에 직접 요청을 보내면 이를 제어할 수 없었습니다.
그래서 서버에서 쿼리실행 요청을 받으면 이를 동시에 처리하지 않고 순차적으로 처리할 수 있게 구현하였습니다.
하지만 순차처리만으로 서버의 안정성을 높이기에는 한계가 있었습니다.
- 모든 요청을 받기에 WAS에 부담을 줄 수 있습니다.
- 일시적인 부하량은 제어할 수 있어도, 일정량의 부하를 지속적으로 줄 수 있습니다.
이를 해결하기 위해 사용자별 처리를 제한하는 Rate Limiter를 구현하였습니다.
일반적으로 처리율 제한은 요청 수를 기준으로 적용하는 방식이 많이 사용됩니다.
이 방법은 특정 API의 단일 요청이 예상되는 부하를 유발하거나, 서비스적으로 제어가 필요할 때 유용합니다.
그러나 Q-Lab에서는 사용자가 실행하는 쿼리에 따라 서버 부하가 크게 달라지기 때문에, 요청 수 기반의 제한 방식은 효과적이지 않습니다.
따라서, 서비스에 적합한 방식으로 서버 부하를 측정할 수 있도록 쿼리 실행 시간을 기준으로 삼았습니다.
또한, 쿼리 실행은 단 하나의 쿼리만으로도 높은 부하를 발생시킬 수 있기에 보다 정밀한 제어가 필요합니다.
이를 위해 처리율 제한 방식 중 가장 정교한 제어가 가능한 Sliding Window Log 알고리즘을 기반으로 구현하였습니다.
flowchart TD
A["클라이언트"] -- 쿼리 실행 요청 --> B{"잔여 실행 시간 확인"}
B -- 잔여 실행 시간 > 0 --> C["잔여시간을 최대 실행 시간으로 설정"]
C --> D["쿼리 실행"]
D --> H["쿼리 실행 시간 저장"]
H --> E{"최대 실행시간 초과 확인"}
E -- 초과 시 (에러) --> X["에러 응답"]
X --> A
E -- 초과 안함 (정상 응답) --> Y["정상 응답"]
Y --> A
B -- 잔여 실행 시간 ≤ 0 --> X
busy waiting
(pub/sub)을 고려하지 않은 이유
Message Queue를 이용하여 순차처리를 구현하지 않은 이유
API Gateway 서버를 분리하여 이를 구현하지 않은 이유