트래픽 전환
고친 사람 github-actions[bot]
트래픽 전환은 들어오는 요청이 가는 곳을 옛 서버에서 새 서버로 옮기는 일입니다. 주로 새 버전을 배포할 때 씁니다. 돌고 있는 서버를 고치는 대신 요청의 행선지를 바꿔서 버전을 갈아 끼웁니다. 새 버전에 문제가 보이면 행선지를 다시 옛 서버로 돌립니다.
쉽고 빠른 이해
같은 주소로 들어오는 요청을 어느 서버 묶음이 받을지 바꾸는 일입니다. 옛 버전이 도는 서버 묶음 옆에 새 버전 묶음을 띄워 둡니다. 그다음 요청이 새 묶음으로 가게 길을 바꿉니다.
이 방법이 없으면 버전을 올릴 때마다 돌고 있는 서버를 멈추고 고쳐야 합니다. 그동안 요청이 실패합니다. 탈이 나면 되돌리는 일도 다시 설치하는 일이 됩니다.
- 새 버전 서버 묶음을 띄우고 요청을 받을 준비가 됐는지 확인합니다
- 요청을 나눠 보내는 장치에서 행선지를 새 묶음으로 바꿉니다. 한 번에 바꾸거나 조금씩 몫을 늘립니다
- 지켜보다가 문제가 보이면 행선지를 옛 묶음으로 되돌립니다
대가는 전환하는 동안 서버를 두 벌 띄워야 한다는 것입니다. 그리고 데이터베이스처럼 두 버전이 함께 쓰는 것은 길을 되돌려도 되돌아가지 않습니다.
상세
새 다리를 놓는 공사를 떠올려 봅시다. 옛 다리를 막고 고치는 대신 옆에 새 다리를 다 지은 뒤 표지판만 바꿔 차를 새 다리로 보냅니다. 새 다리에 금이 보이면 표지판을 다시 옛 다리 쪽으로 돌립니다.
이 절은 그 표지판을 바꾸는 일을 차례로 봅니다. 먼저 행선지를 어디서 바꾸는지 봅니다. 그다음 한 번에 바꿀지 조금씩 옮길지를 견줍니다. 이어서 바꾸는 순간 옛 서버에 남는 요청과, 길을 되돌려도 안 돌아가는 것을 봅니다. 마지막에 이 방식을 고를 상황을 가립니다.
서버를 고치는 대신 길을 바꾸는 방식
트래픽은 서비스로 들어오는 요청의 흐름입니다. 트래픽 전환은 그 흐름이 닿는 곳을 바꾸는 일입니다. 서버에 깔린 프로그램은 손대지 않습니다.
돌고 있는 서버를 멈추고 새 버전을 깔면 그동안 요청을 받을 서버가 없습니다. 트래픽 전환은 순서를 뒤집습니다. 새 버전을 먼저 다른 서버에 띄웁니다. 다 뜬 다음에 요청이 가는 곳을 옮깁니다.
주문 요청을 받는 서버 네 대가 옛 버전을 돌리고 있다고 해 봅시다. 새 버전 서버 네 대를 옆에 띄웁니다. 그다음 요청을 나눠 보내는 장치가 새 서버 넷을 바라보게 바꿉니다. 옛 서버 넷은 한동안 켜 둔 채로 남깁니다.
이처럼 요청이 어느 서버로 갈지 정하는 곳을 라우팅 계층이라고 부릅니다. 트래픽 전환은 결국 라우팅 계층의 설정 하나를 바꾸는 일입니다.
flowchart TD
U["사용자 요청"] --> R["라우팅 계층"]
R -. "전환 전" .-> O["옛 버전 서버 묶음"]
R -- "전환 후" --> N["새 버전 서버 묶음"]
O --> DB[("데이터베이스")]
N --> DB
그림에서 바뀌는 것은 라우팅 계층에서 나가는 화살표 하나뿐입니다. 두 서버 묶음은 같은 데이터베이스를 바라봅니다. 이 점은 뒤의 「길을 되돌려도 안 돌아가는 것」에서 다시 다룹니다.
행선지를 바꾸는 계층
라우팅 계층은 한 겹만 있지 않습니다. 요청은 서버에 닿기 전에 몇 겹을 거칩니다. 그 어느 겹에서든 행선지를 바꿀 수 있습니다. 어디서 바꾸느냐에 따라 전환이 사용자에게 퍼지는 시점이 달라집니다. 흔히 쓰는 라우팅 계층은 셋입니다.
첫째는 DNS(Domain Name System, 도메인 이름 시스템)입니다. 클라이언트가 서비스 이름을 물으면 DNS 는 그 이름이 가리키는 서버 주소를 답으로 돌려줍니다.
DNS 는 요청을 직접 받지 않습니다. 요청을 보내기 전에 어디로 보낼지를 알려 줄 뿐입니다. 이 답을 바꾸면 요청이 가는 곳이 바뀝니다.
둘째는 로드 밸런서와 리버스 프록시입니다. 둘 다 서버 앞에 서서 요청을 직접 받은 뒤 뒤쪽 서버 중 하나로 넘깁니다.
로드 밸런서는 요청을 여러 서버에 고르게 나누는 일을 주로 맡습니다. 리버스 프록시는 서버 쪽에 서서 요청을 대신 받아 넘겨 주는 중계 서버입니다. 나눠 보내는 일도 함께 맡을 때가 많아서 트래픽 전환에서는 둘이 같은 일을 합니다.
셋째는 서비스 메시입니다. 서비스끼리 주고받는 호출을 각 서버 옆에 붙은 프록시가 대신 나릅니다. 프록시는 요청을 대신 받아 목적지로 넘겨 주는 중계 프로그램입니다. 그래서 여기서 바꾸는 것은 사용자 요청이 아니라 서비스 사이 호출의 행선지입니다.
| 바꾸는 곳 | 무엇을 바꾸나 | 전환이 퍼지는 시점 |
|---|---|---|
| DNS | 이름이 가리키는 주소 | 클라이언트가 들고 있던 답이 만료된 뒤 |
| 로드 밸런서 · 리버스 프록시 | 요청을 보낼 대상 서버 목록 | 설정을 바꾼 뒤 새로 들어오는 요청부터 |
| 서비스 메시 | 서비스 사이 호출의 행선지와 몫 | 각 서버 옆 프록시가 새 설정을 받은 뒤 |
표의 셋째 칸이 갈림의 핵심입니다. DNS 의 답은 클라이언트와 중간 서버가 한동안 기억합니다. 중간 서버는 클라이언트 대신 DNS 에 물어 주는 서버입니다. 같은 질문이 다시 오면 기억해 둔 답을 그대로 돌려줍니다.
그 기억이 유지되는 기간을 TTL(Time To Live, 유효 시간)이라고 합니다. 주소를 바꿔도 TTL 이 다 지나기 전까지는 일부 요청이 옛 서버로 갑니다.
로드 밸런서와 리버스 프록시는 요청이 들어올 때마다 대상 목록을 봅니다. 목록을 바꾸면 그 뒤에 들어온 요청부터 새 서버로 갑니다. 그래서 전환을 짧은 시간 안에 끝내거나 되돌려야 할 때는 이쪽을 주로 씁니다.
서비스 메시에서는 바꾼 설정을 각 서버 옆 프록시에 나눠 보냅니다. 프록시가 새 설정을 받은 뒤부터 그 프록시를 지나는 호출이 새 행선지로 갑니다. 받는 시점이 프록시마다 조금씩 달라서, 다 받을 때까지는 옛 행선지와 새 행선지가 잠깐 섞입니다.
한 번에 바꾸기와 조금씩 옮기기
행선지를 바꾸는 방식은 두 끝 사이에서 고릅니다. 모든 요청을 한 순간에 새 묶음으로 보내는 쪽과, 요청의 몫을 나눠 조금씩 넘기는 쪽입니다.
한 번에 바꾸는 쪽은 라우팅 계층의 대상을 옛 묶음에서 새 묶음으로 통째로 갈아 끼웁니다. 두 묶음을 나란히 두고 한 번에 넘어가는 이 방식을 블루-그린 배포라고 부릅니다. 전환이 금방 끝나고 되돌리기도 한 번이면 됩니다. 대신 새 버전에 문제가 있으면 모든 사용자가 동시에 그 문제를 겪습니다.
조금씩 옮기는 쪽은 요청을 비율로 나눠 보냅니다. 처음에는 요청 열에 하나만 새 묶음으로 보냅니다. 괜찮으면 절반으로, 그다음 전부로 늘립니다. 요청을 이렇게 비율로 나눠 보내는 것을 트래픽 분할이라고 합니다. 처음 몫을 아주 작게 잡고 지켜보는 방식이 카나리 배포입니다.
몫을 늘릴지는 지표를 보고 정합니다. 대표적인 것은 둘입니다. 오류율은 새 묶음에서 나온 요청 중 실패한 비율입니다. 응답 시간은 응답이 오기까지 걸린 시간입니다.
둘이 옛 묶음과 비슷하면 몫을 늘립니다. 나빠지면 몫을 0으로 되돌립니다.
flowchart TD
S0["옛 묶음이 요청을 전부 받는다"] --> S1["새 묶음에 요청 열에 하나"]
S1 --> K{"새 묶음의 오류율과 응답 시간이 옛 묶음과 비슷한가"}
K -->|"나빠졌다"| S3["새 묶음의 몫을 0으로 되돌린다"]
K -->|"비슷하다"| A{"전부 넘겼나"}
A -->|"아직"| S2["몫을 늘린다 · 절반 → 전부"]
S2 --> K
A -->|"넘겼다"| E["전환 끝 · 옛 묶음은 한동안 남겼다가 내린다"]
그림처럼 조금씩 옮기는 쪽은 몫을 늘릴 때마다 한 번씩 멈춰 지표를 봅니다. 두 방식이 무엇을 주고받는지는 이렇습니다.
| 한 번에 바꾸기 | 조금씩 옮기기 | |
|---|---|---|
| 새 버전의 문제를 겪는 사용자 | 전부 | 그때 넘긴 몫만큼 |
| 전환을 마치는 데 드는 시간 | 한 번의 설정 변경 | 몫을 늘리는 단계 수만큼 |
| 두 버전이 함께 요청을 받는 기간 | 거의 없음 | 전환 내내 |
조금씩 옮기는 쪽에는 이점이 하나 더 있습니다. 새 서버는 막 떴을 때 준비가 덜 된 상태입니다. 자주 쓰는 값을 메모리에 담아 두는 캐시가 아직 비어 있어서 요청마다 데이터베이스까지 내려갑니다.
이런 서버에 요청을 한 번에 전부 넘기면 데이터베이스에 부하가 몰립니다. 막 뜬 서버가 겪는 이런 상태를 콜드 스타트라고 합니다. 조금씩 옮기면 새 서버의 캐시가 찰 시간을 법니다.
대신 조금씩 옮기는 쪽에서는 한 사용자가 옛 버전과 새 버전을 번갈아 만날 수 있습니다. 요청 하나하나를 비율로 나누기 때문입니다. 이를 막으려고 같은 사용자의 요청을 늘 같은 묶음으로 보내는 설정을 씁니다. 이 설정이 스티키 세션입니다.
전환하는 순간 옛 서버에 남는 요청
행선지를 바꾸는 순간에도 옛 서버는 이미 받은 요청을 처리하고 있습니다. 이 요청을 끊으면 사용자는 응답 대신 오류를 받습니다.
그래서 옛 서버를 바로 끄지 않습니다. 라우팅 계층의 대상에서 먼저 빼서 새 요청이 안 들어오게 합니다. 그다음 처리 중이던 요청만 마저 끝내게 합니다. 이렇게 마무리할 시간을 주는 것을 커넥션 드레이닝이라고 부릅니다.
sequenceDiagram
participant U as 사용자
participant R as 라우팅 계층
participant O as 옛 서버
participant N as 새 서버
U->>R: 요청 1
R->>O: 요청 1 을 보낸다
Note over R: 대상을 새 서버로 바꾼다
U->>R: 요청 2
R->>N: 요청 2 를 보낸다
Note over O: 요청 1 만 마저 끝낸다
O-->>R: 요청 1 의 응답
R-->>U: 요청 1 의 응답
오래 열려 있는 연결은 마무리가 길어집니다. 웹소켓처럼 한 번 맺고 계속 주고받는 연결은 행선지를 바꿔도 옛 서버에 붙은 채로 남습니다. 이런 연결은 끊어질 때까지 기다리거나, 정해진 시간이 지나면 끊고 클라이언트가 다시 맺게 합니다.
길을 되돌려도 안 돌아가는 것
트래픽 전환의 되돌리기는 행선지를 다시 옛 묶음으로 돌리는 것으로 끝납니다. 다만 그것은 옛 묶음이 아직 켜져 있을 때만입니다. 옛 서버를 이미 내렸다면 되돌리기는 다시 배포하는 일이 됩니다.
데이터베이스는 전환되지 않습니다. 앞의 그림처럼 두 묶음이 같은 데이터베이스를 쓰기 때문입니다. 새 버전이 전환 뒤에 써 넣은 데이터는 길을 되돌려도 남습니다.
그래서 두 버전이 서로의 데이터를 읽을 수 있어야 합니다. 전환하면 새 버전이 옛 데이터를 읽습니다. 길을 되돌리면 옛 버전이 새 데이터를 읽습니다.
새 버전이 옛 데이터를 읽는 성질을 하위 호환이라고 부릅니다. 거꾸로 옛 버전이 새 데이터를 읽는 성질은 상위 호환입니다. 트래픽 전환을 되돌릴 수 있으려면 둘 다 지켜야 합니다.
테이블에 열을 더하는 변경은 두 버전 모두와 호환됩니다. 옛 버전이 읽던 열을 지우는 변경은 되돌아갈 길을 끊습니다.
고를 만한 상황과 미룰 상황
트래픽 전환이 맞는 상황은 서버를 한 벌 더 띄울 여유가 있을 때입니다. 되돌리기가 설정 하나로 끝나야 하는 서비스라면 더 그렇습니다. 옛 묶음을 켜 둔 동안에는 문제가 보이는 즉시 길을 돌릴 수 있습니다.
미룰 상황은 둘입니다. 하나는 서버를 두 벌 띄우는 비용을 감당하기 어려울 때입니다. 그럴 때는 서버를 몇 대씩 갈아 끼우면서 대상 목록도 그만큼 바꾸는 롤링 업데이트를 고려합니다.
롤링 업데이트도 행선지가 옮겨 갑니다. 다만 옛 묶음을 따로 남겨 두지 않아서 되돌리는 데 시간이 더 걸립니다.
다른 하나는 두 버전이 같은 데이터를 함께 다룰 수 없을 때입니다. 옛 버전이 새 데이터를 못 읽는 변경이라면, 길을 되돌려도 새 버전이 남긴 데이터가 옛 버전을 깨뜨립니다.
이럴 때는 데이터 변경을 여러 번으로 나눕니다. 단계마다 두 버전이 모두 호환되게 만든 다음에 전환합니다. 열 이름을 바꾸는 일이라면 새 이름의 열을 먼저 더하고 두 열을 함께 채운 채로 전환합니다. 옛 버전이 다 내려간 뒤에야 옛 열을 지웁니다.
관련 항목
트래픽 전환으로 굴러가는 배포 방식
블루-그린 배포 · 카나리 배포 · 롤링 업데이트 · 단계적 출시 · 다크 런치 · 섀도 트래픽
요청의 행선지를 바꾸는 장치
로드 밸런서 · 리버스 프록시 · DNS · 서비스 메시 · 인그레스 · API 게이트웨이 · 프록시
전환하는 동안 연결과 요청을 지키는 기법
커넥션 드레이닝 · 스티키 세션 · 그레이스풀 셧다운 · 헬스 체크 · 준비성 프로브 · TTL
두 버전이 함께 도는 동안 지켜야 하는 성질
하위 호환 · 상위 호환 · 스키마 마이그레이션 · 무상태 · 콜드 스타트
전환을 이어 갈지 판단하는 지표
오류율 · 응답 시간 · 지연 · 백분위수 · 카나리 분석 · 골든 시그널
트래픽 전환이 속하는 상위 흐름
다른 이름: traffic shifting · traffic switching · traffic cutover · 트래픽 이동 · 트래픽 스위칭 · 트래픽 컷오버