Netty Proxy

1,040 단어·3 분·원문(.md)

외부 기관과 연동하는 시스템에서 외부기관은 최대 세션 80개까지 밖에 지원을 해주지 않는 상황이였다.

그래서 해당 서비스 트래픽 제어와 세션 제어, 서킷 브레이커, 리트라이 등 하나의 책임을 갖고 트래픽을 관리하는 프록시 서버를 구축해야했다.

그중에서 네티를 사용하기로 했다.

물론 단순한 세션제한, rate limit, backpressure는 다른 프록시 제품도 구현이 가능하다 nginx haproxy envoy등도 가능하다.

하지만 문제는 외부 시스템이 40~80세션밖에 안된다는 점에서 출발해야하는데 이 상황에서는 단순 커텍션 리밋 이상의 확장성이 필요하다.

외부 세션이 적을수록 대부분의 요청이 대기상태가 된다.

외부 시스템 40~80개 세션만 있다면 내부 2000 RPS, 외부 초당 50개의 처리가능인 상황에서 나머지 1950개는 프록시에서 대기 (QUEUED) 되어야 한다.

이 지점에서 문제가 생기는데 대기중인 1950개의 요청이 모두 블로킹 IO방식으로 처리되면

  • 스레드 수가 급증
  • CPU context switch 폭증
  • 메모리 증가
  • 스레드 exhaustion으로 프록시 자체가 장애가 난다

쉽게 말해 외부 세션이 적으면 대기 요청이 많아지고 그 대기 요청을 어떻게 효율적으로 유지하느냐가 핵심이다.

그리고 이 부분에 대해서 네티가 압도적으로 유리하다.

Single thread Event Loop로 수만개의 대기 요청을 버틸 수 있다. #

비동기 non-blocking 기반의 네티 본질적인 강함이 존재해선데

  • worker thread 수가 매우적고
  • 모든 요청을 event loop에서 상태 기반으로 처리한다.
  • 외부 세션 할당 가능으로 이벤트가 올 때까지 요청은 lightweight state로 유지된다.
  • 요청수가 100,000개여도 스레드 폭증이 없다.

반면 nio 미지원 프록시/블로킹 구조라면

  • 요청 수만큼 스레드 or coroutine 필요하고
  • 스레드 예약만으로도 서버가 다운되며
  • 메모리 초과 또는 context switching이 폭증한다.

연결수 제한 + 비동기 큐잉 + 스케줄링을 안정적으로 지원하기도 한다.

다른 프록시들도 connection limit 정도는 쉽게 제공하지만

  • 복잡한 queue scheduling
  • priority queue
  • deadline queue
  • external availability event 기반 request dispatch

같은 고급 io제어는 제약이 그다

netty는 다음이 모두 가능하다.

  • 40개의 outbound 세션 콜
  • 이 세션 중 available channel 이벤트가 발생할때만 디스패치
  • 나버지는 event loop가 경량 객체로 홀드
  • queue overflow시 백프레셔
  • 사용자가 원하는 정책으로 커스텀 제어 가능

이 수준의 custom io 제어는 nginx haproxy envoy로는 사실상 불가능하다.

외부 연동 응답이 느린경우 네티가 안정적이다. #

예를들어 외부가 5~10초 걸리는 응답시간이라면 블로킹 스레드 모델의 프록시는 요청이 오래 붙잡혀 스레드 고갈이 발생할 가능성이 매우 높다.

하지만 네티는

  • 모든 진행을 async state machine으로 처리
  • 시간이 오래 걸리면 단순히 futrue 상태로 남아있음
  • 스레드는 다른 요청 처리 가능
  • 스레드 고갈 없음

따라서 외부 시스템 응답이 느린 형태의 도메인에서 좋다.

Back-End/nettyproxy.md