HTTP와 네트워크에 관한 질문들

HTTP에 관한 질문들

  • 웹브라우저에 주소를 입력하고 화면이 뜨기까지의 과정을 설명해보세요.

웹브라우저에 주소를 입력하면 우선 도메인 이름을 resolve해야 한다.

도메인 네임은 각 시스템마다 입력되어 있는 DNS 서버에 질의하는 방식으로 이뤄진다. 대부분의 경우 각 ISP가 제공해주는 DNS를 사용하고 있고 저 개인적으론 프라이버시에 관심이 많아 8.8.8.8 이라는 외국 사설 DNS를 사용하고 있다. 국내 DNS 서버들이 DPI 등 패킷 수준 감청에 활용되고 있다는 느낌을 받기 때문이다.

DNS는 자신이 갖고 있는 레코드와 질의 내용을 비교해본 후 자신이 갖고 있지 않은 정보라면 요청을 TLD 네임서버로 보낸다. TLD란 Top level Domain으로 .ac.kr, .com 과 같은 주소를 관리하는 서버들이다.

TLD로 질의가 올라간다고 해서 바로 답변을 얻을 수 있는 것은 아니고, 해당 도메인 대역에 대한 정보를 얻을 수 있는 NS로 다시 연결시켜준다. NS에서 마지막으로 도메인 이름을 IP주소로 바꿔주거나, CNAME 레코드인 경우 다시 도메인을 찾을 수 있도록 요청을 바꿔준다.

  • CNAME이 뭔가? 도메인에도 종류가 있는 건가?
    • 도메인의 레코드에도 몇 가지 종류가 있다.
    • 가장 기본적인 것은 A Record로 해당 도메인과 서버의 IP 주소가 바로 매치되는 것이다.
    • 이외에도 CNAME이 있다. CNAME은 Canonical Name으로 원본 레코드 주소의 별칭 같은 것이다. 이때 원본 레코드는 IP주소이면 안되고 스킴 부분을 제외한 URL, 즉 순수 도메인 네임의 형태여야 한다.
    • MX 레코드는 메일 서버의 메일 주소 등록을 위해 사용한다.

일단 도메인 네임을 리졸브하고 나서 얻은 호스트 주소로 TCP 커넥션을 오픈하면(L4) 본격적인 데이터 교환이 시작된다. 브라우저가 보낸 GET 요청은 먼저 호스트측의 웹 서버에 닿을 것이다.

웹 서버는 GET 요청의 헤더를 차근차근 살펴본다. Host 헤더를 기준으로 요청을 역방향 프록시하는 경우가 많다.

  • Host 헤더란 어떤 것인가? 역방향 프록시는 또 뭔 소린가?
    • Host 헤더는 HTTP 1.1의 표준으로 채택된 요청 측 헤더 의 한 종류다.
    • HTTP 1.0 까지는 Host 헤더가 부재했고, 일단 DNS를 통해 호스트의 주소를 밝혀내고 나면 이 요청이 어떤 주소를 향하고 있었는지를 알 방법이 없었다. referer 등의 헤더로 우회 구현할 수는 있었지만 부족한 경우가 많았다.
    • 이 경우 req header의 URI 부분밖에 알 수가 없다(e.g. /home/user). HTTP 1.0 시대에는 이런 부족함이 문제가 안 됐을 수도 있다.
    • 그러나 한 서버에서 여러 웹 서비스를 호스팅하는 가상 호스팅 이 보편화되면서 이 부족함은 큰 불편함이 됐고 따라서 다음 표준에서 Host 헤더가 도입된 것이다.
    • Nginx를 기준으로 말씀드리면 server block을 정의할 때 명시하는 server_name 값이 이 Host 헤더의 내용과 비교되는 것이다.
    • 역방향 프록시란 이렇게 요청이 웹 서버까지 다 도달한 다음에야 다음 행선지로 요청이 넘어가는 방식을 말하는 것이다. 원래 네트워크에서 프록시란 클라이언트 측이 모든 요청을 특정한 행선지를 한 번 거쳐서 처리하게 설정하는 것을 말한다. 즉 지금 나가는 요청이 어디를 거쳐야하는지 클라이언트측에서 설정해야 하는 것이다. 이를 정방향 프록시 혹은 그냥 프록시라고 말한다. 그냥 프록시라고 많이 말하는 것 같다.
    • 그러나 이런 구현을 클라이언트 측에서는 모르게 하고 호스트의 웹 서버에 도달해서야 호스트 웹 서버가 프록시처럼 작동하는 일을 역방향 프록시라고 칭한다.

요청이 이제 웹 서버의 역방향 프록시를 거쳐 웹 애플리케이션 서버에 도달했다. 만약 요청이 정적 자원이라면 웹 서버가 해당 자원을 리스폰스하고 요청이 종료될 것이다.

  • 정적 자원이란?
    • 말 그대로 바뀌지 않는 자원, 즉 파일을 말한다. 첨부파일이나 그림 파일, 간단한 텍스트 등등….
    • 제 프로젝트에서도 Nginx의 정적 호스팅 기능을 사용하였다. 단순한 첨부파일 조회, 이미지 파일 조회 등의 기능을 WAS로 넘기지 않고 Nginx단에서 처리함으로써 서비스의 부하를 줄이고 응답 속도를 빠르게 하고자 했다.
    • 정적 자원 외에 동적 페이지, dynamic page가 있을 수 있다. 요청에 따라 응답 내용이 계속 바뀌어야 하는 경우엔 정적 호스팅으로 불충분하며 웹 애플리케이션 서버가 처리해줘야 한다.

만약 요청이 동적 응답을 요구한다면 앞서 말씀드린 역방향 프록시를 통해 웹 애플리케이션으로 요청을 전달해야 한다(L7). 애플리케이션은 요청을 열어보고 필요한 작업을 수행한 뒤 응답한다. 응답은 요청의 역순이다.

웹 브라우저는 돌려받은 HTML, CSS 등 파일을 한 줄 한 줄 열어보고 Gecko와 같은 레이아웃 엔진을 통해 화면을 그려낸다.

  • HTTP method 아는대로 설명해보세요.

GET, POST, PUT, PATCH, OPTIONS, DELETE…..

요청 헤더의 첫 줄, 가장 앞 칸에 HTTP 메소드가 명시된다. (GET /user/info)

중요한 것은 HTTP message의 형태차이는 GET과 POST 계열 두 가지만 있을 뿐이다. GET에서는 HTTP request body를 사용하지 않는다. POST 등 나머지에서는 본문이 존재한다. OPTIONS는 존재하지 않는다.

  • 상태 코드 아는대로 설명해보시오.

100번대 : 단순 정보

200번대: 요청 성공 코드. 200 OK

300번대: 변경 코드, 301 Moved Temporarily (Permanently), 302 Found, 304 Unchanged….

400번대: 요청측 오류 코드, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found

500번대: 서버측 오류 코드, 500 Internal Server Error, 503 Bad Gateway

  • TCP와 UDP의 차이점에 대해 서술하시오.

TCP는 느리고 UDP는 빠르다.

왜 이런 차이가 나는지 설명하겠다. TCP는 아시는 것처럼 핸드셰이크도 수행하고 패리티 비트도 있다.

커넥션이 열리기 전 3-way handshake를 수행해야 한다. 연결이 닫힐 때는 4-way다. 이런 식으로 연결 상태를 확인하며 받는 쪽이 받을 준비가 됐는지, 보내는 쪽이 정보를 다 보내고 연결이 끊어진건지를 확인하는 것이다.

정합성이 중요한 데이터를 주고받을때는 커다란 장점이지만 정합성보다 속도가 요구되는 상황에서는 치명적인 약점이다. 예를 들면 온라인 게임같은 상황이다. 한 두개의 패킷 로스가 발생하더라도 속도를 높게 유지하는 것이 이런 상황에선 더 도움이 된다. 이럴때는 UDP를 써야 한다.

온라인 게임에서는 UDP를 사용해 RTT를 최대한 낮추려고 노력한다. 그래도 충분하지 않아 소프트웨어적으로 보간 지연(interpolation delay)을 둬서 클라이언트-서버 양측의 시간차이를 보정하기도 한다.

  • OSI 7계층?

    • 1계층 : 물리 계층, RJ-45, RS-232 같은 규격들
    • 2계층 : 데이터 링크 계층
    • 3계층 : 네트워크 계층
    • 4계층 : 전송 계층
    • 5계층 : 세션 계층
    • 6계층 : 표현 계층
    • 7계층 : 응용 계층
  • HTTP 2.0의 특징에 대해 간단히 서술해 보시오.

HTTP2.0은 빠르다. 그리고 안전하다.

우선 안전한 이유부터 설명드리면 2.0부터는 TLS의 적용이 의무화된다. L6 ~ L7을 아우르는 표준이 됐기 때문에 L6에서의 TLS를 의무화시킬 수 있었다.

그리고 빠르다. 빠른 이유는 두가지가 있는데 스트림과 서버 푸시다.

하나의 요청이 끝나고 4방향 악수가 끝난 다음에야 통신이 종료되고 다음 통신으로 넘어가는 기존 규격과는 다르게 2.0은 스트림을 열어놓고 필요한 정보를 계속 요청하거나 수신할 수 있다. 이 과정에서 헤더는 압축되어 표현된다. 연결을 새로 수립하고 끊는 오버헤드를 절감할 수 있다.

그리고 서버 푸시도 중요한 기술이다. 클라이언트가 특정 경로로 요청을 보냈을 때 부가적으로 요청해야 할 것들(웹페이지를 예로 들면 CSS나 .js 파일들)을 서버가 미리 알아차리고 푸시해줄 수 있다. 이 과정에서도 오버헤드가 절감된다.