실시간 AI 에이전트는 왜 QPS만 보고 분산하면 무너질까? 활성 세션 기반 라우팅 체크리스트

읽는 시간 약 9분 · 실시간 AI 운영 체크리스트

먼저 답부터 말씀드리면: WebSocket·gRPC 기반의 실시간 AI 에이전트는 QPS나 CPU만 보고 새 연결을 분산하면 안 됩니다. 애플리케이션이 정의한 활성 세션을 자원 압력, 새 세션 수락률, 스트림 시작 지연과 함께 보고, 종료 처리를 한 번만 반영하도록 설계해야 합니다.

음성 상담이나 실시간 대화 에이전트를 여러 인스턴스로 늘리는데, 대시보드의 QPS와 CPU는 낮은데도 어느 순간 응답이 밀리는 일이 있습니다. 이때 팀이 답해야 할 질문은 단순합니다. 새 연결은 어느 백엔드로 보내고, 언제 받기를 멈추며, 끊긴 세션은 어떻게 정확히 빼야 할까요?

QPS와 CPU, 활성 세션을 함께 확인하는 실시간 AI 에이전트 운영 대시보드 개념도

핵심 요약

  • QPS는 들어오는 요청의 속도를 보여 주지만, 이미 약속한 긴 대화의 양은 보여 주지 못합니다.
  • CPU·메모리는 현재 압력을 보여 주지만, 무음 상태의 음성 세션이 동시에 발화할 위험은 놓칠 수 있습니다.
  • 활성 세션은 애플리케이션이 실제로 책임지는 동시 작업량입니다. 연결 수와 같은 뜻으로 쓰면 안 됩니다.
  • 새 연결 배정은 단일 지표가 아니라 세션 상한, 자원 압력, 메트릭 신선도, 시작 지연을 함께 보는 보수적 규칙이 안전합니다.
  • 부하 시험은 짧은 요청 폭주만으로 끝내지 말고, 세션 길이·무음·취소·재연결을 섞어야 합니다.

목차

  1. 짧은 API와 장기 스트림이 다른 이유
  2. 지표별 역할과 단독 사용의 함정
  3. 세션 계수 규약: 한 번만 더하고 한 번만 빼기
  4. 새 연결 수락·drain을 정하는 운영 체크리스트
  5. 현실적인 부하 시험 설계
  6. 과도한 설계를 피해야 하는 경우
  7. 자주 묻는 질문

왜 QPS와 CPU만으로는 부족할까요?

일반 HTTP API는 요청이 들어오고, 처리하고, 응답하면 끝나는 경우가 많습니다. 그래서 요청 수와 처리 시간이 용량의 좋은 출발점이 됩니다. 반면 WebSocket·gRPC 기반의 실시간 AI는 연결이 유지되는 동안 오디오 조각, 중간 전사, 모델 출력, 도구 호출, 음성 합성이 이어질 수 있습니다.

Google Developers Blog도 이런 장기 양방향 스트림에서는 지연 시간·QPS·CPU만으로 약속된 작업량을 설명하기 어렵고, 런타임이 아는 활성 세션 신호를 함께 다뤄야 한다고 설명합니다. 여기서 중요한 것은 네트워크 연결이 아니라 서비스가 지금 끝까지 책임져야 하는 대화 단위입니다.

운영 기준 한 문장: 활성 세션은 “사용자 연결이 열렸을 때”가 아니라, 서비스가 처리 준비를 마치고 자원을 약속한 순간부터 종료가 확정된 순간까지로 정의하는 편이 좋습니다. 이 정의는 제품과 런타임에 맞게 팀이 문서로 합의해야 합니다.

지표는 경쟁하지 않습니다. 역할이 다릅니다.

지표 알려주는 것 단독 사용 시 놓치는 것 운영 경고
QPS 새 요청·연결의 유입 속도 이미 유지 중인 긴 대화의 누적 부담 QPS가 낮아도 세션이 계속 쌓이면 신규 배정을 줄입니다.
CPU·메모리 현재 처리 압력과 메모리 여유 무음 세션이 동시에 활성화될 미래 부담 짧은 급등이 반복되면 세션 상한과 함께 안전 여유를 둡니다.
활성 세션 백엔드가 약속한 동시 대화량 각 세션의 순간 비용 차이 계수 정확도가 의심되면 신규 수락보다 측정 복구를 우선합니다.
새 세션 수락률 최근에 늘어난 약속의 속도 기존 세션의 품질 저하 짧은 시간에 급증하면 점진 배정 또는 대기열을 검토합니다.
p95 첫 스트림 시간·drop rate 독자가 체감하는 시작 품질과 이탈 왜 그런 현상이 생겼는지 세션 분포·자원 압력과 같은 시점으로 비교합니다.

예를 들어 인스턴스 A에 무음 상태의 긴 음성 세션이 많이 남아 있다면 CPU는 낮게 보일 수 있습니다. 하지만 사용자가 동시에 말하기 시작하면 추론·음성 처리 비용이 한꺼번에 올라갈 수 있습니다. 반대로 CPU가 잠시 높아도 활성 세션이 적고 감소 추세라면, 즉시 차단보다 관찰 창을 두는 편이 나을 수 있습니다.

세션 계수는 이벤트가 아니라 상태 전이로 관리하세요

유령 세션은 단순한 메모리 문제가 아닙니다. 잘못 남은 숫자가 라우터에게 “여기는 이미 가득 찼다”는 잘못된 신호를 보냅니다. 반대로 두 번 감소하면 실제보다 빈 자리가 많아 보이고, 새 연결이 몰릴 수 있습니다.

실시간 AI 세션의 연결, 준비, 취소, 시간 초과, 종료 상태 전이 다이어그램

이벤트 권장 상태 변화 계수 처리 멱등성 확인
connect 연결됨 → 검증 중 아직 증가하지 않거나 별도 연결 계수만 기록 같은 연결 재시도는 같은 세션 식별자로 묶습니다.
ready 검증 중 → 활성 활성 세션을 한 번 증가 활성 전환 기록이 있으면 재증가하지 않습니다.
cancel·timeout·disconnect 활성 → 종료 중 → 종료됨 종료 확정 시 한 번 감소 종료 토큰 또는 compare-and-set으로 첫 종료만 반영합니다.
정리 실패 종료 중이 오래 지속 자동 보정 후보로 표시 로그·트레이스와 대조한 뒤 보수적으로 복구합니다.

구현 언어보다 규약이 먼저입니다. 세션마다 추적 ID를 두고, ready 이전 연결·헬스 체크·실패한 인증을 활성 세션에 섞지 않는지 확인하세요. 종료 경로가 여러 개인 경우에는 모두가 동일한 “종료 확정” 함수를 호출하도록 모으는 편이 안전합니다. 취소와 시간 초과가 동시에 와도 한 번만 감소해야 합니다.

새 연결을 받을지, drain할지 정하는 기준

활성 세션 수만으로 순위를 매기면 세션 비용 차이를 놓칩니다. 반대로 CPU만 보면 조용하지만 이미 많이 약속한 인스턴스를 과대평가합니다. 따라서 각 백엔드에 대해 세션 여유와 현재 자원 압력이 모두 안전한가를 먼저 묻는 혼합 기준이 필요합니다.

활성 세션과 자원 사용률을 함께 반영하는 실시간 AI 백엔드 라우팅 흐름도

새 연결 수락 전 체크리스트

  • 활성 세션이 팀이 실험으로 정한 상한보다 낮은가?
  • CPU·메모리·이벤트 루프 지연 같은 자원 신호가 목표 범위 안에 있는가?
  • 세션 메트릭의 수집 시각이 너무 오래되지 않았는가?
  • 최근 첫 스트림 시간이 나빠지거나 끊김이 늘지 않았는가?
  • 어느 신호가 비어 있거나 의심스러울 때, 더 낙관적인 인스턴스가 아니라 보수적 fallback으로 보낼 수 있는가?
FLOWIT 실무 관점: 이 기준은 성능 문제만이 아닙니다. 세션이 오래 남으면 모델 호출 비용, 사용자 대화 문맥, 도구 실행 권한이 함께 남습니다. 수락 중단과 drain은 서버를 보호하는 장치이면서, 권한이 남은 장기 작업을 통제하고 서비스 품질 약속을 지키는 운영 장치입니다.

drain은 기존 세션을 곧바로 끊는다는 뜻이 아닙니다. 새 연결 배정만 중단하고, 이미 진행 중인 대화가 안전하게 끝나도록 기다리는 단계로 설계할 수 있습니다. 메트릭이 지연되거나 계수 오류가 의심될 때는 무작정 새 연결을 받기보다, 명확한 재시도 안내나 대체 경로를 제공하는 편이 신뢰를 지키기 쉽습니다.

부하 시험은 ‘짧은 폭주’보다 ‘긴 대화의 현실성’이 중요합니다

짧은 요청을 많이 보내는 시험은 최대 처리량을 보는 데 도움이 되지만, 실시간 대화의 실패 조건을 그대로 재현하지 못합니다. 다음 매트릭스를 한 번에 모두 최고치로 올리기보다, 한 변수씩 바꾸며 세션 분포와 시작 품질을 기록해 보세요.

시험 변수 바꿀 값 관찰 지표 통과 또는 중단 기준
동시 세션 낮음·보통·목표 상한 근처 백엔드별 세션 분포, 수락률 한 인스턴스에 장기 세션이 치우치면 라우팅 규칙을 점검합니다.
세션 길이 짧음·중간·긴 대화 종료 후 계수 복구, 메모리 종료 뒤 계수가 원래 범위로 돌아오는지 확인합니다.
무음·동시 발화 무음 비율과 동시 활성화 시점 CPU 급등, 첫 스트림 시간 무음 상태만 보고 신규 배정을 늘리지 않았는지 확인합니다.
취소·재연결 정상 종료·중간 취소·즉시 재접속 이중 감소, 유령 세션, drop rate 동일 세션이 두 번 빠지거나 남지 않아야 합니다.

이 설계를 바로 도입하지 않아도 되는 경우

모든 에이전트가 세션 기반 라우팅을 필요로 하지는 않습니다. 작업이 수 초 내 끝나는 단발성 배치, 동시성이 매우 낮은 내부 도구, 연결을 유지하지 않는 API라면 먼저 기본적인 요청 제한·관측·오류 복구를 갖추는 편이 낫습니다. 복잡한 계수기는 그 자체로 장애 지점이 될 수 있기 때문입니다.

다만 음성·실시간 상담·지속 스트림처럼 한 연결이 오랫동안 문맥과 자원을 잡는 서비스라면, ‘현재 얼마나 바쁜가’와 ‘이미 무엇을 약속했는가’를 분리해 보는 순간 운영 판단이 훨씬 선명해집니다.

첫 주에 실행할 최소 점검

  1. 활성 세션의 시작·종료 정의를 한 문장으로 합의합니다.
  2. ready·cancel·timeout·disconnect를 포함한 상태 전이 로그를 샘플링합니다.
  3. 각 백엔드의 활성 세션, CPU·메모리, 첫 스트림 시간, 끊김을 같은 시간축에 놓습니다.
  4. 한 대의 백엔드를 drain한 뒤 기존 대화 종료와 신규 연결 우회가 기대대로 작동하는지 확인합니다.
  5. 무음·취소·재연결이 섞인 작은 부하 시험부터 반복합니다.

자주 묻는 질문

세션 affinity를 쓰면 활성 세션 기반 라우팅은 필요 없나요?

필요할 수 있습니다. Kubernetes의 session affinity는 특정 클라이언트 요청을 같은 Pod로 보내는 특성에 가깝습니다. 이는 대화 문맥 유지에는 도움이 될 수 있지만, 그 Pod가 새 장기 세션을 더 받을 여유가 있는지까지 판단해 주지는 않습니다.

활성 세션 상한은 몇 개로 정해야 하나요?

모든 서비스에 같은 숫자를 적용하면 안 됩니다. 모델 크기, 음성 처리, 도구 호출, 인스턴스 사양, 목표 응답 품질이 다르므로 실제 대화 패턴을 섞은 시험으로 시작점과 안전 여유를 정해야 합니다.

연결 수를 활성 세션으로 대신 세어도 되나요?

권장하지 않습니다. 인증 실패, 준비 전 연결, 헬스 체크, 재시도 연결, 이미 종료된 스트림이 섞일 수 있습니다. 서비스가 실제로 처리 책임을 가진 상태를 별도로 정의하는 편이 정확합니다.

메트릭 수집이 늦으면 어떻게 해야 하나요?

늦은 수치로 공격적으로 신규 배정하면 위험합니다. 수집 시각을 함께 기록하고, 신호가 오래됐거나 누락됐을 때는 수락을 줄이거나 대체 경로로 보내는 보수적 규칙을 준비하세요.

마무리

실시간 AI 운영에서 QPS는 유입을, CPU는 현재 압력을, 활성 세션은 이미 약속한 동시성을 보여 줍니다. 이 세 가지를 함께 보되, 정확한 종료 계수와 현실적인 부하 시험을 갖추는 것이 먼저입니다. 그 다음에야 새 연결 배정과 drain이 팀의 감이 아니라 반복 가능한 운영 기준이 됩니다.

함께 읽으면 좋은 글

참고 자료

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

FLOWIT on YouTube

영상으로도 FLOWIT을 이어서 보세요

AI 자동화, Claude Code, n8n, 데이터 분석 흐름을 블로그와 영상으로 함께 정리하고 있습니다.

YouTube 채널 보기