우리가 사용하는 컴퓨터의 자원은 유한합니다.
예를 들어, 제가 지금 사용하고 있는 컴퓨터를 기준으로 생각해 보겠습니다.
CPU: i7-1360P
메모리: 32.0GB
i7-1360P는 12코어, 즉 동시에 12명의 인부를 부릴 수 있는 셈입니다.
32GB 메모리는 작업대에 비유할 수 있습니다. 최대 32GB만큼의 작업 정보를 동시에 펼쳐 놓고 처리할 수 있다는 의미입니다.
노트북 치고는 꽤 괜찮은 사양이지만, 그만큼 구매 비용도 높습니다. 이처럼 컴퓨터 자원(CPU, 메모리)은 무한하지 않으며, 비용과 맞바꾸는 유한한 자원이라는 점을 먼저 인지해야 합니다.
여기에 시간이라는 요소도 함께 고려해야 합니다.
같은 물건을 만든다고 하더라도 수작업은 많은 시간이 소요되는 반면, 기계는 매우 빠르게 동작합니다. 즉, 연산 능력뿐 아니라 얼마나 오래 자원을 점유하는지 역시 중요한 요소가 됩니다.
프로그램에서 시간을 고려해야 하는 부분은 어디일까요?
디스크에서 파일을 읽거나 쓰는 작업, 외부와 통신하는 작업은 CPU 연산에 비해 훨씬 느립니다. 그렇기 때문에 I/O(input/output)와 Network 역시 중요하게 고려해야 합니다.
이렇기 때문에 어떤 객체나 기능이 비싸다, 무겁다고 말할 때는 다음 네 가지 관점에서 판단하게 됩니다.
| 비용 유형 | 정의 | 측정 단위 |
|---|---|---|
| 1. CPU 사용량 | 연산에 드는 비용 | CPU 사이클, 시간 |
| 2. 메모리 점유 | 공간에 드는 비용 | 바이트, 할당 시간 |
| 3. 초기화/실행 시간 | 셋업에 드는 비용 | 밀리초, 나노초 |
| 4. I/O & Network | 외부 자원에 드는 비용 | 왕복시간, 지연 |
1. CPU 사용량
- 암호화 및 해싱
- 직렬화/역직렬화
- 컴파일 및 빌드
- 정규표현식 매칭
2. Memory
- Context Switching
- Memory Leak 사용하지 않는 메모리를 반환하지 않아 가용 가능한 RAM의 크기가 줄어듦
- Memory Fragmentation (파편화): 메모리는 충분하지만, 조각조각 나 있어 큰 데이터를 올릴 수 없는 상태
3. I/O (Disk)
- Random Read/Write
- Logging 무분별하게 찍는 로그인 경우.
- Swap 메모리가 부족해 하드디스크의 일부를 메모리처럼 쓸 때는 속도가 느림.
4. Network
- Round Trip Time (RTT) : 네트워크 왕복 시간
- Handshake (TLS/SSL): 보안 연결을 수립하기 위해 패킷을 여러 번 주고받는 과정
- API 호출
설계에서 고려하는 방법
설계에서 지속적으로 비쌈 무거움 을 고려합니다. 그러나 위의 4가지 경우 모두를 피할 수 없는 경우에는 어떻게 해야할까요? 우선, 실제 성능에 영향을 미치는 순서를 알아봅시다.
실제 성능 영향 순서 1순위 : Network
ms단위 지연 : 초- 예측 불가능성
2순위 : I/O
ms~ s 단위의 지연 : 초
3순위 : Memory
ms단위
4순위 : CPU
ns단위 : 초
그리고 이제 적당한 돈으로 극복할 수 없는 한계를 살펴봅시다.
돈으로 개선 가능한 것
- CPU 연산 (더욱 좋은 CPU)
- 메모리 성능(DDR4 → DDR5)
불가능한 것
- Network IO
- 물리적 거리를 극복할 수 없음.
- Disk IO
SSD와 같은 것을 써도, 메모리 만큼 빠르기는 불가능
이러한 점을 고려하면 최적화 순서를 다음과 같이 정의할 수 있습니다.
비용을 고려한 최적화 순서
1순위: Network I/O 최적화
├─ RTT 횟수 최소화 (배치 처리)
├─ 연결 재사용 (Connection Pooling)
└─ 캐싱 (자주 쓰는 데이터)
2순위: Disk I/O 최적화
├─ 순차 접근 설계
├─ 인덱싱
└─ 캐싱 (핫 데이터)
3순위: 메모리 관리
├─ 메모리 누수 제거
├─ GC 튜닝
└─ 캐시 전략
4순위: CPU 최적화
├─ 알고리즘 개선
├─ 불필요한 연산 제거
└─ 병렬화 (마지막 수단)
→ 그렇다면, cache 가 과연 최고의 방법일까요?
Cache가 최고의 방법일까