웹 서버는 HTTP 요청을 처리하고 응답을 제공한다.
웹 서버는
웹 서버 소프트웨어
와웹페이지 제공에 특화된 장비
모두를 가리킨다.
웹 서버 구현
웹 서버는 HTTP 및 그와 관련된 TCP 처리를 구현한 것이다.
웹 서버의 형태
다목적 소프트웨어 웹서버
주로 몇 가지 웹 서버 소프트웨어만이 널리 사용
2022년 version
임베디드 웹 서버
일반 소비자용 제품에 내장될 목적으로 만들어진 작은 웹 서버 → 간편한 웹 브라우저 인터페이스로 관리할 수 있게 해줌
일반적인 HTTP/1.1의 기능들을 지원하려면, 풍부한 리소스 지원, 가상 호스팅, 접근 제어, 로깅, 설정, 모니터링, 그 외 성능을 위한 각종 기능들이 필요하다.
대신 최소한으로 기능하는 HTTP 서버는 30줄 이하의 펄(perl) 코드로도 만들 수 있다. → 책에서는 type-o-serve
라는 예제를 사용. 자세한 코드는 책 참조(C, Python으로 만드는 소켓 서버와 비슷한 듯)
공통적으로 다음과 같은 일들을 수행한다.
클라이언트가 이미 서버에 열려있는 지속 커넥션이 있다면 그것을 사용하고 없다면 새 커넥션을 연다.
새 커넥션 다루기
서버는 클라이언트와 커넥션을 맺고 그 커넥션에서 IP 주소를 추출하여 어떤 클라이언트인지 확인한다. 그 이후, 새 커넥션을 커넥션 목록에 추가하고 어떤 데이터들이 오가는지 지켜보기 위한 준비를 하는데, IP 주소나 호스트 명이 인가되지 않았거나 악의적이라고 알려진 것인 경우 커넥션을 닫는다.
클라이언트 호스트 명 식별
웹 서버는 역방향 DNS를 사용해서 클라이언트의 IP 주소로부터 호스트 명을 변환하도록 하여 이를 구체적인 접근 제어와 로깅을 위해 사용할 수 있다.
호스트명 룩업은 웹 트랜잭션을 느려지게 할 수 있어서 대부분의 웹 서버에서 호스트 명 분석을 꺼두거나 특정 콘텐츠에 대해서만 켜둔다.
ident를 통해 클라이언트 사용자 알아내기
ident 프로토콜은 서버에게 어떤 사용자 이름이 HTTP 커넥션을 초기화했는지 찾아낼 수 있게 해준다. 일반적으로 113번 포트를 사용하고, 웹 서버 로깅에 유용하기 때문에, 널리 쓰이는 일반 로그 포맷의 두 번째 필드는 각 HTTP 요청의 ident 사용자 이름을 담고 있다.(보통 아파치에서 가용한 정보가 없는경우 -(하이픈)으로 채운다.)
그러나 공공 인터넷에서는 아래의 이유로 잘 동작하지 않는다.
요청 메시지 파싱시 요청 메서드, URI, 버전 번호를 찾으며, CRLF(캐리지 리턴 줄바꿈)를 기준으로 읽는다.
메시지의 내부 표현
몇몇 웹 서버는 요청 메시지를 쉽게 다룰 수 있도록 내부의 자료 구조에 저장하여 관리한다.
커넥션 입력/출력 처리 아키텍처
고성능 웹 서버는 수천 개의 커넥션을 동시에 열 수 있도록 지원하는데, 웹 서버의 아키텍처의 차이에 따라 요청을 처리하는 방식이 달라진다.
단일 스레드 웹 서버
한 번에 하나씩 요청, 심각한 성능 문제를 발생시켜 보통 로드가 적은 서버나 type-o-serve와 같은 진단도구에서만 작성
멀티프로세스와 멀티스레드 웹 서버
여러 개의 프로세스 혹은 고효율 스레드를 할당하는데 필요할때 혹은 미리 만들어짐으로써, 수많은 프로세스나 스레드는 너무 많은 메모리나 시스템 리소스를 소비한다.
따라서 보통 웹 서비스들은 최대 개수에 제한을 건다.
다중 I/O 서버
대량의 커넥션 지원을 위해 많은 웹 서버가 다중 아키텍처를 채택하였다. 실제로 해야 할 일이 있을 때, 커넥션에 대해 작업을 수행한다.
다중 멀티스레드 웹 서버
멀티스레딩과 다중화를 결합한것 → 여러 개의 스레드는 각각 열려있는 커넥션을 감시하고 각 커넥션에 대해 조금씩 작업 수행
HTTP 메서드에 따라 요청을 처리하는 단계
요청 메시지의 URI에 대응하는 콘텐츠를 식별하는 과정
Docroot
웹 서버 파일 시스템의 특별한 폴더이며 웹 콘텐츠를 위해 예약해 둔 것을 docroot라고 부른다.
이를 사용하는 과정에서 서버는 상대적인 url이 docroot이외 부분이 노출되는 일이 생기지 않도록 주의해야한다.
가상 호스팅된 docroot
가상 호스팅된 웹 서버는, 각 사이트에 그들만의 분리된 문서 루트를 주는 방법으로 한 웹 서버에서 여러 개의 웹 사이트를 호스팅한다.
서버는 두 웹 사이트를 HTTP Host 헤더나 서로 다른 IP 주소를 이용해 구분할 수 있다.(docroot 설정을 해주어야 함)
사용자 홈 디렉터리 docroots
사용자들이 한 대의 웹 서버에서 각자의 개인 웹 사이트를 만들 수 있도록 해주는 것으로, URI
는 사용자의 개인 문서 루트를 가리킨다.
디렉터리 목록
파일이 아닌 디렉터리 URL에 대한 요청을 받을 때 다음과 같은 행동을 취하도록 웹 서버를 설정할 수 있다.
모든 파일의 이름을 우선순위로 나열해주는 디렉터리 색인 파일 자동 생성 기능도 있고 웹서버에서 이를 끄고 킬수 있다.
동적 콘텐츠 리소스 매핑
아파치는 아래와 같은 기능들을 제공한다.
오늘날의 애플리케이션 서버는 서버사이드 동적 콘텐츠 지원기능을 갖고 있다.(ex: MS의 액티브 서버 페이지, 자바 서블릿)
서버사이드 인클루드
이 서버사이드 인클루드가 설정되어 있다면 서버는 그 리소스의 콘텐츠를 클라이언트에게 보내기 전에 처리한다.(동적 콘텐츠를 만드는 쉬운 방법)
접근 제어
웹 서버는 클라이언트의 IP 주소에 근거하거나 비밀번호를 요구하여 각각의 리소스에 접근 제어를 할당할 수 있다.
응답 메시지는 응답 상태코드, 응답 헤더, 응답 본문을 포함한다.
응답 엔터티
응답 본문이 있다면 주로 아래의 내용을 포함한다.
MIME 타입 결정하기
리다이렉션
웹 서버는 요청을 수행하기 위해 브라우저가 다른 곳으로 가도록 리다이렉트 할 수 있다.
서버는 커넥션 상태를 추적하여 비지속적인 커넥션이면 메시지 전송후 커넥션을 닫는다.
지속적인 커넥션이면 Content-length 헤더를 바르게 계산하기 위해 특별한 주의를 필요로 하는 경우가 있을 수 있다. 또한 클라이언트가 응답이 언제 끝나는지 알 수 없는 경우에 커넥션은 열린 상태를 유지한다.
트랜잭션 완료 시 로그를 로그파일에 기록
송신측과 수신측의 데이터 처리 속도 차이를 해결하기 위한 기법
수신측에서 받을 수 있는 데이터 양보다 더 많은 데이터가 들어오면 초과된 데이터들이 손실될 수 있다.
1. Stop and Wait
매번 전송한 패킷에 대해 확인응답을 받아야만 그 다음 패킷을 전송하는 방법
패킷을 하나씩 보내기 때문에 비효율적이다.
2. Sliding Window
수신측에서 설정한 윈도우 크기만큼 송신측에서 확인응답 없이 세그먼트를 전송할 수 있게 하여 흐름을 동적으로 조절하는 기법
윈도우에 포함된 패킷을 계속 전송하고, 수신 측으로부터 확인 응답이 오면 윈도우를 옆으로 옮겨 다음 패킷들을 전송한다.
재전송
수신 측으로부터 확인 응답을 받지 못하면, 패킷을 재전송한다.
보통 타이머를 이용해 구현한다.
송신측의 데이터 전달과 네트워크 데이터 처리 속도를 해결하기 위한 기법이다.
→ 발생하는 원인으로 한 라우터에 데이터가 몰릴 경우 데이터를 모두 처리하지 못해 재전송하면서 혼잡을 가중시켜 오버플로우 혹은 데이터 손실을 발생시킨다. 따라서 이러한 네트워크 혼잡을 피하기 위해 송신측에서 보내는 패킷 수를 조절하는 작업을 혼잡제어라고 한다.
혼잡제어기법
혼잡 제어 정책
혼잡이 발생하면 윈도우 크기를 줄이거나, 혹은 증가시키지 않으며 혼잡을 회피한다
라는 전제를 깔고 있다.
가장 유명한 정책 2가지 Tahoe
와 Reno
이고 기본적은로 처음에 Slow Start
정책을 사용하다가 네트워크가 혼잡하다고 느껴졌을 때는 AIMD
방식으로 전환하는 방법을 사용한다.
3 ACK Duplicated
혹은 Timeout
이라는 2가지 시나리오가 발생하면 윈도우의 크기를 줄이게 된다.
또한 ssthresh
라는 Slow Start 임계점
이 존재하고 이는 여기까지만 slow start
를 사용하겠다는 의미이다.
Tahoe
Slow Start
를 사용하여 자신의 윈도우 크기를 지수적으로 증가시키다가 sshtresh
를 만난 이후부터는 AIMD
에서 사용하는 합 증가 방식을 사용한다. 또한 sshtresh
를 혼잡이 발생할 때마다 그의 반으로 설정한다.
그러나 윈도우 크기를 다시 1로 변경하기 때문에 윈도우 크기를 키울 때 너무 오래걸린다는 것이 단점이다. 그래서 나온 방법이
빠른 회복 방식
을 활용한TCP Reno
이다.
Reno
3 ACK Duplicated
를 만났을 때 윈도우의 크기를 반으로 줄이고, Timeout
을 만났을 때 윈도우 크기를 1로 만든다. 그러나 sshtresh
는 3 ACK Duplicated
가 일어났을 때만 반으로 줄인다.
훼손된 패킷을 감지하고 손실된 패킷은 재전송하고, 순서에 맞지 않는 세그먼트를 버퍼에 저장하는 일을 한다.
Stop And Wait
송신 측에서 패킷을 보내고 보낸 패킷에 대한 응답이 오면 다음 패킷을 보냄
그러나 Sliding Window 기법을 사용하면 데이터를 연속적을 보내는 방식이라 의미가 없음 따라서 재전송 기반의 오류 제어, ARQ(Automatic Repeat Request)를 사용!
ARQ
TCP는 기본적으로 재전송 기반의 오류 제어를 사용하지만, 수 많은 데이터를 주고 받아야 하는 상황에서 이 방법은 비효율적이기 때문에 이러한 재전송을 최대한 적게하는 방식으로 TCP는 오류를 제어한다.
1. Go-Back-N
여러개의 데이터를 연속적으로 보내다가 오류가 발생한 데이터부터 다시 재전송하는 방식
이미 수신한 데이터를 폐기하고 다시 재전송해야한다는 단점
2. Selective Repeat
오류가 발생한 데이터만 골라서 재전송하는 방식
송신측은 오류가 발생한 패킷만 재전송하는데, 수신측의 버퍼에 순서가 보장되지 않는다는 단점이 존재한다. 그렇기 때문에
재정렬
이 필요하고 이는 또 다른 버퍼 공간을 필요로 한다.
https://velog.io/@jsj3282/TCP-흐름제어혼잡제어-오류제어#5-tcp의-제어-3--혼잡제어
https://steady-coding.tistory.com/507
https://gyoogle.dev/blog/computer-science/network/흐름제어 & 혼잡제어.html