서버 과부하로 확장할 때, 로드 밸런싱에 의해 분산된 두 연결을 다루는 방법과 핵심 플래그 두 가지의 중요성
요약
서버 과부하로 확장 시, 로드 밸런싱에 의해 분리된 두 연결(GET SSE 및 POST)을 다루는 방법을 설명합니다. MCP 클라이언트가 여러 인스턴스를 필요로 할 때 발생하는 상태 관리 문제를 지적하며, 이를 해결하기 위해 `stateless_http`와 같은 핵심 플래그의 이해가 필수적임을 강조하는 개발 가이드입니다.
핵심 포인트
- 확장은 단순히 기계를 추가하는 것이 아니라 프로토콜 이해가 필요합니다.
- 로드 밸런싱은 두 개의 연결을 서로 다른 인스턴스로 분산시킬 수 있습니다.
- 인스턴스 간 협조(예: 샘플링)는 상태 관리의 복잡성을 높입니다.
- `stateless_http=True`는 이러한 협조 문제를 제거하는 해결책이 될 수 있습니다.
서버가 과부하되어 확장을 할 때, 로드 밸런싱으로 분리된 두 연결은 어떻게 해야 할까? 답은 두 개의 플래그를 이해하는 것이다.
이 글은 Anthropic Academy의 《Model Context Protocol: Advanced Topics》 제13과 실습 교육 내용입니다. 제목을 직역하면 《State and the StreamableHTTP transport (상태와 StreamableHTTP 전송)》입니다. 결론부터 말씀드리겠습니다. 이 내용은 상식에 반하는 부분이 있습니다:
확장은 단순히 기계를 추가한다고 끝나는 것이 아닙니다. MCP 클라이언트가 두 개의 연결을 필요로 할 때, 로드 밸런싱은 이를 서로 다른 인스턴스로 분산시킬 수 있습니다. 이때 도구가 샘플링(sampling)할 때, 요청을 처리하는 인스턴스와 푸시 채널을 처리하는 인스턴스가 서로 협조해야 하는데, 이 협조가 너무 복잡해지면 상태 비저장 HTTP(stateless HTTP)가 기능과 확장을 교환하는 해결책이 됩니다.
먼저 용어를 명확히 하겠습니다. **State (상태)**란 서버가 특정 클라이언트가 누구인지, 연결이 어느 단계까지 진행되었는지 기억할 수 있는 능력을 말합니다. **stateless_http (무상태 HTTP)**는 상태 추적을 비활성화한 설정으로, 서버가 개별 클라이언트를 더 이상 기억하지 않게 됩니다. **json_response (JSON 응답)**는 POST 응답 스트리밍 전송을 비활성화하고 최종 결과만 담긴 순수 JSON만을 반환하는 설정입니다. **로드 밸런싱(load balancing)**은 클라이언트의 요청을 여러 서버 인스턴스로 분산시키는 방식입니다.
실제 예시를 들어보겠습니다. 서버가 과부하되어 수많은 클라이언트가 단일 인스턴스를 감당할 수 없을 때, 일반적인 해결책은 다중 인스턴스와 로드 밸런싱을 사용하는 것입니다. 하지만 MCP 클라이언트는 두 개의 연결이 필요합니다. 하나는 GET SSE를 통해 서버에서 시작하는 메시지를 받고, 다른 하나는 POST를 통해 도구 응답을 받는 방식입니다. 로드 밸런싱은 이 두 요청을 서로 다른 인스턴스로 분산시킬 수 있습니다. 만약 도구가 Claude를 샘플링해야 한다면, POST를 처리하는 인스턴스는 GET SSE를 처리하는 인스턴스와 협조해야 하는데, 이는 매우 복잡합니다.
그들은 사람들이 흔히 오해하는 '익숙한 구식 경로'도 지적했습니다. 확장한다는 것은 무조건 수평적으로 기계를 추가하고 기능은 변하지 않을 것이라고 생각하는 것입니다. 공식적인 비판은 매우 직설적입니다: 두 플래그의 근본적인 역할은 서버의 동작 방식을 제어하는 데 있습니다. 확장을 하거나 프로덕션에 배포하기 전에 이 두 가지를 반드시 이해해야 하며, 그렇지 않으면 기계를 추가하는 것이 곧 장애를 추가하는 것과 같습니다.
모든 상황에서 무상태(stateless)여야 하는 것은 아닙니다. 다음 조건 중 어느 하나라도 충족될 때만 고려할 가치가 있습니다:
- 로드 밸런싱을 통한 수평 확장이 필요하여 단일 인스턴스가 감당하기 어려울 때;
- 서버가 클라이언트로 통신할 필요가 없을 때;
- 도구가 AI 샘플링이 필요하지 않아 연결 오버헤드를 줄이고 싶을 때.
1. 무분별한 확장으로 인한 세 가지 실패 방식
- 두 연결의 분리: GET SSE와 POST가 서로 다른 인스턴스로 분산되어, 서버에서 시작하는 메시지를 찾지 못하게 됩니다.
- 샘플링 협조 실패: 도구 요청을 처리하는 인스턴스가 샘플링해야 하는데, 푸시 채널을 처리하는 인스턴스와 협조해야 하므로, 협조가 엉망이 되어 샘플링에 실패합니다.
- 개발 환경과 프로덕션 동작 불일치: 로컬에서는 상태를 사용해 개발하고, 프로덕션에서는 무상태로 배포하여, 동작 방식의 차이가 실제 서비스에서 터져 나옵니다.
2. 대안 방안: 두 플래그와 그에 따르는 비용을 계산한 후 적용하기
stateless_http=True를 사용할 때의 해결책과 비용은 다음과 같습니다: 협조 문제를 제거하지만, 클라이언트가 세션 ID를 얻지 못하고 서버는 개별 클라이언트를 추적할 수 없게 됩니다. 서버에서 클라이언트로 요청이 오가지 않으므로 GET SSE 채널을 사용할 수 없습니다. 샘플링이 불가능하여 Claude 같은 모델을 사용할 수 없고, 진행 상황 보고도 할 수 없으며, 구독 기능으로 리소스 업데이트를 알릴 수도 없습니다. 유일한 장점은 클라이언트가 초기화할 필요 없이 바로 요청을 보낼 수 있다는 것입니다. json_response=True는 더 간단합니다: POST 응답의 스트리밍 전송만 비활성화하는 것입니다. 도구가 실행되는 과정에서 여러 개의 SSE 메시지가 발생하지 않고, 최종 결과만 담긴 순수 JSON만 남습니다. 중간 진행 메시지도 없고, 실행 기간 로그도 없으며, 오직 최종 도구 결과만 있습니다. 두 플래그가 하는 일은 동일합니다: 기능을 단순함과 교환하는 것입니다. 그러므로 이전에 그 비용들을 먼저 나열해야 합니다.
3. 목표 형태: 필요에 따라 플래그를 선택하고, 유행을 따르지 않기
이상적인 상태는 플래그 선택에 기준이 있는 경우입니다: 로드 밸런싱을 통한 수평 확장이 필요하고, 서버가 클라이언트로 통신할 필요가 없으며, 도구가 AI 샘플링이 필요하지 않아 연결 오버헤드를 줄이고 싶을 때, 무상태 HTTP를 사용합니다. 스트리밍 응답이 필요 없고, 간단한 비스트리밍 응답을 선호하며, 연동 요구사항이 순수 JSON인 시스템에서는 JSON 응답을 사용합니다. 표준(기준)을 먼저 정하고 플래그를 적용해야 하며, 그 반대는 안 됩니다.
4. 세 단계로의 전환: 단일 인스턴스로부터 확장으로, 동작 차이를 먼저 검증하기
첫 번째 단계: 상태에 의존하는 기능을 나열하기
샘플링, 진행 상황, 구독, 서버에서 시작하는 요청 등 상태에 의존하는 모든 것을 먼저 목록화합니다.
두 번째 단계: 표준에 따라 플래그를 선택하고, 둘 다 활성화하지 않기
무상태와 JSON 응답은 각각 비용이 있으므로, 정말 필요한 것만 켜고, 편의를 봐서 두 가지 모두 활성화해서는 안 됩니다.
세 번째 단계: 프로덕션과 동일한 전송 방식으로 한 번 테스트하기
로컬에서 STDIO로 개발하고 프로덕션에서 HTTP로 배포할 때는 반드시 프로덕션과 동일한 전송 방식으로 테스트해야 합니다. 상태 기반과 무상태의 동작 차이는 매우 크므로, 개발 단계에서 발견하는 것이 상선 후에 발견하는 것보다 훨씬 좋습니다.
5. 팀이 어떻게 동일한 확장 습관을 구축할 수 있을까
확장의 가장 큰 함정은 기술 자체가 아니라, 개발과 프로덕션이라는 두 개의 피부를 가진 것입니다: 개발은 상태 기반으로 작성하고, 프로덕션은 무상태로 실행합니다. 팀은 먼저 세 가지 사항에 대해 합의해야 합니다: 플래그 값 설정 내용을 배포 목록에 포함시키고, 변경되면 반드시 심사를 거치게 할 것; 상태 의존 기능 목록을 플래그와 함께 전달할 것; 상선 전에 프로덕션과 동일한 전송 방식으로 한 번 검증하고, 개발 환경 설정을 사용해 프로덕션을 테스트하지 않을 것.
6. 공식 도구 키트 외에 기억해야 할 사항
이 강의에서는 완벽한 도구 상자를 제공하지 않았지만, 경계는 매우 명확하게 설명했습니다: 두 플래그는 서버의 동작 방식을 제어하는 것이지, 작은 스위치가 아닙니다. 확장을 하기 전에 이들을 이해하는 것이 확장 자체보다 더 중요합니다. 개발과 프로덕션의 일치성은 마지막 방어선입니다.
결론: 원칙이 구조보다 중요하다
확장은 기계를 추가하는 것이 아니라 행동 방식을 바꾸는 것이다. 원칙이 아키텍처보다 중요하다—먼저 기능적 대가를 명확히 계산한 후, 플래그(flag)를 열지 여부를 결정해야 한다. 기계를 많이 추가할수록, 그 대가가 명확하게 계산되지 않으면 장애가 더 많아진다.
반복 가능한 행동 규칙은 다음과 같다: 다음 확장 전에 세 가지 질문을 먼저 던져야 한다—의존성 상태(dependency status) 기능 목록이 작성되었는가, 플래그를 필요한 것만 열었는가, 프로덕션 환경에서 동일한 방식으로 테스트했는가? 이 세 가지에 모두 답할 수 있을 때만 확장이 허용된다.
원본 링크: https://t.co/mLgqaNisz4
원본: Anthropic Academy (S1哥 편집)
AI 자동 생성 콘텐츠
본 콘텐츠는 X Claude/Anthropic의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기