이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
기초개념 › 구조와 운영
서버가 다른 서버를 부르는 것은 메서드를 부르는 것과 무엇이 다른가
큰 서비스는 기능을 여러 서버로 나누기도 합니다. 주문을 받는 주문 서버와 결제를 맡는 결제 서버가 따로 실행되는 서로 다른 프로그램이라면, 주문 서버는 결제를 하려고 결제 서버에 네트워크로 요청(POST /pay)을 보내야 합니다. 같은 프로그램 안의 메서드를 부를 때는 부를 상대가 늘 같은 프로그램 안에 있고 호출이 곧바로 끝나지만, 네트워크 너머의 서버를 부를 때는 상대가 꺼져 있어 연결이 거절될 수 있고, 상대가 느려서 기다려야 할 수 있습니다. 그래서 주문 서버의 코드에는 답을 얼마나 기다릴지(타임아웃)와, 실패했을 때 클라이언트에게 무엇으로 답할지를 정해 두어야 합니다. 이 실습은 결제 서버의 상태와 기다리는 시간을 정했는지를 바꿔 가며, 클라이언트가 받는 응답과 걸린 시간, 주문 서버가 겪은 일을 봅니다. 코드 칸은 프로그램이 아니라 누가 누구에게 무엇을 보내는지를 적은 것이고, 실제 실행은 이 설정대로 주문 서버와 결제 서버를 띄워 요청을 주고받은 것입니다.
실행으로 대조 · Node.js 24.18.0의 주문 서버와 결제 서버를 띄워 여섯 가지 조합을 실행해 대조
# 클라이언트 → 주문 서버(8080): POST /orders # 주문 서버 → 결제 서버(9000): POST /pay (최대 1초 기다린다) # 결제 서버: 0.1초 뒤 "결제 완료" # 주문 서버: 연결 실패는 502, 시간 초과는 504로 답한다
코드 칸은 실행한 프로그램이 아니라, 클라이언트와 주문 서버와 결제 서버가 주고받은 것을 적은 글입니다. 실제 실행은 Node.js 24.18.0의 http 모듈로 주문 서버와 결제 서버를 127.0.0.1에 따로 띄우고(포트는 운영체제가 정한 빈 포트이며, 화면의 8080과 9000은 예시 번호입니다), 클라이언트가 주문 서버에 POST /orders를 보내게 했습니다. 주문 서버는 결제 서버에 POST /pay를 보내고(연결을 재사용하지 않음), 결제 서버가 답하면 200 "주문 완료"로, 연결 실패(ECONNREFUSED)이면 502로, 시간 초과이면 504로 답하게 썼습니다. 결제 서버는 0.1초 뒤 또는 3초 뒤에 200 "결제 완료"로 답하며, 꺼진 결제 서버는 서버를 띄웠다가 닫아 아무도 듣지 않는 포트를 만들어 흉내 냈습니다. 최대 1초 기다리는 것은 AbortSignal.timeout(1000)을 http.request의 signal로 주어, 정하지 않는 것은 signal을 주지 않아 구현했습니다. 여섯 가지 조합을 모두 실행해 클라이언트가 받은 응답과 걸린 시간, 주문 서버가 겪은 오류의 종류, 결제 서버가 요청을 받았는지와 결제 처리를 끝낸 때, 그때 연결이 이미 끊겨 있었는지를 모형과 대조했고, 화면의 코드가 서버들이 실제로 받은 요청 줄과 주문 서버에 정한 기다림 한도, 결제 서버의 지연 설정, 오류별 상태 코드에서 만든 글과 같은지도 조합마다 확인했습니다. 걸린 시간은 화면에 어림으로 적었고 이 PC에서 잰 값은 약 0.1초(0.117초), 바로(0.003초 이하), 약 1초(1.01초), 약 3초(3.02초)였습니다. 결제 서버가 꺼져 있을 때는 기다리는 시간을 정했는지와 관계없이 같은 결과가 나왔습니다. 3초 뒤에 답하는 결제 서버에 1초 한도를 두면, 주문 서버가 기다림을 그만둔 뒤에도 이 결제 서버는 3초 뒤 결제 처리를 끝냈습니다. 이 결제 서버는 연결이 끊겼는지 확인하지 않고 처리를 끝내도록 이 실습에서 쓴 것이므로, 모든 서버가 그렇게 동작한다는 뜻은 아닙니다. 기다리는 시간을 정하지 않고 결제 서버가 요청을 받고도 끝내 답하지 않게 했을 때는 4초가 지나도록 주문 서버가 포기하지 않았고 클라이언트도 응답을 받지 못했지만, 그 이상 오래 기다리면 어떻게 되는지는 보지 않았습니다. 이것들은 이 Node.js 버전에서 관찰한 동작입니다. 문서로 확인한 것은 RFC 9110의 3.3절(클라이언트와 서버의 정의, 같은 프로그램이 둘 다 될 수 있음), 15.6.3절(502는 게이트웨이나 프록시로 일하는 서버가 안쪽 서버에게서 올바르지 않은 응답을 받았을 때), 15.6.5절(504는 게이트웨이나 프록시로 일하는 서버가 안쪽 서버에게서 제때 응답을 받지 못했을 때)과 Node.js 문서의 http.request(signal 옵션은 진행 중인 요청을 중단하며, timeout 옵션은 요청을 중단하지 않고 timeout 이벤트만 더함)입니다. 주문 서버는 엄밀하게는 프록시가 아니라 스스로 일하는 서버이므로, 연결 실패에 502를, 시간 초과에 504를 쓴 것은 규격이 정한 쓰임을 넓게 따른 이 코드의 선택이고, 다른 상태 코드(예를 들어 503)로 답하는 서버도 있을 수 있습니다. 같은 프로그램 안의 메서드 호출에는 연결이라는 단계가 없다는 것은 실행으로 재지 않은 설명입니다. 화면은 한 번 부르는 가장 단순한 경우만 다루었고, 실패한 호출을 다시 보내는 것, 계속 실패하는 서버를 부르지 않고 건너뛰는 것, 여러 서버에 걸친 일을 되돌리는 것은 다루지 않았습니다. 연결 타임아웃과 읽기 타임아웃의 구분은 "세부 동작 실습: 외부 API 호출과 타임아웃", 실패하는 서버를 막아 주는 장치는 "서킷 브레이커", 여러 서버의 일을 되돌리는 방법은 "Saga와 Outbox", 요청을 한곳에서 받아 나누는 방법은 "게이트웨이와 점진적 전환"에서 다룹니다.
줄을 그은 곳은 처음 코드에서 지운 것이고, 색을 칠한 곳은 새로 쓴 것입니다.