Synchronous Programming vs Reactive Programming

2023-09-18

동기(주로 명령형 프로그래밍)에서는 각 요청마다 별도의 스레드를 할당(thread per request)하여 요청을 처리한다. 이 방법에서는 스레드 풀(Tomcat: 200 thread pool)이 모두 사용되고 있을 때와 같이 스레드가 차단되고 있을 때 요청을 처리하지 못 하고, 모든 스레드가 차단(blocked)되어 요청들이 거절되거나 큐에서 타임아웃까지 대기하게 된다. 이렇게 요청이 많은 서비스(예) 광고 서비스)에서는 idle 상태가 길게 유지되면 매우 비효율적이라고 볼 수 있다.

  • idle 상태란?

    간단하게 요청의 처리를 대기하고 있는 상태라고 생각하면 된다. (휴식 같은 느낌~)

  • 명령형(동기) 특징

    thread per request (요청당 스레드)

    요청이 동기적으로 처리되고 블로킹된다.

    • 간단한 동기/블로킹 예시 하나의 활주로에서 P2는 P1이 착륙을 완료한 후에 P2가 착륙할 수 있다.

      여기서 P2는 P1이 착륙을 하는 과정동안 착륙을 하지 못 한다. ( 블로킹 / 동기(순차적 실행) )

    스레드가 할당되면 해당 스레드는 작업이 완료(종료)될 때까지 블로킹 상태가 된다.

    스레드 풀의 크기 만큼만 요청을 처리할 수 있다.

    모든 스레드가 사용 중이면 메모리 사용률이 높아져 성능 저하가 발생한다.

    → 자원 사용이 효율적이지 못 하다.

    CPU에 비해 많은 스레드를 사용하는 애플리케이션은 비효율적

    • 컨텍스트 스위칭으로 인한 스레드 전환 비용 발생

      • 컨텍스트 스위칭 - 여러 프로세스 / 스레드가 번갈아가며 실행되는 것
        • 프로세스 1을 실행 후 잠시 중단되면 PCB에 실행 정보가 저장된다.
        • 프로세스 2는 프로세스 1 실행 동안 idle 상태이고, 프로세스 2의 idle 상태가 끝나면 PCB에서 실행 정보를 리로드한다.
        • 그동안 프로세스 1은 당연히 idle 상태일 것이다
        • 여기서 프로세스 1이 중지 되는 시점과 프로세스 2의 idle 상태가 끝나는 시점이 다르다.
          • 왜? PCB에 저장하고 로드하는데 시간이 걸려 두 개의 시점이 맞지 않는 것이다.
          • 그럼 CPU는 그동안 일을 못 함
        • 이와 같이 스레드에서도 컨텍스트 스위칭 비용이 발생한다.

      스레드가 증가할 수록 컨텍스트 스위칭 비용이 증가한다.

    • 메모리 사용에 의해 오버 헤드 발생 (스레드 증가)

      • 64 비트 JVM의 default stack size는 1024KB 이다
      • 하지만 50,000명이 동시에 접속할 시 50GB의 메모리가 추가로 필요하다. (오버 헤드)
    • 스레드 풀의 응답 지연 문제 발생

      • idle 상태의 스레드가 존재하지 않으면 응답시간이 길어짐
      • 스레드 사용 후 반납 과정에서도 응답 지연이 발생한다.

그래도 엄청 큰 규모(트래픽)가 아닌 이상 동기식이여도 상관없다.

이러한 많은 요청(높은 트래픽)을 서버에서 빠르게 응답하고 반응하기 위해 존재하는 프로그래밍 패러다임이 반응형 프로그래밍(Reactive Programming)이다.

  • 반응형 프로그래밍 특징
    • 비동기 / 논 블로킹
    • 배압(백프레셔) 지원
    • 데이터 스트림
    • 작업 스레드 사용 여부와 상관없이 차단되지 않음
    • 적은 스레드 사용으로 전환 비용이 적음
    • 주로 선언형 프로그래밍