software 성능을 분석하는 관점에서 cpu bound, I/O bound로 분류를 할 수 있습니다.
spring webflux는 대량의 I/O 요청에 용이하게 설계 되어 있습니다.
이는 I/O Bound 작업에 가깝습니다.
---
CPU Bound
- CPU :
- CPU란 computer process unit의 약자입니다. 명령어를 기반으로 계산을 처리하는 중앙처리 장치입니다.
컴퓨터의 모든 작업은 CPU를 사용하게 됩니다. CPU 바운드 작업이란 단순히 CPU를 사용한 다는 것이 아니라 CPU를 중점적으로 사용하는 것을 말합니다.
예를 들면, 암호화, 압축 알고리즘 계산, 다수의 데이터에 대한 집계도 그 예시가 됩니다. 주로 CPU성능에 작업이 크게 좌지우지 됩니다.
밑에서부터 하드웨어, 커널, 어플리케이션을 추상화하여 나타내었습니다.
동시간에 하나의 명령어를 처리 할 수 있는 CPU 코어가 1개가 있다고 가정합니다.
어플리케이션 레이어에서는 Apps#1은 실행된 프로세스라고 가정합니다.
물리적인 하나의 CPU코어에 명령어를 내리는 상황입니다.
만약 어플리케이션이 추가로 한개 더있다고 가정합니다.
2개의 App에서 단일 CPU core에 작업을 요청한다고 생각해봅니다.
이때, CPU 코어에서는 동시 실행하는 것 처럼 보여 질 수 있지만 동시간대에 하나의 명령어만 처리 할 수 있기 때문에
타임 슬라이스를 잘게 나누어서 보게 되면 어플리케이션 1번과 2번이 번갈아 실행하는 것을 볼 수 있습니다.
이렇게 번갈아 가면서 실행하는 과정을 OS 관점에서는 context switching이라고 합니다.
실행 관점에서 문맥을 바꿧다는 의미입니다. context switcing 작업들은 CPU Bound에서는 성능 저하를 가져오게 됩니다.
어플리케이션이 실행되어 메모리에 Load되고 process로 동작되게 될 것입니다.
CPU가 scheduling 되어 실행되게 될 때, 기계어 실행을 위해 필요한 것을 Register로 미리 가져오게 됩니다.
그리고 ALU를 통해서 실제 계산이 진행됩니다.
Register에서는 기존에 어떤 명령어가 진행되었는지 함께 저장해두게 됩니다.
필요해 의해 캐시도 해둡니다. 동일한 프로세스를 꾸준히 하면 할 수록 효율적입니다.
컨텍스트 스위칭에 대해 알아보기 위해 이번에는 application 2번이 실행된다고 봅시다.
이를 위해 register 정보를 초기화하는 과정부터 진행됩니다.
정확히는 1번 어플리케이션이 실행했던 기존 정보들을 메모리에 별도 저장해두고 2번 어플리케이션 데이터 정보를 가져와서
register에 적재한 뒤 이제 명령어를 실행하게 됩니다.
그래서 하나의 CPU에서 다수의 프로세스들이 번갈아 가면서 CPU 작업들이 진행되기 때문에 성능상 오버헤드가 발생한다고
볼 수 있습니다.
사실 현대 컴퓨팅 시스템에서 하나의 CPU를 통해서 여러 프로세스가 실행되는 것은 정상적으로 동작한다고 볼 수 있습니다.
하지만 성능관점에서 잦은 컨텍스트 스위칭은 적절하다고 볼 수 없습니다.
만약 어플리케이션1번과 2번이 실행되고 있을때 아래 둘중 어느것이 더 빠르게 끝날까요?
- 동기적으로 진행(하나의 어플리케이션 작업이 모두 끝나고 다음 어플리케이션 작업)
- 비동기적으로 진행(1번 어플과 2번 어플 작업을 일정 영역과 시간대로 조금씩 번갈아가면서)
논리적으로 1번입니다. 이유는 번갈아가면서 진행하게 되면 컨텍스트 스위칭으로 발생하는 오버헤드가 커지기 때문입니다.
그렇다면 어떻게 하면 CPU Bound 상황을 더 효과적으로 만들 수 있을 까요?
간단합니다. 멀티코어를 사용합니다. 이는 병렬 처리하는 것입니다.
동시간 2개의 코어에서 2개의 명령어를 각각 처리하게 됩니다.
2개의 CPU 작업에 대해서 각각의 코어를 활용하게 함으로써 컨텍스트 스위칭을 최소화 할 수 있습니다.
Multi Core
- 6Ghz
- 8Ghz
- 10Ghz
context switching이 아니더라도 하나의 CPU에 대해서 고속화를 하게 되면 특정 지점부터는 발열문제를 해결하기 어려워집니다.
일반적으로 CPU를 5Ghz 이상으로 고속화하지 않고 멀티코어 방식으로 하드웨어 설계 방식이 발전하고 진행되게 되었습니다.
평균적으로 3Ghz, 저전력 CPU들은 1Ghz를 활용하는 경우도 많습니다. 서버 하드웨어들은 대략 3,4 Ghz를 기반으로 16코어, 32코어, 64코어를 넘어서 118코어까지 많은 코어를 탑재한 경우도 있습니다.
I/O Bound
I/O 바운드에서 I/O는 Input, Output이며 입출력 작업에 중점적인 작업을 I/O Bound 작업이라고 합니다.
예를들어, 키보드, 네트워크 통신, 마우스를 통한 데이터를 주고 받는 작업을 말합니다.
Network I/O를 한 번 살펴 보겠습니다.
아래 이미지를 살펴봅니다.
client에서 전달한 'Hello' packet은 NIC(Network Interface Card)를 통해서 kernel에서 네트워크 프로토콜을 지나가게 됩니다.
Server Application 입장에서는 커널로부터 packet을 전달 받기 전까지, 즉 커널에서 패킷을 처리하기 전까지 대기를 하게 됩니다.
즉, NIC로부터 packet을 받고 kernel까지의 과정 또한 CPU 사용이 필요한 영역이긴 합니다..
어플리케이션 관점에서 패킷 수신 완료까지 대기하기 때문에 CPU를 중점적으로 사용하지 않는 상태라고 할 수 있습니다.
만약 패킷이 오지 않았다고 한다면 해당 프로세스는 계속 대기하게 됩니다.
Web Application의 관점
web application에서 어떤 I/O가 있는지 살펴봅니다.
- client, DB, API Server와의 요청과 응답은 I/O를 발생시키게 됩니다.
다수의 요청이 Client로부터 발생 한 경우를 알아봅니다.
전통적으로는 웹어플리케이션 쓰레드의 개수를 늘려서 처리하는 것입니다.
CPU관점에서 context switching을 고려해야 합니다. 오버헤드가 발생되기 때문입니다.
context switching over head를 감수하더라도 I/O 요청을 최대한 처리 할 수 있도록 하는 전략이라고 볼 수 있습니다.
만약 하나의 쓰레드에서 하나의 연결을 처리하는 순간 다른 추가 요청이 있게 되면 이것이 대기하는 것이 아니라
또 다른 쓰레드를 할당하여 처리하도록 만들게 됩니다. 만약 대량의 요청을 처리하기 위해서 그때마다 쓰레드 개수를 늘리게 된다면,
성능과 리소스 관점에서 고려 할 것이 2가지가 있습니다.
쓰레드를 메모리가 필요합니다. 만약 10만개의 요청을 동시에 처리하고 싶다면 (10만 요청 * 요청 메모리 용량)의 자원이 필요합니다.
만약 하드웨어 메모리 최대 용량까지 사용하게 된다면, 시스템이 아예 동작하지 못 할 수 있습니다.
커널에서는 안전 장치로써 OOM이 있습니다. 주요 프로세스를 KILL 함으로써 System Down을 예방합니다.
그렇다면 웹어플리케이션 프로세스도 정리해버리게 됩니다.
요청이 완료된 쓰레드는 삭제하고 새로 들어온 요청을 위해서 쓰레드를 다시 생성 할 수 있습니다.
이러한 생성 -> 삭제 -> 생성 -> 삭제의 과정은 성능 측면에서 낭비가 됩니다.
이러한 이슈에 대한 대응 전략으로 쓰레드 풀이 활용됩니다.
쓰레드 풀에서는 미리 가용가능한 쓰레드를 만들어 둡니다.
요청이 오면 쓰레드를 꺼내 사용하고 사용이 모두 완료되면 다시 쓰레드 풀에 반납하는 전략입니다.
즉, OS 레벨에서 쓰레드 생성과 삭제가 빈번하게 발생하지 않아 오버헤드를 줄일 수 있습니다.
하드웨어 관점에서도 메모리를 모두 소진하여 OOM을 발생시키는 것을 예방할 수 있습니다.
물론 context switching이라는 over head는 발생 할 수 있습니다.
실제 Spring MVC에서는 기존 내장된 Tomcat 서버에서 쓰레드 풀 기반으로 동작하게 되어 있습니다.
특정 MAX 수치만큼 쓰레드 개수를 유지하면서 트래픽을 처리 할 수 있도록 설계되어 있습니다.
'프로그래밍 언어 > 스프링부트' 카테고리의 다른 글
Webflux - reactor 실습 (0) | 2024.09.18 |
---|---|
Redis Pub/Sub과 Spring Boot를 활용한 실시간 알림 시스템 구현 (0) | 2024.09.15 |
Spring Session (0) | 2024.09.15 |
OneToMany 관계 설정 시 필드 타입 설정은 뭘로 하나? (0) | 2024.05.28 |