열렬히.뛰기

5. 웹 서버

네트워크 > HTTP 완벽 가이드 > HTTP 완벽 가이드 > 5. 웹 서버

웹 서버란?

사용자가 웹 브라우저를 통해 요청한 웹 리소스를 제공하는 서버.

흔히 말하는 웹 서버에는 크게 2가지 의미가 있다.

  • 웹 서버를 위한 소프트웨어 (아파치, Nginx 등등)
  • 웹 서버를 위한 각종 하드웨어 장비

여기서 말하는 웹 서버는 소프트웨어를 의미한다.

웹 서버의 특징

  • 리소스에 대한 HTTP 요청을 받아서 콘텐츠를 클라이언트에게 돌려줌
  • HTTP 프로토콜을 구현하고, 웹 리소스를 관리.
  • TCP 커넥션에 대한 책임을 운영체제와 나눠 가짐

웹 서버가 하는 일

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

1. 커넥션 맺기

클라이언트 커넥션 수락

새 커넥션 다루기

클라이언트가 웹 서버에 TCP 커넥션을 보내면, 웹 서버는 커넥션을 맺는다.

이때, TCP에서 IP 주소를 추출해 클라이언트가 누구인지 확인한다.

웹서버는 언제든지 커넥션을 거절하거나 닫을 수 있다.

클라이언트 알아내기

  1. 역방향 DNS를 통해 클라이언트의 IP주소를 클라이언트의 호스트명으로 변경
  • 영어로는 hostname lookup이라고 함.
  • 이를 가지고 접근 제어 및 로깅에 사용할 수 있음.
  • 그러나 꽤 시간이 많이 걸리고, 웹 트랜잭션이 느려질 수 있음.
  • 따라서 클라이언트를 알아내는 과정을 끄거나, 일부 콘텐츠에서만 사용.
  1. IETF ident 프로토콜을 사용해 이를 알아내기도 함.

서버에게 어떤 사용자 이름이 HTTP 커넥션을 초기화했는지 찾을 수 있게 해줌.

  • 클라이언트가 연결을 시도할 때 서버에게 IDENT 요청을 보내고, 서버는 클라이언트의 사용자 정보를 응답하는 방식.
  • 이때, 호스트명 정보도 얻을 수 있다.

단, ident는 더 이상 많이 사용되지 않는다.

  1. 많은 클라이언트 pc가 ident 데몬 소프트웨어를 실행하지 않음
  2. ident 프로토콜은 http 트랜잭션을 지연시킴
  3. 방화벽이 ident 프로토콜을 막음
  4. ident 프로토콜은 보안상 문제가 많고, 가상의 ip 주소를 지원하지 않음.

2. 요청 메시지 받기

메시지를 받는 방식에도 여러가지가 존재한다.

소켓 프로그래밍의 관점에서, 커넥션 == 소켓이라고 할 수 있음.

커넥션 입출력 다루기

  • 단일 쓰레드 : 한번에 1개의 커넥션 지원
  • 다중 쓰레드 / 프로세스 : 한번에 여러개의 커넥션 지원
    • 단, 프로세스나 쓰레드를 커넥션마다 만들어야 하기 때문에 자원 소모가 크다.
  • 다중 I/O (멀티플랙싱)
    • 다중 쓰레드 / 프로세스의 단점을 해결하기 위한 조치
    • 하나의 프로세스(쓰레드)가 다수의 커넥션을 다루는 것
    • select(), poll(), kqueue()가 이걸 위한 함수
  • 다중 I/O (멀티플랙싱) + 다중 쓰레드 / 프로세스
    • 둘의 이점을 결합한 모습
    • 여러개의 쓰레드가 각각 열려있는 커넥션을 감시
    • 조금씩 작업을 수행.

3. 요청 처리

요청 메시지를 받은 후, 이를 파싱한다.

javascript
요청줄 파싱 
	- 요청 메소드, URI, 버전 번호를 알아냄
	- 각 값은 스페이스 1개로 분리되어 있음.
	- 요청줄은 \r\n (=캐리지 리턴 줄바꿈)으로 끝남.

메시지 헤더 파싱
	- 각 메시지 헤더는 \r\n (=캐리지 리턴 줄바꿈)으로 끝남.

요청 본문 파싱
	- 길이는 메시지 헤더 중 Content-Length로 정의됨.

파싱 후 이를 쉽게 다룰 수 있도록 적합한 자료구조에 저장.

이후 메소드, 리소스, 헤더, 본문을 이용해 처리

4. 리소스 접근

웹 서버에서 클라이언트에게 줄 리소스에 접근하는 과정

URI로 파일 찾기

URI == 웹 서버 안의 파일이름

이 경우 문서 루트(docroot)라는 특별한 폴더를 준비하고, URI를 파싱한 뒤 docroot 뒤에 붙인다.

javascript
URI 파싱 결과 : /specials/photo-this-year
docroot : /usr/local/httpd

파일 경로 : /usr/local/httpd/specials/photo-this-year

해당 파일을 찾은 뒤 반환

docroot 외의 폴더는 못 들어가게 막아야 한다. (보안을 위해서)

docroot를 이용해서 클라이언트 개개인의 웹사이트를 만들 수 있게 할 수도 있다. (ex. 개인 블로그)

URI가 디렉토리(폴더)라면?

크게 3가지 대응을 할 수 있다.

  1. 에러 반환
  2. 디렉터리 대신 특별한 ‘색인 파일’ 반환
  3. 디렉터리를 탐색해서 그 내용을 담은 html 페이지를 반환

특별한 ‘색인 파일’ 반환 : index.html 같은 것.

동적 콘텐츠 : CGI

웹 서브 안에서 콘텐츠 파일을 찾는 것이 아닌, 웹 서브 - 리소스용 프로그램 - 콘텐츠로 연결된 구조.

이럴 때 웹서버의 요청을 받아 콘텐츠를 줄 수 있는 무언가를 CGI(커먼 게이트웨이 인터페이스)라고 한다.

CGI 장점

  • 언어, 플랫폼 독립적이다(스펙만 준수하면 된다).
  • 매우 단순하고 다른 server-side 프로그래밍 언어에 비해 advanced task를 훨씬 쉽게 수행할 수 있다.
  • 재사용할 수 있는 CGI 코드 라이브러리가 풍부하다.
  • CGI가 웹서버에서 실행될 때 안전하다.
  • CGI 코드를 수행하는데 특정 라이브러리가 필요하지 않기 때문에 매우 가볍다.

CGI 단점

  • 느리다(요청이 올 때마다 DB connection을 새로 열어야 한다).
  • HTTP 요청마다 새로운 프로세스를 만들기 때문에 서버 메모리를 많이 잡아먹는다.(servlet은 요청마다 스레드를 만든다.)
  • 페이지 로드 사이에 데이터가 메모리에 캐시될 수 없다.

동적 콘텐츠 : SSI

서버 사이드 인클루드(SSI) : 서버 측 데이터(Server-Side)를 가진 변수들을 HTML에 포함(Includes) 시키는 것

어떠한 리소스가 서버사이드 인클루드를 포함하고 있으면, 서버는 그 리소스의 콘텐츠를 클라이언트에 보내기 전에 처리. 서버는 콘텐츠에 변수나 내장된 스크립트가 될 특별한 패턴이 있는지 검사.

5단계 : 응답 만들기

다시 보낼 응답 메시지를 만드는 과정.

javascript
HTTP/1.1 200 OK
Date: Thu, 12 Jan 2023 12:00:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 100
Connection: close

<html>
<head>
<title>HTTP Response Example</title>
</head>
<body>
This is an example of an HTTP response message.
</body>
</html>

응답 엔티티

응답 메시지에는 다음을 포함한다.

  • MIME 타입을 서술하는 Content-type
  • 길이를 서술하는 Content-Length
  • 실제 응답 본문

MIME 타입

mime 타입과 리소스를 연결시키는 방법들을 알아보자.

javascript
1. mime.types : 확장자별 mime 타입이 담겨 있는 파일을 탐색
2. magic typing : 아파치 웹 서버가 사용하는 방법. 파일 내용을 검사 후 패턴을 찾는다.
3. explicit typing : 특정 파일이 파일 확장자나 내용에 상관없이 어떤 mime 타입을 갖도록 
	웹 서버를 설정할 수 있다.

4. type negotiation : 사용자와의 협상을 통해 가장 좋은 mimo 형식을 찾는 것.

리다이렉션

성공 메시지 대신 리다이렉션 응답을 반환할 수도 있다. 이를 통해 브라우저가 다른 곳으로 가도록 유도할 수 있음.

이럴 때 리다이렉션의 응답은 300번대 상태 코드로 지칭된다. Location 응답 헤더는 콘텐츠의 새로운 혹은 선호

하는 위치의 URI를 포함함.

다음과 같은 경우 리다이렉션이 유용하다.

javascript
1. 리소스가 영구히 옮겨진 경우
2. 임시로 리소스가 옮겨진 경우
3. URL 증강
4. 부하 균형
5. 친밀한 다른 서버가 있을때 : 서버 -> 서버로 연결
6. 디렉터리 이름 정규화 : 빗금(/)을 빠트린 경우 이를 합친 URI로 리다이렉트

6단계 : 응답 보내기

요청을 받는 것과 비슷한 과정.

7단계 : 로깅

서버나 프락시의 문제를 찾거나, 웹 사이트 접근 통계를 내기 위해 로깅을 함

보통은 트랜잭션의 기본적인 항목을 로깅. (메서드, HTTP 버전, 리소스의 URL, HTTP 상태코드, 요청과 응답의 크기 등등)

로깅을 위한 다양한 로그 포맷이 존재 (ex. 일반 로그 포맷, 혼합 로그 포맷, 넷스케이프 확장 로그 포맷 등등)