Handshake: 현대 API의 보이지 않는 비용
Source: Dev.to
무슨 일이 일어나고 있나요?
로컬에서 API가 20 ms에 응답할 때, 로그에는 병목 현상이 보이지 않고, 데이터베이스는 이미 최적화됐으며 코드도 깔끔합니다. 프로덕션에 배포하면 응답 시간이 400 ms로 늘어납니다. 우리는 즉시 로그를 다시 확인하고, 코드를 검토하고, 데이터베이스를 살펴보며, 문제가 거기에 있어야 한다고 확신합니다.
우리가 보통 잊거나 단순히 눈치채지 못하는 것은 첫 번째 바이트가 전송되기 전에 이미 비용이 발생한다는 점입니다.
클라이언트와 서버는 통신해야 합니다. 보안과 신뢰성을 위한 이 통신 협상은 네트워크 품질, 관련 지역 간 거리, 사용되는 전송 프로토콜에 따라 비용이 달라집니다. 로컬에서는 이 비용이 눈에 띄지 않지만, 프로덕션에서는 피할 수 없습니다. 이를 무시하면 현대 아키텍처에서 조용히 비용이 곱해집니다.
거쳐가는 경로
DNS 해석이 캐시되어 있지 않다면, 요청은 계층적인 과정을 거칩니다:
- 클라이언트가 루트 서버에 질의하여 어느 서버가 TLD를 담당하는지 확인합니다.
- TLD 서버가 도메인의 권한 있는 서버를 가리키고, 최종적으로 IP 주소를 반환합니다.
각 단계마다 왕복 통신이 발생하며, 연결이 설정되기 전에도 지연이 추가될 수 있습니다.
데이터가 전송되기 전, TCP는 클라이언트와 서버 사이에 신뢰할 수 있는 연결을 설정해야 합니다. 이 과정, 즉 three‑way handshake는 최소 한 번의 왕복이 필요합니다.
보안이 요구되는 연결에서는 이 비용이 더 증가합니다. TCP가 설정된 뒤에도 보안을 협상해야 하며, TLS는 클라이언트와 서버 사이에 또 하나의 통신 단계를 요구합니다.
비용은 이미 지불되었습니다. 없앨 수는 없지만, 아키텍처 차원에서 상쇄하거나 영향을 줄일 수는 있습니다.
피해 최소화
이 지연은 구현상의 문제가 아니라 신뢰성과 보안을 위한 올바른 선택의 결과입니다. 없앨 수 없으므로, 언제, 몇 번, 어디서 이 비용을 지불할지를 결정하는 것이 핵심입니다.
- 연결 재사용: keep‑alive와 connection pooling을 사용하면 DNS, TCP, TLS 비용을 한 번만 지불하고 여러 요청을 동일한 채널을 통해 전송할 수 있습니다.
- HTTP/2: 하나의 연결에 여러 요청을 다중화하여 필요한 연결 수를 줄입니다. 이득은 네트워크를 더 빠르게 만드는 것이 아니라 초기 비용을 몇 번이나 지불해야 하는지를 감소시키는 데 있습니다.
- TLS session resumption: 보안 연결에서 이전 TLS 연결 정보를 재사용해 전체 핸드셰이크를 반복하지 않게 합니다.
- TLS 종료 집중화: load balancers나 API gateways에 TLS 종료를 두면 비용이 발생하는 위치가 바뀌고, 내부 서비스 간에 비용이 무분별하게 퍼지는 것을 방지합니다.
- HTTP/3 (QUIC): TCP 의존성을 없애고 전송 계층에 TLS를 통합해 첫 바이트가 전송되기 전 필요한 단계 수를 줄입니다. 모바일이나 불안정한 연결 환경에서는 이 차이가 결정적일 수 있습니다.
- 불필요한 호출 회피: 캐시, 데이터 집계, fan‑out 감소는 핸드셰이크 자체를 빠르게 만들지는 않지만, 핸드셰이크가 발생하는 횟수를 줄입니다.
지연은 네트를 몇 번 건너가기로 결정했는가에 따라 발생합니다. 핸드셰이크 비용을 무시하면 비용이 곱해지고, 이를 아키텍처의 일부로 다루면 제어·상쇄·많은 경우에 크리티컬 경로에서 제외할 수 있습니다.
참고 자료
- System Design – Protocolos e Comunicação de Rede
- Optimizing TLS over TCP to Reduce Latency – Cloudflare Blog
- SSL/TLS Recommender – Cloudflare Blog
- What is DNS? – Cloudflare Learning