지금까지 배운 네트워크는 굉장히 이상적인 네트워크라고 볼 수 있다.
단말기와 단말기 사이에 단단한 파이프라인을 통해 데이터를 전송받으며 데이터의 손실없이 받아낼수 있는것이였다.
하지만 실제로 우리의 네트워크는 그렇지않다
우리는 현재 클라우드 네트워크를 기반으로 데이터를 전송 받고 있는데 이는 문제점이 있다
- 무한한 흐름이 불가능하다.
- 데이터가 크면 그것을 한번에 보내는것이 불가능한것이다.
- 그러면 패킷을 잘라서 전송을 하게된다.
- 그렇게 되면서 패킷의 유실이 문제가 되는것이다.
- 더불어 패킷이 잘리면서 패킷의 순서또한 뒤죽박죽이 된다는것이다.
- 패킷의 변조가 발생할 수 있다.
그래서 이를 해결하기 위해 여러가지 네트워크 기법을 적용한다
Reliable Networking( End - to - End )
그중 전송계층에서 다루고 있는것이 end - to - end인데 이것을 다시 정리해보자
- 무한한 흐름이 불가능한 곳에서 거대한 데이터를 보낼때 데이터를 패킷화(잘게 자른다) 하여 하나씩 보낸다.
- 이때 패킷의 유실과 패킷의 순서가 바뀌는 상황이 발생할 수 있는데 그것을 방지 하기 위해서 acknowledgement 를 대입한다
※ acknowledgement
패킷을 전송하는 과정에 서버가 패킷을 제대로 받았다는 말을 하기 위해서 만들어진것이다.
패킷을 전송하는 입장(A)에서는 타이머를 작동시키고 패킷을 전송한다. 그럼 패킷을 받은 곳(B)에서 패킷을 받고 ACK에 시퀀스 넘버를 담아 다시 데이터를 전송하는데 만약 ACK이 담긴 데이터가 돌아오지 않은채로 타이머가 종료되면 데이터를 서버가 못받았다고 전제하고 같은 패킷을 재전송한다.
이로써 유실이 됐는지 안됐는지 알수있게 되는것이다.
기본적인 내용은 이렇다. 그럼 조금 더 심화된 내용으로 패킷의 유실에 대한 내용을 알아보자
- 애초에 패킷이 전달되지 않고 유실되었을때
- ACK이 담긴 패킷이 다시 돌아오는 과정에서 유실되었을때
- 서로 잘 주고 받았는데 심각한 딜레이로 인해 타이머가 작동하여 데이터를 계속해서 재전송할때
예시를 통해 좀 더 자세히 알아보자
!!예시1!! = ABCDEFGH
우리는 문자 "ABCDEFGH"라는 것을 패킷을 통해 보내고 싶은데 패킷의 최대 길이는 4글자이다. 그래서 한번에 최대글자인 ABCD를 보냈는데 유실이 발생했다. 근데 해당 유실의 경우가 2번이 되었다. 그럼 A의 입장에서는 패킷이 유실되었다 판단할테고 또다시 같은 데이터를 보낼것이다. 그렇다면 이번엔 문제가 B에서 발생한다.
B는 이전의 ABCD와 재전송한 패킷인 ABCD의 차이점을 B는 알수 없다. 즉, B입장에서는 ABCD를 원하는건지 ABCDABCD를 원하는것인지 알수 없다는것이다.
그래서 A측에서도 시퀀스 넘버를 패킷에 작성해서 보내주는것이다. 그러면 전송을 할때 0번.ABCD 를 보내면 B의 입장에서는 ACK 0. ABCD받았다 라는 패킷이 중간에 유실되어도 타이머가 다된 A에서는 0번.ABCD로 다시 보내기때문에 B의 입장에서도 "아 그거 아까 한 요청이구나"라는것을 알아차리며 다시 ACK0.ABCD 잘받았다 라는 패킷을 다시 보내게 되는것이다.
!!예시2!! = ABCDABCD
예시 1번을 이해했다면 쉬운 예시이다. ABCD가 두번이 연속으로 진행되지만 처음에 보낸 ABCD에 0번이라는 시퀀스 넘버가 붙어있다면 그 다음 데이터인 ABCD엔 1.ABCD 라고 붙여 보내면서 B의 입장에선 "아! 두개가 다른 패킷이구나 ABCDABCD보내는거구나" 라고 이해할수 있기 때문이다.
이로써 패킷의 유실에 대비할 수 있게 되는것이다. 또한 패킷의 순서까지도 보안이 되는것이다.
그럼 이것이 성능이 좋은것일까? 단점을 보안하기 했지만 성능 자체만 놓고 봐서는 그렇게 좋지 않다.
왜냐하면 하나씩 데이터를 전송하기 때문이다. 이전에도 배웠듯이 데이터를 하나씩 보내는것은 전체적인 전송률을 따지면 좋지 않다. 그래서 우리가 배운것이 바로 PipeLine이라는 기법이였다.
성능 향상 - Pipelining
늘 그렇듯 성능향상은 굉장히 중요한 문제이다. 이전에 배워봤지만 한번 더 배워보자
Pipelining 기법
- 연속된 대량의 작업이 순차성을 갖고 있으나 앞의 일이 종료하지 않고도 다음일을 시작할 수 있는 병렬성을 가진 경우의 성능 향상 기능
- 기본적인 메커니즘은 매우 간단하다. 굳이 ACK을 기다리지 않고 한번에 데이터를 전송한다. 1,2,3,4 이런식으로 쭈욱 보내고 각자의 타이머를 설정한다. 그럼 ACK이 담긴 패킷들이 들어올텐데 그중 타이머가 끝나도 들어오지 않은 패킷을 파악하여 그것만 다시 요청하는 방식으로 진행하는 것이다.
Pipelining 을 구현하는 2가지 방법
첫번째 방법 . Go - Back - N
- 최대 N개의 패킷을 병렬적으로 처리
- 송신측에서는 N개의 패킷을 buffering한다( 재전송을 위해서 )
- Buffering의 의미는 수신이 확실하지 않은 패킷에 대하여 재전송을 위해 보관
- 수신측에서는 순차적으로 잘 수신된 패킷에 대하여 ACK을 송신하고 패킷의 내용(Payload)을 응용계층으로 올려 보낸다
- 송신측에서는 buffer에 여유가 생기면(ACK을 받아서) 그만큼 추가로 Pipelining을 해준다.
!! 예시1 !! = 수신측은 잘 받았지만 송신측에 ACK을 담은 패킷이 유실되었을 경우
Buffer의 크기가 4라고 가정하고 데이터를 전송한다. 그럼 1,2,3,4를 보내고 수신측에서는 잘 받아서 응용계층으로 받은 패킷을 올려보내고 ACK을 달고 수신측에 잘 받았다고 보낸다
근데 다시 보내는 과정에 2번 패킷이 유실되었다. 그런데 다음으로 보낸 3번 패킷이 송신측에 잘 도착했다면
송신측의 Buffer는 3번까지 잘 받았구나 라고 판단하여 buffer에서 1,2,3을 지우고 빈 공간에 6,7을 보낸다.
왜냐하면 수신측에서 보내는 내용은 받은 내용 뿐아니라 순차적으로 잘 수신된 패킷에 대하여 ACK달아 보낸다고 했다. 즉, ACK에는 받은 패킷의 시퀀스 넘버뿐아니라 여기까지 잘 받았다! 라는 뜻을 달고 있기도 하다는것이다.
!! 예시2 !! = 애초에 수신측에서 패킷을 받지 못하고 유실됬는데 그 다음 패킷을 잘 받는다면?
똑같이 Buffer의 크기를 4라고 가정하고 1,2,3,4를 보냈는데 수신측에서 3을 못 받은것이다. 그런데 그 다음 4번 패킷은 잘 받았다.
그렇다면 아까 말했듯이 수신측은 순차적이지 못한 패킷을 받은것이다 여기서 수신의 반응이 2가지로 나뉜다
1. 조용히 있는다
--그냥 가만히 있는것이다...마치 아~무것도 받지 못한것처럼 가만히 있는것이다.
2. 잘 받은 마지막 패킷에 대한 ACK을 전송한다.
-- 2번까지 잘 받았다 라는 정보를 계속해서 전달한다. 그 후의 정보가 도착하던 말던 2번까지 잘받았다 라고 계속 송신측에 보내는것이다.
- 수신측이 정보를 받지 못했다는것을 송신측이 알아차렸다면 Go - Back - N에서의 재전송 정책은 어떤것이 있을까
- 각 패킷 전송시에 패킷을 위한 타이머를 설정하여 못받았다는것을 알아차린다
- ACK을 받으면 ACK해당 패킷과 앞쪽 패킷에 대한 타이머가 소멸된다.
- 타이머 이벤트(시간초과) 발생시 해당 패킷부터 재전송한다.
- 추가 재전송 정책
k번째 패킷에 대한 ACK이 반복적으로 올 경우(2번예시)는 (k+1)번째 패킷의 유실을 함축한다.
3번정도 k패킷에 대한 ACK이 오면 타이머와 무관하게 k+1번째 패킷부터 재전송한다.
- Go-Back-N 의 장점
- 단순하다. ( 특히 수신측 )
- 간명하게 시스템의 상태가 추상화된다.
- Go-Back-N 의 단점
- 패킷 유실에 대한 복구비용이 크다.
두번째 방법 . Selective Refeat
- Go - Back - N의 단점인 복구비용이 큰 것을 수신측에 버퍼를 둠으로써 보완한것이다.
- 빠진 패킷이 있다면 그 뒤쪽의 잘 도착한 패킷들은 버퍼에 보관한다.
- 빠진 패킷이 추후 도착하면 버퍼에 저장한 이후 패킷들 까지 순차적으로 응용에 전달한다.
- Go - Back - N에서 ACK의 의미는 n번 패킷"까지" 잘 왔다는 뜻이였고
Selective Refeat에서 ACK의 의미는 n번 패킷"이" 잘 왔다는 뜻으로 두개의 구분을 잘 해주어야한다.
!! 예시1 !! = 패킷이 수신에 가지 못하고 유실되었을 경우
송신측의 Buffer는 4라고 가정하고 1,2,3,4를 보낸다. 그중 2번패킷이 전송과정에 유실되었고 나머지 3,4는 잘 전송되었다. 그렇다면 수신 측에선 먼저 1을 잘 받았다는 ACK을 보내고 송신은 이어서 5번을 보낸다. 하지만 2번에 대한 ACK은 오지않고 그 뒤에 3,4의 ACK만 받는다
여기서 중요한 점 수신측의 buffer도 4라고 만들어놨고 그 안에 순차적이지 않은 넘버를 저장해놓는다.
즉, 1번은 응용으로 보내지만 순차적이지 않은 3,4,5는 보내지 않고 버퍼에 저장해 둔다는 것이다.
그러면 GO - Back - N과는 다르게 송신측은 Buffer안에 있는 2,3,4,5중 가장 먼저 보냈던 2번을 못받아서 지워지지 않았다면 buffer의 공간이 남더라도 뒤에 수를 보내지 않고 타이머 이벤트를 기다리게 된다. 그후 타이머 이벤트가 발생하면서 2번을 다시 보내게 되는것이다.
그 2번은 수신측으로 잘 보내지게 되고 수신의 buffer또한 2,3,4,5로 순차적으로 정리되면서 응용계층으로 올려보내는 것이다. 그리고 buffer를 비운다. 그리고 2번을 잘 받았다 ACK을 전송한다.
그럼 송신측은 2를 지우고 6,7,8을 또 다시 우르르 보낸다.
또 다른 문제 = 수신은 잘 받았는데 ACK담긴 패킷이 넘어오지 못했다면
5,6,7,8을 잘 받은 수신은 모든 번호를 응용에 올려보내고 정보(8번까지 잘 받았다)를 저장한다 근데 5번이 담긴 ACK이 가다가 유실되고 나머지 번호들은 잘 간다면 송신측의 buffer엔 또 5번만 남기고 나머지 패킷은 지워진다. 그렇다면 송신측은 똑같이 buffer안에 더이상 수를 채우지 않고 5번을 기다리는 타이머 이벤트가 발생하길 기다리다가 또다시 5번을 보내게 된다. 그러면 수신이 5번을 받는데 아까 응용으로 보낸 정보를 저장해두었던 수신은 "아까 5번 잘 받았어!" 라고 대답만 보낸다.
- Selective Refeat의 장점
- 실패한 패킷만 재전송하여 성능이 좋아진다.
- Selective Refeat의 단점
- 시스템 추상화가 복잡해진다. ( 모든 패킷의 상태를 모두 정의해야한다는것이다. )
- 수신측에도 버퍼(저장공간)가 필요하다.
'CS' 카테고리의 다른 글
Cookie와 Session (4) | 2023.05.01 |
---|---|
HTTP(1). GET & POST (0) | 2023.04.27 |
응용계층(1.프로세스의 통신) (0) | 2023.04.25 |
P2P ( Peer - to - Peer ) (0) | 2023.03.17 |
컴퓨터 네트워크 (2) | 2023.03.10 |