확인 응답
고친 사람 github-actions[bot]
확인 응답은 데이터를 받은 쪽이 보낸 쪽에게 「여기까지 받았다」고 알려 주는 짧은 답장입니다. 보낸 쪽은 이 답장을 받고 나서야 그 데이터를 손에서 놓습니다. 답장이 제때 안 오면 같은 데이터를 다시 보냅니다. 메시지를 처리하는 프로그램이 「다 처리했다」고 알리는 신호도 같은 이름으로 부릅니다.
쉽고 빠른 이해
확인 응답은 받은 쪽이 「어디까지 받았다」고 보내는 답장입니다. 파일을 내려받는 동안 받은 쪽이 끊임없이 돌려보내는 작은 패킷이 이것입니다.
이 답장이 없으면 보낸 쪽은 데이터가 도착했는지 없어졌는지 알 길이 없습니다. 망은 잃어버린 데이터를 따로 알려 주지 않습니다.
- 보낸 데이터마다 번호를 붙입니다
- 받은 쪽이 「몇 번까지 받았다」고 답장합니다
- 답장이 정해진 시간 안에 안 오면 그 데이터를 다시 보냅니다
대가는 답장에 드는 통신량과 기다리는 시간입니다. 답장이 오갈 때까지 보낸 쪽은 그 데이터를 버리지 못하고 들고 있어야 합니다.
답장 자체도 없어질 수 있어서, 받는 쪽은 같은 데이터를 두 번 받는 일을 견뎌야 합니다.
상세
등기 우편을 떠올려 봅니다. 보낸 사람은 우체국에서 「받는 사람이 수령했다」는 통지를 받고 나서야 편지가 도착한 것을 압니다. 통지가 안 오면 편지가 갔는지 중간에 없어졌는지 알 수 없어서 한 통을 더 보내게 됩니다. 확인 응답도 같은 노릇을 합니다.
확인 응답은 받은 쪽이 보낸 쪽에게 도착 사실을 알리는 신호입니다. 영어로는 ACK(acknowledgment, 확인 응답)라고 줄여 부르고, 실무에서도 「애크」라는 말이 그대로 쓰입니다. 이 신호는 대개 따로 보내는 작은 패킷이거나, 반대 방향으로 흐르는 데이터에 함께 실리는 값입니다.
데이터가 빠짐없이 도착하도록 책임지는 전송 프로토콜은 대부분 이 답장 위에 서 있습니다. TCP(Transmission Control Protocol, 전송 제어 프로토콜)가 그 대표입니다.
답장이 없으면 무엇을 모르나
네트워크는 데이터를 반드시 나른다고 약속하지 않습니다. 중간 장비의 버퍼가 차면 지나가던 데이터를 그냥 버립니다. 이 버림을 패킷 손실이라고 부릅니다.
버릴 때 누구에게도 알리지 않는 것이 중요한 대목입니다. 보낸 쪽은 자기가 보낸 데이터가 도착했는지 없어졌는지를 스스로는 알 수 없습니다.
확인 응답은 이 모름을 메웁니다. 답장이 오면 도착한 것이고, 안 오면 둘 중 하나입니다. 데이터가 없어졌거나 답장이 없어졌거나입니다. 어느 쪽인지는 보낸 쪽이 구별하지 못하고, 그래서 두 경우를 같게 다룹니다. 다시 보냅니다.
다시 보내는 이 동작이 재전송입니다. 확인 응답과 재전송은 둘이 한 벌입니다. 답장이 없으면 재전송할 수 없고, 재전송이 없으면 답장을 받아 봐야 할 일이 없습니다.
sequenceDiagram
participant 보내는쪽
participant 받는쪽
보내는쪽->>받는쪽: 데이터 1번
받는쪽-->>보내는쪽: 1번까지 받았다
보내는쪽->>받는쪽: 데이터 2번
Note over 보내는쪽,받는쪽: 2번이 도중에 버려진다
보내는쪽->>받는쪽: 데이터 2번 다시
받는쪽-->>보내는쪽: 2번까지 받았다
그림에서 보낸 쪽이 2번을 다시 보낸 까닭은 답장이 안 왔기 때문입니다. 답장을 얼마나 기다렸다가 다시 보낼지는 타임아웃이 정합니다.
무엇에 대한 답장인지 정하는 값
답장이 「받았다」고만 말하면 무엇을 받았다는 것인지 알 수 없습니다. 데이터는 여러 개가 한꺼번에 날아다니고, 답장도 여러 개가 돌아옵니다.
그래서 보내는 데이터마다 번호를 붙입니다. 이 번호를 순서 번호라고 합니다. 답장은 그 번호를 담아서 「몇 번을 받았다」고 말합니다.
번호는 답장을 짝지어 주는 일 말고도 두 가지를 더 해 줍니다. 받은 쪽이 데이터를 원래 순서대로 맞춰 놓을 수 있고, 같은 번호가 두 번 오면 중복인 줄 알 수 있습니다.
답장 하나가 여러 개를 덮는 방식
받은 데이터마다 답장을 하나씩 보내면 답장 수가 데이터 수만큼 됩니다. 그래서 흔히 쓰는 방식은 「여기까지 빠짐없이 받았다」는 한 점을 알리는 것입니다. 이것을 누적 확인 응답이라고 부릅니다.
3번까지 받았다는 답장 하나는 1번과 2번도 받았다는 뜻을 담습니다. 답장 하나가 없어져도 다음 답장이 그 앞을 덮으므로 보낸 쪽은 곤란해지지 않습니다.
대신 중간에 하나만 빠졌을 때가 곤란해집니다. 1·2번을 받고 3번을 놓친 뒤 4·5번을 받았다면, 받은 쪽이 알릴 수 있는 점은 여전히 2번뿐입니다. 4·5번을 들고 있다는 사실이 답장에 안 실립니다.
이 한계를 넘으려고 「여기까지 받았고, 그와 별개로 이 구간도 받았다」를 함께 싣는 방식이 있습니다. 선택적 확인 응답입니다. 보낸 쪽은 빠진 3번만 다시 보내면 됩니다.
같은 점을 가리키는 답장이 되풀이해서 오는 경우도 뜻이 있습니다. 받은 쪽이 뒤 데이터를 계속 받고 있다는 신호라서, 보낸 쪽은 타임아웃을 기다리지 않고 빠진 것을 먼저 채워 넣습니다. 이 되풀이되는 답장을 중복 확인 응답이라고 부릅니다.
답장을 미뤄서 합치기
답장은 실어 나르는 데이터가 없는 패킷이라 통신량만 늘립니다. 그래서 받은 쪽은 답장을 곧바로 보내지 않고 잠깐 미루기도 합니다. 미루는 동안 데이터가 더 들어오면 답장 하나로 묶입니다.
마침 반대 방향으로 보낼 데이터가 있으면 그 패킷에 답장 값을 얹어 함께 보냅니다. 답장 전용 패킷이 아예 안 나가므로 통신량이 줄어듭니다. 요청과 응답이 번갈아 오가는 사이에서는 이렇게 얹히는 경우가 많습니다.
미루는 값은 늦어짐입니다. 보낸 쪽은 그만큼 늦게 답장을 받고, 다음 데이터를 내보내는 판단도 그만큼 늦어집니다.
답장이 없어졌을 때 생기는 중복
데이터는 잘 도착했는데 돌아오는 답장이 없어질 수 있습니다. 보낸 쪽이 보기에 이것은 데이터가 없어진 것과 구별되지 않습니다. 그래서 같은 데이터를 다시 보냅니다.
받은 쪽은 이미 처리한 것을 한 번 더 받습니다. 이것이 확인 응답과 재전송을 쓰는 모든 시스템이 안고 가는 성질입니다. 「적어도 한 번은 도착한다」는 보장은 「두 번 이상 도착할 수도 있다」와 같은 말입니다.
sequenceDiagram
participant 보내는쪽
participant 받는쪽
보내는쪽->>받는쪽: 주문 넣기
받는쪽-->>보내는쪽: 받았다
Note over 보내는쪽,받는쪽: 답장이 도중에 버려진다
보내는쪽->>받는쪽: 주문 넣기 다시
Note over 받는쪽: 같은 주문을 두 번 받는다
받은 쪽이 이것을 견디는 방법은 둘입니다. 하나는 번호를 기억해 두고 이미 처리한 번호가 또 오면 처리는 건너뛰고 답장만 다시 보내는 것입니다. 다른 하나는 같은 요청을 여러 번 처리해도 결과가 같게 만드는 것입니다. 뒤쪽 성질을 멱등성이라고 부릅니다.
전송 프로토콜은 대개 앞쪽을 씁니다. 순서 번호로 중복을 걸러 내고 응용 프로그램에는 한 번만 올려 줍니다. 응용 프로그램끼리 주고받을 때는 뒤쪽이 필요해집니다.
안 받았다고 알리는 답장
지금까지 본 답장은 전부 「받았다」를 말합니다. 반대로 「못 받았다」를 알리는 답장도 있습니다. NAK(negative acknowledgment, 부정 확인 응답)라고 부릅니다.
받은 쪽이 빠진 것을 알아챈 순간 곧바로 알릴 수 있어서, 타임아웃만큼 기다리지 않아도 됩니다. 다만 받은 쪽이 빠진 것을 알아채려면 뒤 데이터가 와야 하므로, 뒤가 아예 안 오는 경우에는 쓸 수 없습니다. 그래서 대개 타임아웃과 같이 씁니다.
체크섬이 깨진 데이터를 받았을 때도 이 답장을 보냅니다. 값이 망가졌다는 것은 받은 쪽이 스스로 알 수 있는 몇 안 되는 실패입니다.
확인 응답을 안 쓰는 길
모든 전송이 답장을 주고받지는 않습니다. UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)는 보내기만 하고 도착 여부를 묻지 않습니다. 받는 쪽은 답장을 안 보내고, 보내는 쪽은 다시 보내지 않습니다.
그 대신 얻는 것은 기다림이 없다는 점입니다. 영상 통화처럼 늦게 도착한 데이터가 이미 쓸모없어진 경우에는 다시 보내는 것이 도움이 안 됩니다. 놓친 한 조각을 채우려고 뒤 조각까지 세워 두면 오히려 끊깁니다.
확인 응답이 떠받치는 성질은 신뢰성입니다. 신뢰성이 필요한데 답장이 없는 전송을 써야 한다면, 응용 프로그램이 그 위에 번호와 답장과 재전송을 직접 얹게 됩니다.
보낸 쪽이 답장을 바탕으로 판단하는 것은 도착 여부만이 아닙니다. 답장이 돌아오는 데 걸린 시간은 왕복 시간을 재는 재료가 되고, 이 값이 타임아웃을 정합니다. 답장이 돌아오는 속도는 길이 얼마나 막혔는지를 짐작하는 재료가 되어 혼잡 제어에 쓰입니다. 받은 쪽이 답장에 「앞으로 이만큼 더 받을 수 있다」를 함께 실으면 그것은 흐름 제어가 됩니다.
메시지 큐에서 쓰는 같은 이름
메시지 큐에서도 확인 응답을 씁니다. 여기서 답장을 보내는 쪽은 메시지를 꺼내 처리하는 프로그램이고, 받는 쪽은 큐입니다.
큐는 메시지를 내주고 나서 지우지 않고 들고 있습니다. 처리한 쪽이 「다 처리했다」고 알리면 그때 지웁니다. 알림이 정해진 시간 안에 안 오면 처리하다 죽은 것으로 보고 그 메시지를 다른 프로그램에게 다시 내줍니다.
그래서 여기서도 같은 중복이 생깁니다. 처리를 다 끝내 놓고 답장을 보내기 직전에 죽으면, 그 메시지는 다시 나가고 두 번 처리됩니다. 메시지를 처리하는 코드에 멱등성이 필요하다는 말이 나오는 까닭이 이것입니다.
뼈대는 전송에서 본 것과 같습니다. 받은 쪽이 알릴 때까지 보낸 쪽이 들고 있고, 안 알리면 다시 보내고, 다시 보내니까 중복이 생깁니다. 다른 것은 오가는 단위가 패킷인지 메시지인지뿐입니다.
관련 항목
확인 응답을 주고받는 전송 프로토콜
확인 응답의 하위 종류
누적 확인 응답 · 선택적 확인 응답 · 중복 확인 응답 · 부정 확인 응답 · 지연 확인 응답
확인 응답이 무엇을 가리키는지 정하는 값
순서 번호 · 패킷 번호 · 오프셋 · 메시지 ID · 세그먼트
답장이 안 올 때 보내는 쪽이 실행하는 동작
재전송 · 타임아웃 · 재전송 타임아웃 · 지수 백오프 · 빠른 재전송
확인 응답을 바탕으로 도는 제어 장치
흐름 제어 · 혼잡 제어 · 슬라이딩 윈도 · 느린 시작 · 왕복 시간
확인 응답을 쓰고도 남는 실패
패킷 손실 · 중복 전달 · 순서 뒤바뀜 · 두 장군 문제 · 꼬리 손실
중복 도착을 견디려고 쓰는 장치
멱등성 · 멱등성 키 · 중복 제거 · 최소 한 번 전달 · 정확히 한 번 전달
메시지 큐 쪽에서 확인 응답을 쓰는 제품과 개념
메시지 큐 · Kafka · RabbitMQ · 오프셋 커밋 · 가시성 타임아웃
확인 응답이 떠받치는 성질
다른 이름: ACK · acknowledgment · 애크 · 수신 확인