Загружаем каталог…
Загружаем каталог…
대표 문제 클라이언트가 POST 요청을 보낸 순간부터 Spring Controller가 실행되기까지 실제로 무슨 일이 일어나는가? 스터디 전 최초 답변 클라이언트 POST 요청 -> DNS로 서버 IP 확인 -> TCP 커넥션 생성 -> 서버로 전송 -> Filter -> DispatcherServlet -> Controller 실행 진지하게 대학을 다시 가야 할 것 같고, 다시 정리한 전체 흐름은 아래와 같다. POST https://api.example.com/orders ↓ DNS 도메인 → IP 주소 확인 ↓ TCP 서버와 Connection 생성 ↓ TLS 서버 인증 + 암호화 통신 준비 ↓ HTTP Method / Path / Header / Body 전송 ↓ Web Server / Servlet Container ↓ Filter Chain ↓ DispatcherServlet ↓ HandlerMapping / HandlerAdapter ↓ Controller 1. 사용자가 POST 요청을 보냈다 예를 들어 프론트엔드에서 다음 API를 호출한다고 해보자. POST https://api.example.com/orders Content-Type: application/json { "itemId": 10, "quantity": 2 } 보기에는 단순히 POST /orders 를 호출한 것처럼 보인다. 하지만 클라이언트가 알고 있는 것은 api.example.com 이라는 도메인 이름 이다. 네트워크에서 실제 목적지를 찾아가기 위해서는 먼저 서버의 IP 주소를 알아내야 한다. 여기서 DNS가 등장한다. 2. DNS - 도메인을 IP 주소로 바꾼다 DNS는 Domain Name System의 약자다. 사람은 api.example.com 같은 이름을 사용하기 편하지만 네트워크에서는 실제 목적지를 찾기 위해 IP 주소가 필요하다. 따라서 개념적으로 다음 변환이 필요하다. api.example.com ↓ DNS 203.0.113.10 DNS의 핵심 역할은 도메인 이름을 해당 서비스의 IP 주소 등의 DNS Record로 해석하는 것 이다. 2-1. 요청할 때마다 DNS 서버까지 찾아갈까? 처음에는 Client ↓ DNS Server ↓ IP 반환 정도로 생각하기 쉽다. 하지만 매 요청마다 DNS 전체 조회를 수행한다면 비용이 너무 커지기 때문에 여러 단계에서 Cache를 사용한다. 애플리케이션 / 브라우저 Cache ↓ miss OS DNS Cache ↓ miss Recursive DNS Resolver ↓ 필요하다면 Root DNS ↓ TLD DNS ↓ Authoritative DNS 단, 정확한 Cache 계층과 순서는 OS, Browser, Runtime, Network 환경마다 달라질 수 있다. 2-2. Recursive DNS Resolver 일반 사용자가 Root DNS부터 직접 하나씩 질의하는 것은 아니다. 보통 ISP나 회사, Cloudflare, Google 같은 Recursive Resolver 에게 api.example.com의 IP가 뭐야? 라고 요청한다. Resolver가 이미 Cache하고 있다면 바로 응답한다. 없다면 필요한 DNS 서버들을 조회한다. 2-3. Root → TLD → Authoritative Cache가 전혀 없다고 단순화하면 다음과 같은 흐름이 될 수 있다. Client ↓ Recursive Resolver ↓ Root DNS "example.com은 어디서 알아?" ↓ .com TLD DNS 정보 ↓ TLD DNS "example.com은 어디서 관리하지?" ↓ Authoritative DNS 정보 ↓ Authoritative DNS "api.example.com 주소는?" ↓ IP Address Root DNS가 최종 IP를 모두 가지고 있는 것이 아니다. 각 단계가 다음에 어디를 확인해야 하는지 알려주는 구조에 가깝다. 2-4. TTL DNS Record에는 TTL(Time To Live)이 설정될 수 있다. 예를 들어 TTL = 300 seconds 라면 Resolver 등이 해당 결과를 일정 시간 Cache할 수 있다. 그래서 서버 IP가 변경되더라도 DNS 변경 사항이 모든 사용자에게 즉시 반영된다고 보장할 수는 없다. 핵심 질문 1 POST 요청을 보낼 때마다 DNS Lookup이 발생하는가? 반드시 그렇지는 않다. Browser, OS, DNS Resolver 등의 Cache에 결과가 남아 있다면 Cache된 결과를 사용할 수 있다. 즉 HTTP 요청 1회 = DNS 전체 조회 1회 가 아니다. 3. IP를 알았다면 서버와 연결해야 한다 DNS를 통해 다음 IP를 알아냈다고 가정하자. api.example.com ↓ 203.0.113.10 HTTPS 기본 Port를 사용한다면 목적지는 대략 203.0.113.10:443 이다. 이제 실제 통신을 위한 Connection이 필요하다. 전통적인 HTTP/1.1과 HTTP/2의 HTTPS 통신에서는 일반적으로 TCP 위에서 통신한다. 3-1. TCP 3-Way Handshake TCP Connection을 만들기 위해 대표적으로 3-Way Handshake를 수행한다. Client Server ───────── SYN ────────────→ ←────── SYN + ACK ───────── ───────── ACK ────────────→ 이를 통해 양쪽이 통신 가능한 상태인지 확인하고 Connection 상태를 만든다. 3-2. Connection은 무엇으로 구분할까? TCP Connection은 일반적으로 다음 정보의 조합으로 식별할 수 있다. Source IP Source Port Destination IP Destination Port 예를 들어 192.168.0.10:51000 ↓ 203.0.113.10:443 와 같은 연결이 만들어질 수 있다. Client의 Source Port는 일반적으로 OS가 사용 가능한 Ephemeral Port 중 하나를 선택한다. 3-3. TCP가 제공하는 것 TCP는 애플리케이션에게 신뢰성 있는 순서 보장 Byte Stream 을 제공한다. 대표적으로 다음 기능들이 있다. 순서 보장 손실 감지 및 재전송 중복 처리 Flow Control Congestion Control 예를 들어 데이터 일부가 네트워크에서 손실되더라도 TCP가 재전송할 수 있다. 3-4. 그렇다면 TCP가 있으면 요청 처리가 보장될까? 아니다. TCP가 보장하는 것은 Byte Stream이 상대 TCP Endpoint까지 신뢰성 있게 전달되는 것 에 가깝다. TCP가 주문 DB 저장 성공 결제 성공 Controller 실행 성공 Transaction Commit 성공 같은 비즈니스 처리를 보장하지는 않는다. 즉 TCP 전송 성공 ≠ Business 처리 성공 이다. 핵심 질문 2 TCP 연결에 성공했다는 것은 서버가 POST 요청을 성공적으로 처리했다는 의미인가? 아니다. TCP Connection이 존재한다는 것은 네트워크 통신 경로가 마련됐다는 의미이지, 애플리케이션 비즈니스 로직의 성공을 의미하지 않는다. HTTP 응답을 받아야 하고, 그 HTTP 응답 역시 애플리케이션의 처리 결과를 표현하는 별도의 계층이다. 4. HTTPS라면 TLS가 필요하다 우리는 실제 서비스에서 보통 http:// 보다 https:// 를 사용한다. HTTPS는 개념적으로 HTTP ↓ TLS ↓ TCP 구조로 이해할 수 있다. TLS는 통신 과정에서 주로 다음을 제공한다. Confidentiality → 내용을 암호화 Integrity → 전송 중 변조 여부 확인 Authentication → 인증서를 통해 서버의 신원을 검증 4-1. TLS Handshake에서는 무슨 일이 일어날까? TLS 1.3 기준으로 크게 단순화하면 다음과 같이 볼 수 있다. Client │ │ ClientHello │ 지원 TLS Version │ Cipher Suites │ Key Share 등 ↓ Server │ │ ServerHello │ 사용할 알고리즘 선택 │ Key Share │ Certificate │ Certificate Verify 등 ↓ Client 서로 Key Material 계산 ↓ 암호화된 Application Data 통신 실제 과정은 더 복잡하지만 핵심은 다음 세 가지다. 1. 어떤 암호화 방식을 사용할지 협상한다. 2. 서버의 인증서를 검증한다. 3. 이후 사용할 Session Key를 안전하게 만들어낸다. 4-2. 서버가 비밀키를 클라이언트에게 보내는 걸까? 아니다. 서버의 Private Key를 클라이언트에게 보내면 보안이 완전히 무너진다. TLS에서는 공개키 암호와 Key Exchange를 이용해 양쪽이 공통된 비밀 값을 안전하게 만들어낸다. 실제 Application Data는 성능상 효율적인 대칭키 암호화 를 사용한다. 4-3. 인증서는 왜 필요한가? 암호화만 한다고 안전한 것은 아니다. 공격자가 중간에서 "내가 api.example.com이야" 라고 속이고 자신과 TLS Connection을 만들게 한다면 문제가 된다. 그래서 인증서를 통해 이 서버가 정말 api.example.com의 서버인지 를 검증한다. Client는 보통 다음과 같은 것들을 확인한다. Certificate가 신뢰 가능한 CA Chain으로 이어지는가? Hostname이 일치하는가? 유효 기간이 정상인가? 4-4. TCP 다음에는 무조건 TLS일까? HTTP가 HTTPS라면 HTTP/1.1과 HTTP/2에서는 대체로 TCP ↓ TLS ↓ HTTP 로 이해할 수 있다. 하지만 현대 HTTP에는 예외가 있다. HTTP/3 HTTP/3는 TCP를 사용하지 않고 QUIC 을 사용한다. QUIC은 UDP를 기반으로 하면서 TLS 1.3 기능을 통합한다. 따라서 HTTP/1.1 / HTTP/2 HTTP ↓ TLS ↓ TCP 와 HTTP/3 HTTP/3 ↓ QUIC + TLS ↓ UDP 는 구분할 필요가 있다. 이번 학습에서는 Spring 서버에서 흔하게 접하는 HTTP/1.1 / HTTP/2의 TCP 기반 흐름을 중심으로 본다. 핵심 질문 3 HTTPS는 HTTP와 완전히 다른 프로토콜인가? HTTP의 의미 자체가 완전히 달라지는 것이 아니다. HTTP Message를 TLS로 보호해서 전송하는 구조라고 이해하면 된다. HTTP Request ↓ TLS 암호화 ↓ Network 따라서 HTTPS에서도 GET, POST, Header, Status Code 같은 HTTP 의미는 그대로 존재한다. 5. 이제 HTTP Request를 보낸다 연결과 암호화 준비가 끝나면 실제 HTTP Request를 전달한다. HTTP/1.1의 형태를 단순화하면 다음과 같다. POST /orders HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer xxx Accept: application/json Content-Length: ... { "itemId": 10, "quantity": 2 } HTTP Request는 크게 Request Line Headers Body 로 볼 수 있다. 5-1. Method 여기서는 POST 이다. HTTP Method는 Request가 가진 의미를 나타낸다. 대표적으로 GET POST PUT PATCH DELETE 등이 있다. 다만 POST = 무조건 생성 PUT = 무조건 수정 처럼 HTTP Method를 CRUD와 완전히 동일시하면 안 된다. HTTP가 정의하는 각 Method의 Semantics 가 있고 REST API를 설계할 때 이를 Resource 처리와 연결해서 사용하는 것이다. 5-2. Request Target /orders 는 서버에서 어떤 Resource나 Endpoint를 대상으로 요청하는지를 표현한다. Spring에서는 이후 @PostMapping("/orders") 같은 Mapping과 연결될 수 있다. 5-3. Header HTTP Header에는 Request에 대한 Metadata가 들어간다. 예를 들어 Content-Type Authorization Accept Cookie Host User-Agent 등이다. 5-4. Content-Type과 Accept는 다르다 자주 혼동하는 부분이다. Content-Type: application/json 은 내가 지금 보내는 Body가 JSON이다. 라는 의미다. 반면 Accept: application/json 은 나는 JSON 형태의 Response를 받을 수 있다 / 원한다. 라는 의미다. 5-5. Body POST에서는 Request Body에 데이터를 담는 경우가 많다. { "itemId": 10, "quantity": 2 } Spring에서는 이후 HttpMessageConverter 등을 통해 이 JSON을 Java 객체로 변환할 수 있다. 예를 들어 @PostMapping("/orders") public ResponseEntity<?> create( @RequestBody CreateOrderRequest request ) { } 의 JSON ↓ CreateOrderRequest 변환이 일어난다. 6. HTTP 요청마다 TCP Connection을 새로 만들까? 처음에는 다음처럼 생각할 수 있다. Request 1 TCP 연결 TLS 연결 Request Response 연결 종료 Request 2 TCP 연결 TLS 연결 Request Response 연결 종료 이렇게 하면 Request마다 TCP Handshake TLS Handshake 비용을 계속 지불해야 한다. 비효율적이다. 그래서 기존 Connection을 재사용한다. 6-1. HTTP Keep-Alive HTTP/1.1에서는 Persistent Connection이 기본 동작이다. 즉 Response를 받았다고 TCP Connection을 반드시 바로 종료하지 않는다. TCP + TLS Connection 생성 ↓ Request 1 Response 1 ↓ Request 2 Response 2 ↓ Request 3 Response 3 ↓ Connection 종료 같은 Connection을 여러 Request에 재사용할 수 있다. 6-2. 왜 Connection을 재사용할까? 매번 Connection을 새로 만들면 다음 비용이 발생한다. TCP Handshake TLS Handshake Socket 생성/정리 Network RTT 증가 CPU 암호 연산 Connection을 재사용하면 이러한 비용을 줄일 수 있다. 6-3. Keep-Alive와 Connection Pool Client가 Backend 서버를 호출한다고 생각해보자. 예를 들어 Spring Server A ↓ 외부 API Server B A가 B를 호출할 때마다 Connection을 새로 만들기보다는 HTTP Client가 Connection Pool 을 관리할 수 있다. Connection Pool Connection 1 ─ Server B Connection 2 ─ Server B Connection 3 ─ Server B Request가 들어오면 기존 Connection을 빌려 사용하고 다시 Pool에 돌려준다. 6-4. Connection Pool도 무한하지 않다 예를 들어 Pool에 Connection이 100개밖에 없는데 동시에 1,000개 요청이 외부 서버를 호출한다고 해보자. 100개 → Connection 사용 나머지 900개 → Connection을 기다림 그러면 여기에서도 Queue와 Timeout 문제가 생긴다. 1주차에서 Thread Pool을 봤듯이 Network에도 제한된 Resource가 존재한다. Thread Pool DB Connection Pool HTTP Connection Pool 모두 비슷한 Capacity 문제를 가진다. 6-5. HTTP/2에서는? HTTP/1.1 Connection 재사용보다 더 발전된 방식이 있다. HTTP/2에서는 하나의 TCP Connection 안에서 여러 Stream 을 Multiplexing할 수 있다. 하나의 TCP Connection ├─ Stream 1 → Request A ├─ Stream 3 → Request B ├─ Stream 5 → Request C └─ Stream 7 → Request D 즉 Connection 하나 = Request 하나 가 아니다. 핵심 질문 4 Keep-Alive는 단순히 서버가 살아 있는지 확인하는 기능인가? 여기서 말하는 HTTP Persistent Connection의 Keep-Alive는 서버 Health Check 기능이 아니다. 핵심은 한 Request가 끝난 뒤에도 Connection을 유지하고 다음 Request에서 재사용하는 것 이다. Connection 생성 비용을 줄여 성능을 높일 수 있다. 7. 요청이 서버에 도착했다 이제 Request가 서버 측 Network Stack까지 도착했다고 해보자. Spring Boot + Tomcat 기반의 전통적인 Spring MVC 서버를 예로 들면 크게 다음과 같은 흐름이 된다. Network ↓ Tomcat Connector ↓ Servlet Container ↓ Filter Chain ↓ DispatcherServlet ↓ HandlerMapping ↓ HandlerAdapter ↓ Controller 실제 환경에서는 앞에 CDN Load Balancer Reverse Proxy Nginx API Gateway 등이 추가될 수도 있다. 7-1. Tomcat이 요청을 받는다 Spring Boot에서 Spring MVC를 사용하면 기본적으로 Embedded Tomcat을 사용하는 구성이 흔하다. Tomcat은 Network Connection에서 HTTP Request를 읽고 HTTP Message를 Parsing한다. 이를 Servlet API의 HttpServletRequest HttpServletResponse 형태로 다룰 수 있게 한다. 7-2. Worker Thread 전통적인 Spring MVC + Servlet 기반 서버에서는 Worker Thread가 Request 처리를 담당한다. Request A → Thread 1 Request B → Thread 2 Request C → Thread 3 그래서 지난 주에 공부한 Thread Pool Thread Queue Context Switching I/O Bound 개념이 여기서 그대로 연결된다. 7-3. Filter Servlet 요청은 Spring MVC Controller로 가기 전에 Filter Chain을 통과할 수 있다. 대표적으로 Spring Security도 Filter Chain을 활용한다. Request ↓ Security Filter ↓ Authentication 확인 ↓ Authorization 확인 ↓ DispatcherServlet 예전에 Spring Security에서 공부했던 UsernamePasswordAuthenticationFilter AuthenticationManager AuthenticationProvider SecurityContext 등의 흐름도 결국 Controller보다 앞쪽 Filter 계층에서 시작될 수 있다. 7-4. DispatcherServlet Spring MVC의 핵심 Front Controller다. 모든 Controller가 직접 HTTP Request를 처음 받는 것이 아니라 DispatcherServlet이 중앙에서 Request를 받아 적절한 Handler로 연결한다. Request ↓ DispatcherServlet ↓ 어떤 Controller가 처리하지? 7-5. HandlerMapping DispatcherServlet은 HandlerMapping 등을 통해 현재 Request를 처리할 Handler를 찾는다. 예를 들어 @RestController @RequestMapping("/orders") public class OrderController { @PostMapping public void createOrder() { } } 가 존재하고 POST /orders 가 들어왔다면 해당 Handler Method를 찾는다. 7-6. HandlerAdapter DispatcherServlet이 모든 종류의 Handler를 직접 실행하는 대신 HandlerAdapter가 Hand
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
2. 클라이언트가 POST 요청을 보낸 순간부터 Spring Controller가 실행되기까지 실제로 무슨 일이 일어나는가?. 대표 문제 클라이언트가 POST 요청을 보낸 순간부터 Spring Controller가 실행되기까지 실제로 무슨 일이 일어나는가? 스터디 전 최초 답변 클라이언트 POST 요청 -> DNS로 서버 IP 확인 -> TCP 커넥션 생성 -> 서버로 전송 -> Filter -> DispatcherServlet -> Controller 실행 진지하게 대학을 다시 가야 할 것 같고, 다시 정리한 전체 흐름은 아래와 같다. POST https://api.example.com/orders ↓ DNS 도메인 → IP 주소 확인 ↓ TCP 서버와 Connection 생성 ↓ TLS 서버 인증 +…
Открыть источник