[HTTP 완벽 가이드] 5장. 웹 서버

밈무·2023년 1월 21일
0

HTTP완벽가이드

목록 보기
5/14
  • 여러 종류의 소프트웨어 및 하드웨어 웹 서버에 대해 조사한다.
  • HTTP 통신을 진단해주는 간단한 웹서버를 펄로 작성해본다.
  • 어떻게 웹서버가 HTTP 트랜잭션을 처리하는지 단계별로 설명한다.

5.1 다채로운 웹서버

웹 서버는 리소스에 대한 HTTP 요청을 받아 콘텐츠를 클라이언트에게 돌려준다.

5.1.1 웹서버 구현

웹서버는 HTTP 및 그와 관련된 TCP 처리를 구현한 것이다. 웹 서버는 자신이 제공하는 리소스를 관리하고 웹 서버를 설정, 통제, 확장하기 위한 관리 기능을 제공한다.
웹 서버는

  • HTTP 프로토콜을 구현하고,
  • 웹 리소스를 관리하고,
  • 웹 서버 관리 기능을 제공하고
  • TCP 커넥션에 대한 관리를 운영체제와 나눠 갖는다.

    운영체제 역할

    • 컴퓨터 시스템의 하드웨어 관리
    • TCP/IP 네트워크 지원
    • 웹 리소스를 유지하기 위한 파일 시스템
    • 현재 연산 활동을 제어하기 위한 프로세스 관리

5.1.2 다목적 소프트웨어 웹 서버

다목적 소프트웨어 웹서버는 네트워크에 연결된 표준 컴퓨터 시스템에서 동작한다. 거의 모든 컴퓨터와 운영체제에서 동작한다.

  • 마이크로소프트 웹서버
  • 아파치 웹서버
  • nginx 서버

5.1.3 임베디드 웹 서버

임베디드 웹 서버는 일반 소비자용 제품에 내장될 목적으로 만들어진 작은 웹 서버이다. (ex. 프린터, 가전제품) 사용자가 그들의 일반 소비자용 기기를 간편한 웹 브라우저 인터페이스로 관리할 수 있게 해준다.
아주 작고, 최소한의 기능만을 제공해준다.

5.2 간단한 펄 웹 서버

최소한으로 기능하는 HTTP 서버는 30줄 이하의 펄 코드로도 만들 수 있다. (부가적인 기능을 지원하고 HTTP/1.1 기능을 제공하려면 훨씬 커진다)
책에는 type-o-serve(HTTP 디버깅을 위해 사용) 라는 작은 펄 프로그램이 등장한다. 프로그램은 다음과 같은 순서로 동작한다.
1. 명령줄에서 덮어쓰지 않는 이상 8080포트를 기본으로 사용한다.
이미 80번 포트로 수신하고 있는 웹 서버를 가지고 있기 때문에, 관리자는 type-o-serve 서버를 8080번 포트(사용하지 않는 아무 포트)로 시작한다.
2. 로컬 TCP 소켓을 생성하고 커넥션을 기다리도록(listen) 설정한다.
3. 시작 메시지를 출력한다.
4. 커넥션을 기다린다.
5. 누구로부터의 커넥션인지 출력한다.
6. 빈줄이 나올 때까지 HTTP 요청 메시지를 읽어서 화면에 출력한다.
7. 응답메시지를 위한 프롬포트를 만고 응답줄을 입력 받고, 입력된 줄을 클라이언트에게 보낸다.
8. 브라우저는 응답메시지의 본문을 출력한다.

5.3 진짜 웹 서버가 하는 일

  1. 커넥션을 맺는다.
    클라이언트의 접속을 받아들이거나, 원치 않는 클라이언트라면 닫는다.
  2. 요청을 받는다.
    HTTP 요청 메시지를 네트워크로부터 읽어들인다.
  3. 요청을 처리한다.
    요청 메시지를 해석하고 행동을 취한다.
  4. 리소스에 접근한다.
    메시지에서 지정한 리소스에 접근한다.
  5. 응답을 만든다.
    올바른 헤더를 포함한 HTTP 응답메시지를 생성한다.
  6. 응답을 보낸다.
    응답을 클라이언트에게 돌려준다.
  7. 트랜잭션을 로그로 남긴다.
    로그 파일에 트랜잭션 완료에 대한 기록을 남긴다.

다음부터 이런 기본 작업을 어떻게 웹 서버가 수행하는지 알아보자.

5.4 단계 1 : 클라이언트 커넥션 수락

클라이언트가 이미 서버에 대해 열려있는 지속적 커넥션을 갖고 있다 -> 그 커넥션을 사용할 수 있다.
그렇지 않다. -> 새 커넥션을 열어야 한다. (4장)

5.4.1 새 커넥션 다루기

클라이언트가 웹 서버에 TCP 커넥션을 요청하면 웹 서버는 그 커넥션을 맺고 TCP 커넥션에서 IP 주소를 추출해서 커넥션 맞은 편에 어떤 클라이언트가 있는지 확인한다.
일단 새 커넥션이 맺어지고 받아들여지면, 서버는 새 커넥션을 커넥션 목록에 추가하고 커넥션에서 오가는 데이터를 지켜보기 위한 준비를 한다.
웹 서버는 어떤 커넥션이든 마음애로 거절하거나 즉시 닫을 수 있다.
어떤 웹 서버들의 경우 클라이언트의 IP 주소나 호스트명이 인가되지 않았거나 악의적이라고 알려진 것인 경우 커넥션을 닫는다. 다른 신원 식별 기법 또한 사용될 수 있다.

5.4.2 클라이언트 호스트명 식별

  • 대부분의 웹서버는 역방향 DNS를 사용해서 클라이언트의 IP 주소를 클라이언트의 호스트 명으로 변환하도록 설정되어 있다.
  • 웹 서버는 클라이언트 호스트 명을 구체적인 접근 제어와 로깅을 위해 사용할 수 있다.
  • 호스트명 룩업은 웹 트랜잭션을 느려지게 할 수 있다. 많은 대용량 웹 서버는 호스트명 분석을 꺼두거나 특정 콘텐츠에 대해서만 켜놓는다.

5.4.3 ident를 통해 클라이언트 사용자 알아내기

  • 몇몇 웹서버는 또한 IETF ident를 지원한다. ident 프로토콜은 서버에게 어떤 사용자 이름이 HTTP 커넥션을 초기화했는지 찾아낼 수 있게 해준다.
  • 클라이언트가 ident프로토콜을 지원한다면 클라이언트는 ident 결과를 위해 TCP 포트 113 번을 listengksek.
  • 과정
  1. 클라이언트는 HTTP 커넥션을 연다.
  2. 서버는 자신의 커넥션을 클라이언트의 identd 서버포트(113)을 향해 연다
  3. 서버는 새 커넥션(클라이언트와 서버 포트 번호로 지정)에 대응하는 사용자 이름을 묻는 간단한 요청을 보낸다.
  4. 클라이언트는 ident 응답을 보낸다.

    위와 같은 이유로 ident는 조직 내부에서는 잘 사용할 수 있지만, 공공인터넷에서는 잘 동작하지 않는다.

5.5 단계2 : 요청 메시지 수신

커넥션에 데이터가 도착하면, 웹 서버는 네트워크 커넥션에서 그 데이터를 읽어들이고 파싱해서 요청 메시지를 구성한다.
요청 메시지 파싱 시 웹 서버가 하는 일은 다음과 같다.

  • 요청줄 파싱해서 요청 메서드, URI, 버전 번호 찾는다.
  • 메시지 헤더들을 읽는다.
  • 헤더의 끝을 의미하는 CRLF로 끝나는 빈줄을 찾아낸다.
  • 요청 본문이 있다면, 읽어들인다. (길이는 Content-Length 헤더로 정의)

또한, 웹 서버는 파싱해서 이해 가능한 수준의 분량을 확보할 때까지 데이터를 네트워크로부터 읽어서 메시지 일부분을 메모리에 임시로 저장해둔다.

5.5.1 메시지의 내부 표현

요청 메시지를 쉽게 다룰 수 있도록 내부의 자료구조에 저장한다.
예를 들어 요청 메시지의 각 조각에 대한 포인터와 길이를 담을 수 있고, 헤더는 속도가 빠른 룩업 테이블에 저장되어 각 필드에 신속하게 접근할 수 있다.

5.5.2 커넥션 입/출력 처리 아키텍처

요청은 언제라도 도착할 수 있기 때문에 웹 서버들은 항상 새 요청을 주시한다.
웹 서버의 아키텍처의 차이에 따라 요청을 처리하는 방식도 달라진다.

단일 스레드 웹 서버

단일 스레드 웹 서버는 한번에 하나씩 요청을 처리한다. 트랜잭션이 완료되면 다음 커넥션을 처리된다. 처리 도중 모든 다른 커넥션을 무시해 심각한 성능문제를 만들어내기 때문에 로드가 적은 서버나 type-o-serve같은 진단도구에서만 사용한다.

멀티프로세서와 멀티스레드 웹서버

여러 요청을 동시에 처리하기 위해 여러 개의 프로세스 혹은 고효율 스레드를 할당한다. 서버가 엄청 많은 동시 커넥션을 처리할 때 그로인해 만들어진 수많은 프로세스나 스레드가 너무 많은 메모리나 시스템 리소스를 소비할 수 있기 때문에 스레드/프로세스의 최대 개수에 제한을 거는 멀티스레드 웹서비스가 많다.

다중 I/O 서버

대량의 커넥션을 지원하기 위해 많은 웹 서버가 다중 아키텍처를 채택했다. 다중 아키텍처에선 모든 커넥션은 동시에 그 활동을 감시당한다. 어떤 커넥션에 대해 작업을 수행하는 것은 그 커넥션에 실제로 해야할 일이 있을 때뿐이다. 스레드와 프로세스는 유휴 상태의 커넥션에서 기다리느라 리소스를 낭비하지 않을 수 있다.

다중 멀티스레드 웹서버

멀티 스레딩과 다중화를 결합해 여러 개의 CPU를 사용하는 것의 이점을 살린다. 여러 개의 스레드는 각각 열려있는 커넥션을 감시하고 각 커넥션에 대해 조금씩 작업을 수행한다.

5.6 단계3 : 요청처리

5.7 단계4 : 리소스의 매핑과 접근

웹서버가 클라이언트에 콘텐츠를 전달하려면, 그전에 요청 메시지의 URI에 대응하는 알맞은 콘텐츠나 콘텐츠 생성기를 웹 서버에서 찾아 그 콘텐츠의 원천을 식별해야 한다.

5.7.1 Docroot

  • 리소스 매핑의 가장 단순한 형태는 요청 URI를 웹 서버의 파일 이름으로 사용하는 것
  • 웹 서버 파일 시스템의 특별한 폴더를 웹 콘텐츠를 위해 예약해두는데, 이 폴더를 docroot이라고 부름
  • 웹 서버 내부 설정에서 문서 루트를 설정 가능
  • 상대적인 url이 docroo를 벗어나 파일 시스템의 docroot 이외 부분이 노출되는 일이 생기지 않도록 해야한다. 예를 들어 대부분의 성숙한 웹 서버는 문서루트 위의 파일을 보려고 하는 URI를 허용하지 않음(http://www.joes.com/../)

가상 호스팅된 docroot

각 사이트에 그들만의 분리된 문서루트를 줘서 한 웹 서버에서 여러 개의 웹사이트를 호스팅한다.
IP주소나 호스트명을 통해 올바른 문서루트를 식별하도록 해서 하나의 웹 서버 위에서 두개의 사이트가 완전히 분리된 콘텐츠를 갖고 호스팅되도록한다.

사용자 홈 디렉터리 docroots

사용자들이 한 대의 웹서버에서 각자의 개인 웹 사이트를 만들 수 있도록 해줄 수 있다. (사용자 별로 다른 docroot)

5.7.2 디렉터리 목록

웹 서버는 경로가 파일이 아닌 디렉터리를 가리키는 디렉터니 url 에 대한 요청을 받을 수 있다.
보통 index.html이나 index.htm을 찾는다.

5.7.3 동적 콘텐츠 리소스 매핑

웹 서버는 URI를 동적 리소스에 매핑할 수도 있다. 요청에 맞게 콘텐츠를 프로그램에 생성하는 URI을 매핑하는 것이다.
웹 서버 중에서 웹 애플리케이션 서버(WAS)라고 불리는 것들은 이런 식으로 웹 서버를 복잡한 백엔드 애플리케이션과 연결하는 일을 한다.

5.7.4 서버사이드 인클루드(SSI)

과거 JSP에서 많이 사용하던 아래와 같은 방식

<%@ include file="포함할 파일"%>

이걸 웹 서버에서 클라이언트에 보내기 전에 검사하여 실제 값으로 치환해준다. 이는 동적 컨텐츠를 만드는 쉬운 방법이다.

5.7.5 접근 제어

리소스에 대한 접근 제어. 클라이언트의 IP주소에 의해 제어하거나, 비밀번호를 물어볼 수 있다.

5.8 단계5 : 응답만들기

응답상태코드, 응답헤더, 응답본문(생성되었다면)

5.8.1 응답 엔터티

만약 본문이 있다면 주로

  • Content-Type : 응답 본문의 MIME 타입 서술
  • Content-Length : 응답 본문의 길이를 서술
  • 응답 본문의 내용
    을 포함한다.

5.8.2 MIME 타입 결정

웹서버가 이 타입을 결정해야 한다. 다음은 리소스와 MIME 타입 연결하는 방법들.

mime.type

MIME 타입을 나타내기 위한 파일 이름의 확장자. 이런 확장자 기반 타입 연계가 가장 흔하다.

매직 타이핑

파일의 내용을 검사해서 알려진 패턴에 대한 테이블에 해당하는 패턴이 있는지 찾아본다. 느리지만 표준 확장자가 없는 경우에 편리하다. (아파치)

유형 명시(Explicit Typing)

파일 확장자나 내용에 상관없이 어떤 MIME 타입을 갖도록 설정.

유형 협상(Type Negotiation)

어떤 웹 서버는 한 리소스가 여러 종류의 문서 형식에 속하도록 설정.
협상 과정을 통해 사용하기 가장 좋은 형식을 판별할 것인지 여부도 설정 가능. 특정 파일이 특정 타입을 갖도록 설정 가능.

5.8.3 리다이렉션

종종 성공 메시지가 아닌 리다이렉션 응답 반환. 요청 수행위해 브라우저가 다른 곳으로 가도록 리다이렉트할 수 있다.(3XX)
Location 헤더로 리다이렉트할 위치에 대한 URI를 포함.
다음의 경우 유용.

영구히 리소스가 옮겨진 경우

301 Moved Permanently

임시로 리소스가 옮겨진 경우

이름 변경이 임시적이기 때문에 서버는 클라이언트가 나중에는 원래 URI로 찾아오고 북마크도 갱신하지 않기를 원한다.
303 See Other, 307 Temporary Redirect

URI 증강

문맥 정보를 포함시키기 위해 재작성된 URL 로 리다이렉트.
클라이언트는 리다이렉트를 따라가 상태정보가 추가된 완전한 URL을 포함한 요청을 다시 보낸다.
이것은 트랜잭션 간 상태를 유지하는 방법
303 See Other, 307 Temporary Redirect

부하 균형

과부하된 서버가 요청 받는 경우 덜 부하가 걸린 서버로 리다이렉트

친밀한 다른 서버가 있을 때

클라이언트에 대한 정보를 가지고 있는 다른 서버로 리다이렉트

디렉터리 이름 정규화

디렉터리 이름에 대한 URI 요청하는데 끝에 빗금 빠뜨리면 상대경로의 정상적 동작을 위해 끝애 /를 추가한 URI로 리다이렉트

5.9 단계6 : 응답 보내기

  • 비지속적인 커넥션 - 모든 메시지를 전송 후 서버 쪽에서 커넥션을 닫음
  • 지속 커넥션 - 서버가 Content-Length 헤더를 바르게 계산하기 위해 특별한 주의를 필요로 하는 경우 / 클라이언트가 응답이 언제 끝나는지 알 수 없는 경우 커넥션을 열린 상태로 유지

5.10 단계7 : 로깅

트랜잭션이 완료되었을 때 웹서버는 트랜잭션이 어떻게 수행되었는지 로그를 로그파일에 기록한다.

0개의 댓글