개념과 구조
응용 계층에 존재하는 응용 프로그램은 다음 두 가지 형태로 존재하며 각각의 특징은 다음과 같다.
Client-server 구조
서버의 특징
- 항상 실행되고 있다.
- 영구적으로 할당된 IP를 가짐
- 확장을 위한 데이터 센터가 존재
클라이언트의 특징
- 서버와 통신
- 클라이언트간의 직접적인 통신을 하지 않음
- 간혈적인 연결 (연결과 끊김이 반복적이고 규칙적이지 않다.)
- 대부분 동적 IP를 사용
Peer-to-peer 구조
- 항상 켜져있는 서버가 존재하지 않음
- 임의의 클라이언트와 직접적인 통신
- Peer는 클라이언트이자 서버의 역할을 한다.
- 데이터를 수신하고 때로는 제공하는 임무를 가진다.
- 따라서 Peer가 증가하면 성능적인 확장성이 가능하다.
- Peer는 간혈적인 연결 상태를 가지며, IP 주소가 변경이 가능하다
- 통신이 항상 원활하고 지속적인 통신이 가능하다는 보장이 없고
- Peer들의 관리가 힘들다
따라서 인터넷에서 통신하기 위해선 클라이언트 프로세스와 서버 프로세스가 존재해야한다. 그리고 각 프로세스는 message를 다른 프로세스에게(으로 부터) 송수신하기 위해선 전송 계층에 전달할 필요가 있고, 응용 계층과 전송 계층의 통로가 Socket
이라 한다. 때문에 소켓으로 전달되는 메세지는 IP를 통해 인터넷에 퍼져있는 목적지를 특정할 수 있고, 목적지 내부에 프로세스를 특정하는 것이 포트 번호
이다.
응용 계층의 프로그램은 전송 계층으로부터 전송을 요청하는데 이런 프로그램은 서비스마다 필요로하는 요구사항이 나뉘게 된다.
- 데이터 무결성
- 파일 전송, 웹등은 데이터의 무결성이 깨지면 서비스의 존재 의미가 사라진다. 때문에 전송 계층으로 부터 모든 데이터가 정확히 들어왔는지가 중요하다
- 응답 시간
- 인터넷 통화, 게임과 같은 서비스는 전송된 데이터가 일정한 시간 내에 목적지에 도착이 보장되어야 서비스가 유지된다.
- 처리량
- 멀티미디어 스트리밍같은 경우 단위 시간 내에 일정 프레임이 도착됨이 보장되어야 서비스가 끊김없이 유지된다.
- 보안
- 앞서 데이터 무결성과 보안이 중요한 서비스
프로토콜
전송 계층에서 제공하는 서비스의 종류
TCP
- 송신을 하는 두 프로세스간의 전송의 신뢰성 보장
- 데이터 전송 흐름 제어 (송수신간의 데이터 흐름을 제어, 너무 빠른 송신을 하면 수신쪽 버퍼에 가득찰 경우 데이터 손실일 막음)
- 두 프로세스간의 연결 수립
- 혼잡 제어 (네트워크 상황에 따라서 송신을 제어)
UDP
- 송신을 하는 두 프로세스간의 전송을 신뢰성을 보장하지 않음
인터넷 전송 프로토콜은 두 개의 서비스를 제공하는데 UDP의 경우 TCP에 비해 많은 부분이 부족하지만 TCP의 통신 프로세스간의 연결 수립의 비용을 줄이고, 프로세스 내에서 수신 데이터 무결성을 검사한다면 TCP와 동일한 작업을 하게 된다. 또 TCP의 경우 네트워크 상황에 따라서 단위 시간 수신량이 보장되어야 하는 경우에도 의도하지 않게 전송 계층에서 수신량이 제한되게 된다.
다음은 응용 계층 프로토콜에서 정의되어야 하는 항목에 대해서 알아보자
- 교환하는 메세지의 종류
- e.g., request, response
- 메세지의 문법
- 메세지에 어떤 필드가 있고 각 필드간의 구분을 정의
- 메세지의 해석 방법
- 필드들이 무엇을 의미하는지
- 송수신간의 규칙
웹과 HTTP(Hypertext transfer protocol)
HTTP는 Client-Server 구조를 가지며 클라이언트 브라우저를 통해 서버에 접속하고 웹서버는 요청을 받고 응답을 보내주게 된다. 이와 같이 프로토콜을 통해서 통신하게 되면 어떤 디바이스인지, 프로세스에 상관없이 HTTP 프로토콜을 정의에 따라서 통신이 가능하다.
HTTP 프로토콜은 데이터 무결성이 중요한 TCP를 사용해 통신하며 서버는 80포트를 사용하게 된다. 여기서 중요한 점은 HTTP는 동일한 사용자의 요청이라도 모두 각각의 연관성이 없는 개별적인 요청으로 처리하는 stateless 방식으로 통신한다. 만약 HTTP를 stateful하게 만들려면 많은 개발 비용과 자원이 필요하기 때문에 많은 프로토콜은 stateless하게 동작한다.
Non-persistent HTTP
하나의 요청에 대해 완료 시점에서 통신을 닫음
- 1) 클라이언트는 목적지 주소(IP, URL)와 포트(HTTP의 경우 80포트)로 요청을 보냄
- 2) 서버는 클라이언트가 보낸 요청에 대해 연결을 수립하고 클라이언트에게 알림 (RTT)
- 3) 연결 신호가 오면 클라이언트는 서버에게 본격적으로
요청 메세지
를 보냄 - 4) 서버는 요청에 대한
응답 메세지
를 보내고 TCP 통신을 끊음 (RTT) - 5) 클라이언트는 응답받은 메세지를 분석하고, 화면에 표시
- 6) 분석 내용에 추가적으로 서버에 요청이 필요한 데이터의 경우 다시 1번의 과정을 수행
따라서 한번의 HTTP 통신에서 응답 시간은 2RTT + file transmission time
이라고 할 수 있다. base HTML을 수신한 후 추가적인 요청은 브라우저에서 병렬적으로 요청하여 처리하지만 앞서 TCP의 연결에 대해 비용 소비는 해결할 수 없고, 운영체제는 병렬적인 TCP 소켓을 할당하고 그에 따른 버퍼(TCP 소켓별 혼잡 제어 및 흐름 제어를 위한 버퍼)를 처리하기 때문에 부담이 된다.
Persistent HTTP
앞서 초기 HTTP 통신의 문제점을 해결하고자 현대의 HTTP는 통신된 소켓을 닫지 않고 유지한다. 따라서 추가적인 요청은 처음 통신한 소켓을 사용해 추가적인 통신은 1RTT만에 처리할 수 있다. 추가적으로 Persistent HTTP와 연관된 HTTP 요청 헤더는 Connection: keep-alive
이다.
HTTP 메세지
HTTP 메세지는 요청과 응답 두 가지 형태를 가진다. 각 형태는 ASCII로 작성된다. 여기서 요청에 필요한 값을 포함해야 하는데, 마지막 Body 영역엔 POST 메서드로 요청한 데이터들이 위치하고 GET 메서드의 경우 URL 필드에 ?
구분자를 기준으로 내용을 포함하게 된다.
요청/응답별 메세지
요청 메세지
- 요청 메서드
- HTTP/1.0
- GET
- POST
- HEAD
- 서버에게 응답은 주지만 컨텐츠 내용을 전송하지 않기를 요청한다. 테스트 목적으로 사용
- HTTP/1.1
- GET, POST, HEAD
- PUT
- DELETE
- HTTP/1.0
응답 메세지
- 응답 상태 코드
- 200 ok
- 301 Moved Permanently
- 400 Bad Request
- 404 Not Found
- 505 HTTP Version Not Supported
쿠키
쿠키는 HTTP 통신의 Stateless 특성의 단점을 보완하기 위해서 많은 웹사이트에서 사용되어지고 있다.
- 서버측에서 HTTP 응답 메세지에 쿠키 헤더를 포함해 전달한다.
- 응답을 받은 클라이언트측은 다음 요청에 응답으로 받은 쿠키 헤더를 포함해 전달한다.
- 클라이언트 브라우저는 해당 쿠키 파일을 유지한다.
- 서버도 개별 클라이언트에 대한 Back-end database 유지한다.
쿠키는 위 네 가지 요소로 동작하는데 예를 들어 (1) 최초 클라이언트가 서버로 요청을 보내면 (2) 서버는 해당 요청에 대한 고유 식별자를 포함한 쿠키를 포함해 응답을 돌려준다. (3) 클라이언트는 이후 통신에 받은 쿠키를 포함해 통신을 하는데, 서버 측에선 해당 고유 번호를 기반으로 Back-end database를 유지하며 해당 클라이언트가 보낸 요청에 대해 과거 기록을 확인할 수 있다.
따라서 쿠키를 사용하면 다음과 같은 일을 가능케한다.
- 인증
- 사용자 세션 유지
- 사용자가 브라우저에서 여러 사이트를 방문해도 개별 사이트가 개별 데이터를 유지할 수 있음
- 사용자 세션 유지
- 쇼핑 카트 (Stateless한 클라이언트들이 각각의 데이터를 유지할 수 있다.)
웹 캐시 (프록시 서버)
매 통신마다 같은 데이터에 대해서 바쁜 서버에게 직접적으로 요청하는 것이 아니라 한번 요청했던 데이터를 가까운 곳에 기록한 후 이후 요청에 대해선 저장해둔 데이터를 사용해 더 빠른 처리를 할 수 있도록 하는 방법이다, 클라이언트는 먼저 서버에 직접 요청을 보내는게 아니라 먼저 프록시 서버에 요청을 보내고 존재할 경우 바로 응답을 보내고(서버의 역할), 아닌 경우 요청을 담당하는 서버에 보내게 된다(클라이언트 역할). 이렇게 중간에 프록시를 두면 동일한 요청에 대해서 실질적인 트래픽을 줄일 수 있어 비용적인 부분에서 이득을 얻을 수 있다. 추가적으로 웹 캐시는 요청과 응답을 처리할 수 있어야 하기 때문에 클라이언트와 서버의 특징을 동시에 가져야 한다.
Conditional GET
하지만 만약 캐시된 내용이 최신 업데이트되어 내용이 변경되었다면 사용자들은 요청에 대해서 프록시 서버로 인해 과거의 내용만 보게될 수 있다. 이런 문제를 해결하기 위해서 프록시 서버는 캐시된 내용이 변경이 이뤄졌는지에 대해서 검사할 필요가 있다. 웹 프록시는 If-modified-since: <date>
를 헤더에 포함해 서버로 요청하고, 서버는 요청된 데이터가 언제 마지막으로 업데이트되었는지 알 수 있다. 만약 내용이 업데이트되지 않았다면 컨텐츠가 포함되지 않은 응답을 보내게 된다. 따라서 서버에 부담을 줄일 수 있다. (당연하게 요청된 데이터가 업데이트된 경우 ok 200
과 최신 컨텐츠를 응답으로 받음)
DNS(Domain Name System)
네트워크를 연결하기 위해선 Endpoint를 특정할 수 있는 IP 주소가 필요하다. 하지만 사람은 불규칙한 숫자보다 의미있는 단어를 통해서 더 쉽게 네트워크를 연결하기를 원했고, 이런 요구사항으로 인해 DNS가 생기게 되었다.
- hostname to IP address
- 별칭 hostname 부여
- 외부에 알려진 hostname을 내부에서 사용하는 hostname과 맵핑
- 메일 서버 주소 제공
- 로드 분산
- 동일한 외부 hostname 요청에 내부에서 처리를 분산할 수 있다.
Why not centralize DNS?
만약 DNS가 하나의 포인트를 가진다면 hostname이 IP와 맵핑하지 못하기 때문에 서로간의 연결에서 매우 심각한 문제가 발생하게 된다. 또 DNS가 중앙에 있다면 너무 많은 트래픽을 감당해야 하고, 요청된 클라이언트와의 거리에 따라서 응답 시간에 많은 시간이 소요될 수 있다. 그리고 전세계 인터넷의 모든 hostname을 database로 관리해야 하기 때문에 너무 많은 비용이 발생하게 된다.
따라서 DNS를 distributed, hierarchical database를 유지한다. Root DNS 서버 아래는 TLD(Top level DNS Server)들이 위치하며 이곳에 각 나라별(.kr, .fr, .jp)등의 도메인이 위치하게 된다. 이런 방식으로 구성하게 되면 각각의 DNS 서버들은 바로 위 계층만 알면 모든 통신을
Local DNS name server
위에 설명된 DNS 구조에 속하지 않는 DNS서버로 각 ISP(rediential ISP, 회사, 대학)에서 가지고 있다. 앞서 설명한 웹 프록시와 기능과 용도가 비슷하게 사용된다. 만약 맵핑해야 할 DNS 정보가 local DNS에 없다면 Root DNS server에 물어보게 된다.
DNS nane resolution example
- Iterated query
Local DNS server는 자신이 모르는 DNS 정보에 대해서 가장 먼저 (1) Root DNS로 요청을 보내고, (2) Root DNS는 자신이 모르는 DNS의 경우 (3) 그것을 아는 TLD DNS server의 위치를 알려준다. (4) 다시 Local DNS server는 받은 TDL 정보를 가지고 요청을 보내고 (5) TLD 서버는 자신이 모르는 경우 그 아래인 (5) 기관별 Authoritative DNS 서버의 정보를 알려준다. 마지막으로 (6) Local DNS server는 Authoritative DNS에게 요청하고, (7) Authoritative DNS서버는 자신의 DNS 정보를 모두 알기 때문에 최종적으로 DNS 정보를 local DNS로 돌려주게 된다.
- Recursive query
이 방식은 가장 많은 요청이 올 수 있는 상위 계층(Root DNS server, TLD DNS server)에 많은 부화를 발생시킬 수 있다. (Root DNS와 TLD DNS서버에서 Iterated query 방식에 비해 요청/응답을 2배씩 처리하고 있다.) 추가적으로 각각 동일한 2배의 처리가 이뤄진다고 했지만 TLD DNS보다 더 많은 영역을 포함하고 있는 Root DNS의 부하가 더 많이 발생하게 된다.
Caching, updateing records
DNS는 매우 빈번이 사용되고 상위 계층의 경우 많은 변경이 일어나지 않기 때문에 캐싱된 데이터의 경우 많은 영역을 다루고 있는 Root DNS 영역에 요청하지 않고 바로 TLD DNS로 요청할 수 있다. 하지만 완전히 변경이 없는 영역은 아니기 때문에 Out-of-date가 발생할 수 있고 따라서 TTL(Time to live)을 달아 일정시간 동안 사용 후 갱신이 이뤄진다. 하지만 이런 방법도 Out-of-date를 완벽히 해결할 수 없기 때문에 IETF에서 업데이트된 정보를 전세계로 알리는 새로운 매커니즘을 추가하여 해결했다.
DNS protocol, message
- Identification
- 16bit의 식별자를 동일하게 사용하므로 요청과 응답을 매칭시킬 수 있다.
- flags
- query or reply
- 메세지가 요청인지 응답인지 구분
- recursion desired
- 메세지를 재귀적으로 처리하기를 표시
- recursion available
- 메세지를 재귀적으로 처리할 수 있음을 표시
- reply is authoritative
- 응답이 Authoritative를 표시
- query or reply
DNS records
DNS는 distributed db에 Resource records(RR)을 저장하게 된다. RR은 (name, value, type, ttl) 형식을 가지며 Type은 아래 4가지 타입을 가지게 된다.
- A
- Name : hostname
- Value : IP 주소
- DNS의 가장 기본적인 역할
- NS
- Name : 도메인 (e.g., naver.com)
- Value : 이 도메인을 위한 인증 네임 서버의 hostname
- CNAME
- Name : 실제 이름을 대신할 별칭
- Value : 실제 이름
- MX
- Value : 이 도메인의 메일 서버 이름
이런 DNS records는 TLD 서버에 자신의 도메인에 관련된 정보를 가지고 있다. 따라서 Local name server는 Root DSN server를 알고, Root DNS server는 TLD server를 알고, TLD server는 Authoritative를 알고, Authoritative는 hostname을 IP 주소로 맵핑한다. 이렇게 새로운 RR이 DNS에 삽입되는 절차는 다음과 같다.
P2P applications
지금까지 설명된 모든 통신은 C-S 구조를 가지고 있었는 반면에 P2P는 Always-on 서버가 존재하지 않으며 임의의 유동적인 IP 및 Always-on이 보장되지 않은 End systems(or Peer)와 직접 통신하는 구조를 가진다.
확장성
C-S 구조에서 파일 배포에 걸리는 시간은 서버가 보내야하는 파일의 수(=N)가 비례하여 증가하게 된다. 왜냐하면 파일의 업로드는 단일 지점인 서버의 처리량에 의존하기 때문에 병목 현상이 발생하기 때문이다.
이에 비해서 P2P 구조는 마찬가지로 보내야하는 파일의 수(N)이 증가하지만, 파일을 받는 클라이언트가 서버의 역할을 동시에 하기 때문에 파일 업로드 작업량이 분산되어 병목 현상이 발생하지 않는다.
때문에 C-S 구조와 P2P 구조에서 클라이언트의 수에 따라 지연되는 시간을 나타내는 표를 보면 C-S 구조는 파일을 원하는 클라이언트가 증가함에 따라서 일정하게 증가하는 반면에, P2P 구조에선 파일 업로드의 처리가 분산되기 때문에 파일 배포 시간이 매우 천천히 증가하게 된다
'독서 > 네트워크' 카테고리의 다른 글
누가 구글을 죽였나 🔪 (a.k.a. CVE-2023-44487 분석 해보기) (0) | 2024.01.04 |
---|---|
HTTP 응답 상태 코드 (0) | 2022.01.02 |
전송 계층 (0) | 2021.12.30 |