serversim
학습시뮬레이터템플릿가격
…
…
메뉴 열기
학습↗시뮬레이터↗템플릿↗가격↗
내 Documents문서
목차/9단원9 / 16

동시성 ≠ 병렬성

일하는 사람을 늘리면 언제나 더 빨리 끝날까요? 계산대가 하나뿐인 가게에서는 점원을 몇 명 더 불러도 손님이 빠져나가는 속도는 그대로입니다.

많은 사람이 "동시에 처리한다"와 "동시에 계산한다"를 같은 말로 씁니다. 하지만 이 둘은 완전히 다르고, 구분하지 못하면 스레드만 잔뜩 늘려놓고 왜 안 빨라지는지 모르는 상황에 빠집니다. 아래에서 작업 성격과 코어 수를 바꿔가며 직접 확인해 보세요.

① 동시성 — 여러 일을 번갈아 진행하는 것

코어가 하나여도 여러 일이 "진행 중"일 수 있습니다. 하나가 IO를 기다리는 동안 다른 하나가 CPU를 쓰면 되니까요. 이렇게 여러 작업이 시간을 나눠 겹쳐 진행되는 성질을 동시성이라고 합니다. 시간을 잘게 쪼개 번갈아 하는 것이므로, 어느 순간을 딱 잘라 보면 실제로 계산 중인 것은 하나뿐입니다.

② 병렬성 — 정말로 같은 순간에 계산하는 것

코어가 4개라면 같은 순간에 4개의 계산이 물리적으로 함께 일어납니다. 이것이 병렬성입니다. 동시성은 코어 하나로도 가능하지만, 병렬성은 코어 수가 늘어야만 가능합니다.

③ 작업 성격이 결과를 가른다

작업은 크게 둘로 나뉩니다. 계산이 대부분인 CPU-bound 작업(이미지 변환, 암호화, 압축)과, 기다림이 대부분인 IO-bound 작업(디비 조회, 외부 API 호출, 파일 읽기)입니다. CPU-bound 작업은 코어 하나에서 스레드를 늘려봐야 갈아타기 비용만 늘고 총 시간은 그대로입니다 — 계산할 CPU가 하나뿐이니까요. 반대로 IO-bound 작업은 코어 하나에서도 스레드 수만큼 겹칩니다 — 기다림은 CPU를 쓰지 않으니까요.

④ 직접 확인해 보기

아래 두 패널은 같은 작업을 스레드 1개와 4개로 처리합니다. 작업 성격을 CPU 작업으로 두고 CPU 수를 1로 하면, 스레드를 4배로 늘려도 완료 개수가 오히려 뒤처집니다(갈아타기 비용 때문). CPU 수를 4로 바꾸면 그제야 4배로 빨라집니다. 이번엔 작업 성격을 IO 작업으로 바꿔 보세요 — CPU가 하나여도 스레드 4개 쪽이 훨씬 빨리 끝납니다.

⑤ 병렬성의 상한은 코어 수다

같은 순간에 실제로 계산되는 것은 코어 수를 넘지 못합니다. 코어가 네 개면 스레드를 백 개 만들어도 동시에 계산되는 것은 최대 네 개입니다. 그래서 CPU-bound 작업에서 스레드를 코어 수보다 훨씬 많이 만들면 얻는 것은 없고 컨텍스트 스위치 비용과 메모리만 늘어납니다. 반대로 IO-bound 작업에서는 스레드가 코어 수보다 훨씬 많아도 됩니다 — 대부분이 자고 있기 때문입니다.

⑥ 그래서 몇 개로 잡아야 하나

출발점은 계산입니다. 요청 하나가 CPU를 c만큼, 기다림을 w만큼 쓴다면, 코어 하나를 놀리지 않으려면 대략 (c+w)/c 개의 동시 요청이 필요합니다. CPU 10밀리초에 대기 90밀리초라면 코어당 열 개입니다. CPU-bound는 코어 수 근처, IO-bound는 이 비율만큼 크게 — 이것이 스레드풀 크기와 커넥션 풀 크기를 정하는 첫 계산입니다.

속도작업 성격CPU 수

시뮬레이터에서 해보기

  1. 1.'App 10대로 늘렸는데 왜?' 프리셋 — App(Spring) 노드의 Instances가 10으로 병렬로 돕니다. 10,000 RPS·10초 실측에서 App CPU는 32%로 한가한데 MySQL CPU는 88%(피크 93%)로 빨갛습니다.
  2. 2.인스펙터에서 App 노드의 Instances를 올렸다 내렸다 해보세요 — 앱을 아무리 병렬화해도 그 뒤의 MySQL 카드 색은 그대로입니다. '동시성을 늘린다고 병목이 사라지지 않는다'는 것이 카드 색으로 직접 보입니다.
시뮬레이터에서 실험해보기 →

이 단원의 용어

동시성(concurrency)
여러 작업이 시간을 나눠 겹쳐 진행되는 성질. 코어 1개로도 가능.
병렬성(parallelism)
같은 순간에 여러 계산이 물리적으로 함께 일어나는 것. 코어가 여러 개여야 가능.
CPU-bound
시간의 대부분을 계산에 쓰는 작업. 코어를 늘려야 빨라진다.
IO-bound
시간의 대부분을 기다림에 쓰는 작업. 동시성으로 겹치면 처리량이 오른다.
병렬성 상한
동시에 계산될 수 있는 최대 개수. 코어 수가 정한다.
CPU 대 대기 비율
요청 하나의 계산 시간과 기다림 시간의 비. 적정 동시성의 출발점.

갈아타기는 기다림을 숨길 뿐, 계산을 늘리지는 못한다.

남은 문제

서버 요청은 어느 쪽일까요? 파싱 조금, 디비 대기 한참, 응답 조금 — 전형적인 IO 작업입니다 →

← 이전 단원

8단원. 스레드 — 프로세스가 무거워서 태어났다

다음 단원 →

10단원. 서버의 방법 ① — 스레드풀