HTTP(HyperText Transfer Protocol)는 서버에서 클라이언트로 데이터를 전송하는 상태 비저장 요청-응답 모델을 지원하도록 설계되었습니다. 첫 번째 버전인 1.0은 순수하게 1:1 요청 대 연결 비율(즉, 연결당 하나의 요청-응답 쌍이 지원됨)만 지원했습니다.
버전 1.1에서는 이 비율이 N:1로 확장되었습니다. 즉, 연결당 요청 수가 많아졌습니다. 이는 서버에서 클라이언트로 전송해야 하는 많은 객체와 요소를 포함하여 웹 페이지의 점점 더 복잡해지는 문제를 해결하기 위해 수행되었습니다.
2.0이 도입되면서 HTTP는 연결당 여러 요청 모델을 계속 지원하게 되었습니다. 가장 급진적인 변화에는 헤더 교환과 텍스트 기반 전송에서 바이너리 전송으로의 전환이 포함됩니다.
어느 순간 HTTP는 서버에서 클라이언트로 텍스트와 이미지를 전송하는 간단한 메커니즘 그 이상이 되었습니다. 즉, 애플리케이션을 위한 플랫폼이 되었습니다. 브라우저의 보편성, 여러 플랫폼을 지원하는 특성, 그리고 여러 운영체제와 환경을 지원하는 데 드는 막대한 비용 없이도 애플리케이션을 쉽게 배포할 수 있다는 점은 분명 매력적이었습니다. 안타깝게도 HTTP는 애플리케이션 전송 프로토콜로 설계되지 않았습니다. 문서를 전송하기 위해 설계되었습니다. API를 포함한 HTTP의 최신 용도조차도 문서와 유사한 페이로드를 가정합니다. 이에 대한 좋은 예는 텍스트로 전송되는 키-값 쌍의 데이터 형식인 JSON입니다. 문서와 애플리케이션 프로토콜은 일반적으로 텍스트 기반이지만 유사성은 거기서 끝입니다.
기존 애플리케이션은 상태를 유지할 방법이 필요하지만 문서는 그렇지 않습니다. 애플리케이션은 논리적 흐름과 프로세스를 기반으로 구축되며, 두 가지 모두 애플리케이션이 사용자가 현재 어디에 있는지 알아야 하며, 이를 위해 상태가 필요합니다. HTTP는 본질적으로 상태를 저장하지 않는 특성이 있음에도 불구하고 사실상 웹의 표준 애플리케이션 전송 프로토콜이 되었습니다. 기술 역사상 가장 널리 받아들여지고 유용한 해킹 중 하나로 꼽히는 HTTP를 통해 애플리케이션 사용 전반에 걸쳐 상태를 추적할 수 있는 수단이 제공되었습니다. 이 "해킹"에서 세션과 쿠키가 중요한 역할을 합니다.
세션은 웹 및 애플리케이션 서버가 상태를 유지하는 방법입니다. 이러한 간단한 메모리 덩어리는 웹이나 애플리케이션 서버에 대한 모든 TCP 연결과 연관되며 HTTP 기반 애플리케이션의 정보를 저장하는 메모리 내 저장소 역할을 합니다.
사용자가 처음으로 서버에 연결하면 세션이 생성되어 해당 연결과 연관됩니다. 그런 다음 개발자는 해당 세션을 애플리케이션과 관련된 데이터를 저장하는 장소로 사용합니다. 이 데이터는 고객 ID와 같은 중요한 정보부터 사이트의 첫 페이지를 어떻게 표시할지와 같은 덜 중요한 데이터까지 다양합니다.
세션의 유용성을 가장 잘 보여주는 예는 쇼핑 카트입니다. 왜냐하면 우리 대부분이 어느 시점에서는 온라인 쇼핑을 해본 적이 있기 때문입니다. 쇼핑 카트에 있는 항목은 "세션" 동안 그대로 유지됩니다. 쇼핑 카트에 있는 각 항목은 서버의 세션에서 어떤 방식으로든 표현되기 때문입니다. 또 다른 좋은 예는 마법사 스타일의 제품 구성이나 사용자 정의 애플리케이션입니다. 이런 "미니" 애플리케이션을 이용하면 여러 옵션을 탐색하고 선택할 수 있으며, 마지막에는 추가한 모든 고급 기능의 예상 비용을 보고 깜짝 놀라곤 합니다. 각 "옵션 화면"을 클릭하면 선택한 다른 옵션이 세션에 저장되므로 쉽게 검색, 추가 또는 삭제할 수 있습니다.
최신 애플리케이션은 상태 비저장으로 설계되었지만 아키텍처가 해당 원칙을 준수하지 않을 수 있습니다. 최신 확장 방법은 종종 사용자 이름이나 계좌 번호와 같은 색인 가능한 데이터를 기반으로 요청을 라우팅해야 하는 샤딩과 같은 아키텍처 패턴에 의존합니다. 이를 위해서는 적절한 라우팅과 애플리케이션 동작을 보장하기 위해 각 요청과 함께 인덱싱 가능한 데이터가 전송된다는 점에서 일종의 상태 기반 접근 방식이 필요합니다. 이와 관련하여 현대의 "무상태" 애플리케이션과 API는 종종 상태 있는 이전 애플리케이션과 유사한 관리와 공급이 필요합니다.
문제는 세션이 연결에 묶여 있고, 연결이 너무 오랫동안 유휴 상태로 남아 있다는 것입니다. 또한, 연결에 대한 "너무 길다"의 정의는 세션에 적용될 때와 상당히 다릅니다. 예를 들어 일부 웹 서버의 기본 구성은 15초 동안 유휴 상태, 즉 더 이상 요청이 없으면 연결을 닫는 것입니다. 반면, 이러한 웹 서버의 세션은 기본적으로 300초, 즉 5분 동안 메모리에 남아 있습니다. 분명 둘은 서로 상충됩니다. 연결 시간이 초과되면 연결과 연관된 세션이 무슨 소용이 있겠습니까?
세션에 맞게 연결 시간 초과 값을 늘리면 이러한 불균형을 해결할 수 있다고 생각할 수도 있습니다. 시간 제한을 늘리면 연결을 유지하기 위해 메모리를 소비하게 되며, 이 연결이 사용될 수도, 그렇지 않을 수도 있습니다. 이로 인해 서버의 총 동시 사용자 용량이 감소할 수 있으며 궁극적으로 성능도 저하될 수 있습니다. 그리고 대부분의 사람들이 새로운 장난감을 비교하거나 맞춤 설정하는 데 5분 이상 걸리기 때문에, 연결 시간 초과와 맞춰 세션 시간 초과를 줄이는 것은 바람직하지 않습니다.
중요 참고 사항: HTTP/2는 이러한 문제 중 일부를 해결하지만, 상태 유지와 관련된 다른 문제도 도입합니다. 사양에서는 요구하지 않지만 주요 브라우저는 TLS/SSL을 통한 HTTP/2만 허용합니다. 두 프로토콜 모두 재협상으로 인한 성능 비용을 피하기 위해 지속성이 필요하며, 이를 위해서는 세션 인식, 즉 상태 저장 동작이 필요합니다.
따라서 비활성화로 인해 연관된 연결이 종료된 후에도 세션이 서버에 메모리로 남아 귀중한 리소스를 낭비하고 애플리케이션이 제대로 작동하지 않는 사용자를 화나게 할 가능성이 있습니다.
다행히도 이 문제는 쿠키를 사용하면 해결됩니다.
쿠키는 브라우저가 클라이언트에 저장하는 데이터 조각입니다. 쿠키는 여러분, 여러분의 애플리케이션, 여러분이 방문하는 사이트에 대한 온갖 흥미로운 정보를 저장할 수 있으며, 실제로 그렇게 저장합니다. "쿠키"라는 용어는 UNIX 컴퓨팅의 잘 알려진 개념인 "매직 쿠키"에서 유래되었으며, 여기에서 아이디어와 이름이 영감을 받았습니다. 쿠키는 HTTP 헤더인 쿠키를 통해 브라우저와 서버 사이에서 생성되고 공유됩니다.
쿠키: JSESSIONID=9597856473431 캐시 제어: no-cache 호스트: 127.0.0.2:8080 연결: Keep-Alive
브라우저는 자동으로 컴퓨터의 파일에 있는 HTTP 헤더에 쿠키를 저장해야 한다는 것을 알고 있으며 도메인별로 쿠키를 추적합니다. 특정 도메인에 대한 쿠키는 항상 브라우저에서 HTTP 헤더를 통해 서버로 전달되므로, 웹 애플리케이션 개발자는 애플리케이션의 서버 측에서 쿠키를 요청하기만 하면 해당 값을 검색할 수 있습니다.
세션/연결 길이 문제는 쿠키를 통해 해결됩니다. 거의 모든 최신 웹 애플리케이션은 "세션 ID"를 생성하여 쿠키로 전달합니다. 이를 통해 애플리케이션은 세션이 생성된 연결이 닫힌 후에도 서버에서 세션을 찾을 수 있습니다. 세션 ID를 교환함으로써 HTTP와 같은 상태 비저장 프로토콜에서도 상태가 유지됩니다. 하지만 웹 애플리케이션의 용량이 단일 웹 또는 애플리케이션 서버의 용량을 벗어나면 어떻게 될까요? 일반적으로 로드 밸런서 또는 오늘날의 아키텍처에서는 ADC(애플리케이션 전송 컨트롤러)가 모든 사용자가 가용성과 성능에 만족할 수 있도록 애플리케이션을 확장하기 위해 도입됩니다.
최신 애플리케이션에서는 쿠키를 계속 사용할 수 있지만 다른 HTTP 헤더가 중요해집니다. 인증 및 권한 부여를 위한 API 키는 종종 HTTP 헤더를 통해 전송되며, 백엔드 서비스의 라우팅과 적절한 확장에 필요한 데이터를 전달하는 다른 사용자 정의 헤더를 통해 전송됩니다. 이 데이터를 전송하기 위해 기존의 "쿠키"를 사용하느냐 다른 HTTP 헤더를 사용하느냐는 전체 아키텍처에 대한 중요성을 인식하는 것보다 덜 중요합니다.
이 문제의 원인은 부하 분산 알고리즘이 일반적으로 여러 서버에 요청을 분산시키는 데만 관심이 있기 때문입니다. 부하 분산 기술은 라운드 로빈, 최소 연결, 가장 빠른 응답 시간과 같은 산업 표준 알고리즘을 기반으로 합니다. 그 중 어느 것도 상태가 저장되지 않으며, 같은 사용자가 애플리케이션에 보낸 각각의 요청을 다른 서버로 분산시키는 것이 가능합니다. 이렇게 되면 HTTP 상태를 구현하기 위해 수행한 모든 작업이 쓸모없게 됩니다. 한 서버의 세션에 저장된 데이터는 "풀"에 있는 다른 서버와 공유되는 경우가 거의 없기 때문입니다.
여기에서 지속성이라는 개념이 유용합니다.
지속성(stickiness라고도 함)은 ADC가 구현하는 기술로, 단일 사용자의 요청이 항상 시작된 서버로 분산되도록 보장합니다. 일부 로드 밸런싱 제품과 서비스는 이 기술을 "스티키 세션"이라고 설명하는데, 이는 매우 적절한 별명입니다.
지속성은 SSL/TLS 지원 사이트의 부하 분산에 오랫동안 사용되어 왔습니다. 그 이유는 협상 프로세스(컴퓨팅 집약적 프로세스)가 완료되고 키가 교환되면 프로세스를 다시 시작하면 성능이 크게 저하되기 때문입니다. 따라서 ADC는 SSL 세션 지속성을 구현하여 사용자가 항상 처음 연결한 서버로 이동하도록 보장했습니다.
수년에 걸쳐 브라우저 구현에서는 이러한 세션의 값비싼 재협상을 피하기 위한 기술 개발이 필요하게 되었습니다. 이 기술을 쿠키 기반 지속성이라고 합니다.
로드 밸런서는 SSL/TLS 세션 ID에 의존하기보다는 클라이언트가 사이트에 처음 접속할 때 세션을 고유하게 식별하는 쿠키를 삽입한 다음 후속 요청에서 해당 쿠키를 참조하여 적절한 서버에 대한 연결을 유지합니다.
이후 쿠키 기반 지속성 개념은 애플리케이션 세션에 적용되었으며, 웹 및 애플리케이션 서버에서 생성된 세션 ID 정보를 사용하여 사용자 요청이 동일한 세션 동안 항상 동일한 서버로 전달되도록 보장합니다. 이 기능이 없다면 부하 분산이 필요한 애플리케이션은 세션 정보를 공유할 다른 방법을 찾거나 세션 및 연결 시간 초과를 늘려야 하며, 결국 사용자 기반을 지원하는 데 필요한 서버 수가 관리할 수 없을 정도로 빠르게 늘어나게 됩니다.
가장 일반적인 지속성 형태는 HTTP 헤더에 전달된 세션 ID를 사용하여 구현되지만, 오늘날 ADC는 다른 데이터에도 지속성을 유지할 수 있습니다. 쿠키에 저장되거나 IP, TCP 또는 HTTP 헤더에서 파생된 모든 데이터를 사용하여 세션을 유지할 수 있습니다. 실제로 사용자를 고유하게 식별하는 애플리케이션 메시지 내의 모든 데이터는 지능형 ADC를 통해 브라우저와 서버 간의 연결을 유지하는 데 사용될 수 있습니다.
HTTP는 상태 없는 프로토콜일 수 있지만, 우리는 보편적인 프로토콜에 상태를 강제로 맞추는 데 성공했습니다. 지속성과 애플리케이션 제공 컨트롤러를 사용하면 쿠키와 세션의 다소 취약한 통합을 깨지 않고도 고가용성, 고성능 웹 애플리케이션을 설계할 수 있습니다.
이러한 기능은 HTTP 상태를 제공하지만 구현과 실행은 상태 비저장 상태로 유지됩니다. 쿠키, 세션, 지속성이 없었다면 우리는 분명 애플리케이션을 구축할 수 있는 상태 기반 프로토콜을 찾았을 것입니다. 대신 애플리케이션 전송 컨트롤러(Application Delivery Controllers)에서 제공되는 기능과 기능은 브라우저(클라이언트)와 서버 사이를 중재하여 이러한 기능을 제공하며, HTTP의 유용성을 정적 웹 페이지와 기존 애플리케이션을 넘어 최신 마이크로서비스 기반 아키텍처와 디지털 경제의 총아인 API로 확장합니다.