다중화
고친 사람 github-actions[bot]
다중화는 서로 다른 여러 흐름의 데이터를 통로 하나에 함께 실어 보냅니다. 보내는 쪽이 조각마다 붙인 표시를 받는 쪽이 읽어 원래 흐름으로 되돌립니다. 여분을 여러 벌 두는 일도 같은 낱말로 부릅니다. 뜻이 다른 쪽이라 아래에서 갈라 봅니다.
쉽고 빠른 이해
무슨 일을 하는 물건인가 — 통로 하나를 여럿이 나눠 쓰게 하는 방법입니다. 컴퓨터에 랜선이 한 가닥뿐이어도 브라우저와 메일 프로그램이 같이 통신하는 것이 이 덕분입니다.
왜 이렇게 하나 — 흐름마다 선을 따로 깔면 선 값이 흐름 수만큼 듭니다. 게다가 흐름은 대개 띄엄띄엄 보내다 말기 때문에 자기 선을 놀립니다.
어떻게 도나
- 보내는 쪽이 조각마다 어느 흐름인지 표시를 붙입니다
- 표시를 단 조각들이 한 통로에 섞여 흐릅니다
- 받는 쪽이 표시를 읽어 흐름별로 나눠 줍니다
대가 — 나눠 쓰니 서로 영향을 줍니다. 한 흐름이 통로를 오래 물면 나머지가 기다리고, 통로가 끊기면 그 위의 흐름이 한꺼번에 끊깁니다.
상세
우체국 트럭 한 대가 동네 곳곳으로 갈 우편물을 함께 싣고 나갑니다. 봉투마다 받을 주소가 적혀 있으니 도착한 뒤에 집집마다 나눠 줄 수 있습니다. 집마다 트럭을 한 대씩 두는 것보다 적은 트럭으로 같은 일을 합니다.
다중화와 역다중화
흐름은 서로 상관없는 데이터 줄기 하나를 말합니다. 브라우저가 서버에서 그림을 받는 일이 흐름 하나이고, 같은 컴퓨터에서 메일 프로그램이 메일을 받는 일이 또 다른 흐름입니다.
통로는 이 흐름들이 지나야 하는 공용 길입니다. 랜선 한 가닥일 수도 있고, 두 프로그램이 이미 맺어 둔 연결 하나일 수도 있습니다.
다중화는 이 흐름들을 통로 하나에 몰아넣는 일입니다. 그냥 몰아넣으면 받는 쪽은 어느 조각이 누구 것인지 알 수 없습니다. 그래서 조각마다 어느 흐름의 것인지 알리는 표시를 붙입니다. 이 표시를 식별자라고 부릅니다.
받는 쪽에서 식별자를 읽어 흐름별로 도로 갈라내는 일은 역다중화라고 부릅니다. 둘은 언제나 짝입니다. 갈라내는 쪽이 없으면 받는 쪽에는 뒤섞인 바이트 더미만 남습니다.
flowchart TD
A["흐름 1"] --> M["다중화 · 식별자를 붙인다"]
B["흐름 2"] --> M
M --> L["통로 하나 · 표시를 단 조각이 섞여 흐른다"]
L --> D["역다중화 · 식별자를 읽어 나눈다"]
D --> E["흐름 1"]
D --> F["흐름 2"]
그림 가운데의 통로 하나가 이 방법이 아끼는 것입니다. 흐름이 둘이어도 통로는 한 개이고, 흐름이 백이어도 통로는 한 개입니다. 늘어나는 것은 통로가 아니라 식별자 가짓수입니다.
통로를 나누는 방식
통로 하나를 어떻게 갈라 쓰느냐는 무엇을 기준으로 자르느냐에 달려 있습니다. 크게 네 가지가 쓰입니다.
| 나누는 기준 | 어떻게 나누나 | 쓰는 곳 |
|---|---|---|
| 시간 | 통로를 짧은 시간 조각으로 자르고 흐름마다 차례를 준다 | 회선을 미리 잡아 두는 전화망 |
| 주파수 | 통로가 실어 나를 수 있는 주파수 대역을 흐름마다 나눠 준다 | 라디오 · 케이블 방송 |
| 빛의 파장 | 광섬유 한 가닥에 색이 다른 빛을 여러 줄기 함께 흘린다 | 장거리 광통신 |
| 붙인 식별자 | 보낼 것이 있는 흐름이 그때그때 통로를 쓰고, 조각의 식별자로 가른다 | 인터넷 같은 패킷 통신 |
앞의 세 가지는 흐름마다 몫을 미리 떼어 줍니다. 몫이 정해져 있으니 서로 밀치지 않습니다. 대신 그 흐름이 놀아도 남이 그 몫을 못 씁니다.
마지막 방식은 몫을 미리 떼지 않습니다. 보낼 것이 있는 흐름이 그때그때 통로를 씁니다. 이것을 통계적 다중화라고 부릅니다. 흐름들이 동시에 몰리는 일이 드물다는 셈에 기대는 방식이라 이런 이름이 붙었습니다.
띄엄띄엄 보내는 흐름이 많을수록 마지막 방식이 통로를 덜 놀립니다. 대신 여럿이 한꺼번에 몰리면 통로가 넘칩니다. 넘친 몫은 기다리거나 버려집니다.
흐름을 가르는 식별자
인터넷 쪽 통신은 식별자를 헤더에 적습니다. 헤더는 보낼 데이터 앞에 붙여 받는 쪽에게 이 데이터를 어떻게 다룰지 알리는 안내입니다.
식별자는 한 번만 읽고 끝나지 않습니다. 계층마다 자기 헤더가 있고, 계층마다 자기 식별자로 한 번씩 갈라냅니다. 받는 컴퓨터는 이 갈래길을 위에서 아래로 따라 내려갑니다.
flowchart TD
A["도착한 조각"] --> B["IP 헤더의 종류 칸 · TCP 인가 UDP 인가"]
B --> C["TCP 헤더의 도착 포트 · 어느 프로그램인가"]
C --> D["TLS 레코드의 콘텐츠 타입 · 핸드셰이크인가 응용 데이터인가"]
D --> E["스트림 번호 · 어느 요청인가"]
그림의 이름들을 아래에서 하나씩 풉니다. 네 칸은 서 있는 층이 다를 뿐 하는 일이 같습니다. 전부 「이 조각을 다음에 누구에게 넘길까」에 답합니다.
IP(Internet Protocol, 인터넷 프로토콜)는 주소를 보고 데이터를 목적지까지 나르는 약속입니다. IP 헤더의 종류 칸은 안에 든 것이 TCP(Transmission Control Protocol, 전송 제어 프로토콜)인지 UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)인지를 적습니다. 컴퓨터는 이 칸을 보고 조각을 알맞은 처리기에 넘깁니다.
포트 번호는 한 컴퓨터 안에서 어느 프로그램이 받을 것인지를 가리킵니다. 주소가 하나뿐인 컴퓨터에서 웹 서버와 데이터베이스가 같이 돌 수 있는 것이 이 칸 덕분입니다. 주소가 건물 번지라면 포트 번호는 호수입니다.
TLS(Transport Layer Security, 전송 계층 보안)는 오가는 내용을 암호로 감싸는 약속입니다. 감싼 조각 하나를 레코드라고 부르고, 레코드마다 콘텐츠 타입 칸이 붙습니다. 이 칸이 있어서 키를 맞추는 대화와 실제 데이터가 같은 암호 통로를 함께 지납니다. 부모가 되는 레코드 계층 입장에서 보면 이것도 다중화입니다.
스트림은 연결 하나 안에서 오가는 요청과 응답 한 쌍을 가리킵니다. 웹이 쓰는 약속인 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜)의 둘째 판 HTTP/2 가 스트림마다 번호를 붙입니다. 그 번호로 연결 하나에 요청 여럿을 함께 싣습니다. 앞 판에서는 연결 하나에 요청을 하나씩 올리고 응답이 올 때까지 기다렸습니다.
나눠 쓸 때의 값과 대가
얻는 것은 통로 수가 줄어드는 것입니다. 흐름마다 선을 깔거나 연결을 새로 맺지 않아도 됩니다. 연결을 맺는 데 드는 인사 절차도 한 번으로 끝납니다.
잃는 쪽은 흐름끼리의 독립입니다. 앞 흐름이 통로를 물고 있으면 뒤 흐름은 보낼 것이 있어도 못 보냅니다. 이렇게 앞이 막혀 뒤가 통째로 서는 것을 머리줄 막힘이라고 부릅니다.
식별자를 붙이는 비용도 있습니다. 조각마다 번호나 칸이 따라붙으니 보내는 바이트가 그만큼 늘어납니다. 본문 말고 덧붙는 이 몫을 오버헤드라고 부릅니다.
고장의 범위도 넓어집니다. 흐름마다 선이 따로면 선 하나가 끊겨도 흐름 하나만 끊깁니다. 통로 하나를 백 흐름이 나눠 쓰고 있었다면 그 통로가 끊길 때 백 흐름이 같이 끊깁니다.
통로를 따로 두는 조건
나눠 쓰는 쪽이 늘 이득인 것은 아닙니다. 한 흐름이 통로를 혼자서도 꽉 채운다면 나눠 쓸 몫이 애초에 없습니다. 큰 파일을 계속 내려보내는 흐름이 그렇습니다.
흐름끼리 영향을 주면 안 될 때도 통로를 가릅니다. 결제 요청과 로그 전송이 같은 통로를 쓰면 로그가 몰릴 때 결제가 기다립니다. 그래서 중요한 흐름에는 연결을 따로 두곤 합니다.
흐름 수가 적고 오래 이어질 때도 이득이 작습니다. 다중화가 값을 하는 곳은 짧고 띄엄띄엄한 흐름이 많은 곳입니다. 웹 페이지 하나가 받아 오는 작은 파일 수십 개가 그런 흐름입니다.
백엔드 코드에서 만나는 다중화
서버 코드가 가장 자주 만나는 것은 한 스레드가 소켓 여러 개를 함께 지켜보는 방식입니다. 이것을 I/O 다중화라고 부릅니다. 여기서 나눠 쓰는 통로는 선이 아니라 일하는 사람, 즉 스레드입니다.
소켓마다 스레드를 하나씩 붙이면 접속이 만 개일 때 스레드도 만 개입니다. 대신 스레드 하나가 소켓 목록을 들고 「무엇이든 준비된 것이 있으면 알려 달라」고 운영체제에 맡깁니다. 이 맡기는 창구가 epoll 같은 것들입니다.
응용 계층에서는 연결 하나에 요청 여럿을 싣는 쪽을 만납니다. gRPC 가 그렇게 돕니다. 서비스 사이 호출이 잦을수록 연결을 매번 새로 맺는 비용이 커지기 때문입니다.
커넥션 풀은 이름이 비슷하지만 다중화가 아닙니다. 풀은 연결 여러 개를 미리 만들어 두고 돌려쓰는 것이고, 한 연결은 한 번에 한 요청만 씁니다. 다중화는 연결 하나를 여러 요청이 동시에 쓰는 것입니다.
여분을 뜻하는 다중화
운영 쪽에서 「서버를 다중화한다」고 말할 때의 뜻은 다릅니다. 같은 일을 하는 것을 여러 벌 두어 하나가 죽어도 남은 벌이 일을 잇게 하는 것을 가리킵니다. 영어로는 multiplexing 이 아니라 redundancy 입니다.
두 낱말이 겹친 것이지 같은 뜻이 아닙니다. 방향이 오히려 반대입니다. 통신의 다중화는 하나를 여럿이 나눠 쓰는 일이고, 운영의 다중화는 하나가 하던 일을 여러 벌이 나눠 맡는 일입니다.
여분을 두 벌만 두는 구성은 이중화라고 부릅니다. 이 갈래의 이야기는 고가용성과 신뢰성 쪽에 있습니다.
어느 뜻인지는 문장에서 가릅니다. 「무엇 위에 무엇을 다중화한다」처럼 아래에 통로가 깔리면 통신 쪽입니다. 「무엇을 다중화해 둔다」처럼 대상이 장비나 서버면 여분 쪽입니다.
관련 항목
다중화와 짝을 이루는 처리 단계
역다중화 · 캡슐화 · 역캡슐화 · 프레이밍 · 단편화 · 재조립 · 헤더 압축
흐름을 가르는 식별자가 적히는 헤더 칸
헤더 · 포트 번호 · 콘텐츠 타입 · 스트림 · 연결 ID · 가상 회선 식별자
통로를 나누는 방식
시간 분할 다중화 · 주파수 분할 다중화 · 파장 분할 다중화 · 코드 분할 다중화 · 통계적 다중화 · 패킷 교환 · 회선 교환
한 연결에 여러 흐름을 싣는 프로토콜
TCP · UDP · TLS · HTTP/2 · QUIC · SCTP · gRPC · WebSocket
통로를 나눠 쓸 때 생기는 문제
머리줄 막힘 · 혼잡 제어 · 흐름 제어 · 오버헤드 · 시끄러운 이웃 · 대역폭 · 지연
한 일꾼이 여러 연결을 맡는 방식
입출력 다중화 · epoll · 논블로킹 입출력 · 이벤트 루프 · 커넥션 풀 · 스레드
다중화라는 이름을 나눠 쓰는 다른 개념
이중화 · 고가용성 · 신뢰성 · 복제 · 장애 조치 · 부하 분산
다중화가 속하는 상위 분류
다른 이름: multiplexing · 멀티플렉싱