LLM 게이트웨이 상용화하기: 아키텍처, 트레이드오프 그리고 뼈아픈 교훈들 — 카니시 마누자(Kanish Manuja), 트윌리오(Twilio)
AAI Engineer
Computing/SoftwareManagementInternet Technology
Transcript
00:00:00저는 트월리오의 수석 엔지니어 가네쉬 마누자입니다. 간단히 손을 들어 시작해 보겠습니다.
00:00:20“문제가 발생했습니다. 다시 시도해 주세요”라는 메시지를 보신 분 계신가요?
00:00:27음, 몇 분의 행운아 분들과 점심을 맛있게 드신 분들이 계시는군요.
00:00:33사실 그 단순한 메시지 이면에는 모델 제공업체들이 다운된 상황에서도 여러분께 그 메시지를 전달하는 매우 복잡한 시스템이 숨겨져 있습니다.
00:00:45그리고 그것이 오늘 우리가 프로덕션 환경에 적용하거나 논의할 내용입니다.
00:00:50그렇다면 LLM 게이트웨이란 무엇일까요?
00:00:52LLM 게이트웨이는 애플리케이션과 그 배후의 모델 제공업체 사이에 위치한 진입점이자 미들웨어입니다.
00:00:58라우팅, 인증, 폴백, 속도 제한 등 생각할 수 있는 온갖 거버넌스 작업을 수행합니다.
00:01:08그리고 게이트웨이의 핵심에는 네 가지 요소 간의 치열한 줄다리기가 있습니다.
00:01:13가용성, 지연 시간, 가드레일, 그리고 비용입니다.
00:01:18성능 저하가 발생할 경우, 이 네 가지를 모두 극대화할 수는 없습니다.
00:01:22원하는 것을 선택해야 합니다.
00:01:25따라서 이 강연을 통해 LLM 게이트웨이를 사용할 때 여러분의 유스케이스에 맞춰 그러한 트레이드오프를 결정할 수 있도록 돕고자 합니다.
00:01:35또한 게이트웨이를 설계한다면, 고객이 만족할 수 있도록 호출자와 고객에게 그러한 제어 수단을 설계하여 제공해야 합니다.
00:01:46가용성부터 시작하겠습니다.
00:01:50단일 모델 제공업체를 이용하는 경우, 그들의 한계가 곧 여러분의 한계가 됩니다.
00:01:56그들의 장애가 곧 여러분의 장애입니다.
00:02:03따라서 일반적인 소프트웨어 공학에서 신뢰할 수 없는 의존성을 다루는 방법은 재시도입니다.
00:02:11지터(임의성)를 포함한 지수 백오프를 사용한 재시도 말이죠.
00:02:15그리고 그 모든 것이 실패하면, 충분한 실패가 감지된 후 작동하는 서킷 브레이커를 통해 해당 시스템 호출을 중단합니다.
00:02:24이것만으로는 LLM에 충분하지 않습니다.
00:02:26LLM은 재시도를 수행하는 빠르고 저렴한 API들과는 매우 다릅니다.
00:02:32LLM API를 재시도하는 것은 지연 시간 예산을 정말 빠르게 갉아먹습니다.
00:02:38또한 라우팅할 수 있는 다른 훌륭한 모델 제공업체가 있는데도 서킷 브레이커를 작동시키는 것은 말이 되지 않습니다.
00:02:47두 번째 모델 제공업체를 사용해야 합니다.
00:02:48그리고 세 번째로, 앞서 말씀드렸듯이 호출은 느리고 비용이 많이 듭니다.
00:02:53따라서 맹목적인 재시도는 비용과 테일 지연 시간을 배로 증가시킬 뿐입니다.
00:02:58그렇다면 더 나은 아이디어는 무엇일까요?
00:03:02실제로 요청별 폴백(per request fallback)을 사용하는 것입니다.
00:03:05모델 제공업체 A를 먼저 시도하고, 모델 제공업체 A에 대한 요청이 실패할 경우 순차적으로 모델 제공업체 B를 시도하는 것을 의미합니다.
00:03:14여기서 고려할 수 있는 또 다른 옵션은 두 제공업체에 병렬로 요청을 보낼 수 있다는 점이지만, 이는 단순히 비용을 두 배로 만들 뿐이므로 지연 시간에 극도로 집착하는 경우에만 해당합니다.
00:03:26LLM에도 유사한 서킷 브레이킹 패턴 중 일부가 적용됩니다.
00:03:32기본 제공업체가 한동안 실패하고 있다는 것을 안다면, 다시 시도하는 것은 의미가 없습니다.
00:03:40부하 분산기나 요청 경로에서 제외하여 쿨다운 상태에 두고, 몇 분이 지난 후에 다시 투입을 시도하는 것입니다.
00:03:51여기서 내려야 할 흥미로운 선택지 중 하나는 실패 횟수를 어디에 저장할 것인가입니다.
00:03:59트래픽을 처리하는 인스턴스의 메모리에 실패 횟수를 저장하거나, 전체 플릿에 걸쳐 실패 횟수가 공유되는 공유 정보를 사용할 수 있습니다.
00:04:12각각의 트레이드오프가 존재합니다.
00:04:14빠른 장애 조치를 원한다면 플릿 전체를 활용하는 것이 도움이 됩니다.
00:04:19그리고 인스턴스별 로컬 상태 카운터를 사용할 때 직면하는 문제는 배포 크기를 변경할 때마다 설정과 기대치가 바뀐다는 점입니다.
00:04:30따라서 고려해야 할 사항입니다.
00:04:34앞서 본 깔끔한 다이어그램이 실제로 보여주지 못한 다른 함정들에 대해 논의해 보겠습니다.
00:04:39즉, 폴백은 투명하지 않습니다.
00:04:41업계가 OpenAI API 호환 형식으로 수렴하고 있지만, 여전히 미묘한 차이들이 존재합니다.
00:04:49따라서 폴백을 철저하게 테스트해야 합니다.
00:04:52도구 호출(tool calling) 스키마, 토큰 제한, 중단 이유 등에서 차이가 발생할 수 있습니다.
00:04:58따라서 LLM 게이트웨이를 사용하면 공급자 간 폴백도 원활하게 수행할 수 있도록 보장하는 정규화 계층을 둘 수 있습니다.
00:05:08또 다른 요소는 스트리밍입니다.
00:05:15기본적으로 아무도 30초 동안 기다려 자신 앞에 텍스트 벽이 나타나는 것을 원하지 않습니다.
00:05:22따라서 스트리밍이 절대적으로 필요한 유스케이스가 존재합니다.
00:05:26하지만 대가가 따릅니다.
00:05:27제어 수단을 포기해야 합니다.
00:05:29제공업체 A를 선택하기로 결정했다면, -- 일단 시작한 이상 계속해서 제공업체 A를 고수해야 합니다.
00:05:36스트리밍 도중에 제공업체를 변경할 수 없습니다.
00:05:39클라이언트에게 이미 전송된 내용은 그것으로 끝입니다.
00:05:42그리고 그것이 바로 “문제가 발생했습니다”라는 메시지가 나오는 이유입니다.
00:05:46보게 되는 메시지가 바로 그것입니다.
00:05:48게을러서 그런 것이 아닙니다.
00:05:49설계상 그렇게 보이도록 되어 있는 것입니다.
00:05:52그리고 이는 트레이드오프 중 하나입니다.
00:05:54팀들이 반복해서 실수를 저지르는 또 다른 부분을 짚어보고 싶습니다.
00:06:00그들은 기본 제공업체는 정말 잘 프로비저닝하고 테스트합니다.
00:06:05하지만 두 번째 제공업체, 즉 폴백 제공업체에는 반드시 그만큼의 관심과 노력을 쏟지 않습니다.
00:06:11저는 두 번째 제공업체나 폴백 제공업체의 처리량, 용량, 여유 공간(headroom)이 훨씬 더 높아야 한다고 주장하고 싶습니다.
00:06:21그것이 최후의 방어선이기 때문입니다.
00:06:23거기가 다운되면 여러분의 애플리케이션도 다운됩니다.
00:06:29지연 시간에 대해 논의해 봅시다.
00:06:31가용성 장애는 눈앞에 바로 드러납니다.
00:06:34실패가 발생합니다.
00:06:36경고를 받게 됩니다.
00:06:37호출(페이징)을 받게 됩니다.
00:06:38하지만 높은 지연 시간은 조용히 다가올 수 있습니다.
00:06:42따라서 단순히 가용성에만 맞춰 서비스를 튜닝하는 것보다 지연 시간에 더 많은 신경을 써야 한다고 말씀드리고 싶습니다.
00:06:49한 가지 짚고 넘어가야 할 점이 있습니다.
00:06:54게이트웨이는 혼합된 워크로드를 실행할 수 있습니다.
00:06:581초도 채 걸리지 않는 임베딩 요청이 있을 수 있습니다.
00:07:04역시 1초 미만이 소요되는 분류 요청이 있을 수 있습니다.
00:07:073초가 걸리는 챗 요청이 있습니다.
00:07:10그리고 오랜 시간이 걸리는 추론 요청이 있습니다.
00:07:13간단히 손을 들어보세요.
00:07:15전체 서비스에 대한 종합적인 지연 시간을 측정하시는 분들은 손을 들어주세요.
00:07:20글쎄요, 그것은 함정 질문이었습니다.
00:07:23죄송합니다.
00:07:24측정하시면 안 됩니다.
00:07:25말이 되지 않습니다.
00:07:26거짓말입니다.
00:07:27게이트웨이 전체 수치가 아니라, 모델별 경로별로 P99를 추적해야 합니다.
00:07:32게이트웨이 전체 수치는 특히 혼합된 워크로드를 실행하는 경우 의미가 없습니다.
00:07:36손을 드신 분들 중 설마 그러고 계시진 않기를 바랍니다.
00:07:40정말 강조하고 또 강조하고 싶은 또 다른 점은 모델 클래스별, 경로별로 타임아웃을 설정해야 한다는 것입니다.
00:07:49바로 그것이 조용한 장애의 근본 원인 1순위입니다.
00:07:54타임아웃이 없으면 게이트웨이는 요청이 잘 처리되고 있다고 생각하지만, 실제로는 그렇지 않습니다.
00:08:00지연 시간과 관련해 이 메시지를 남기고 싶습니다.
00:08:05추론 모델의 평상시 상태는 사실상 챗 모델의 장애 상태와 같습니다.
00:08:09따라서 경로별로 지연 시간을 반드시 추적해야 합니다.
00:08:13좋습니다, 이 슬라이드는 가장 고통스러웠거나 저에게 가장 식은땀을 흘리게 만든 슬라이드인데, 바로 추론 모델과 라우터 모델에 관한 것입니다.
00:08:24여기가 진정으로 지연 시간을 예측할 수 없는 영역입니다.
00:08:29추론 모델은 결과를 예측하기 어렵고, 일반 모델보다 훨씬 더 비결정론적입니다.
00:08:40많은 경우 온도(temperature)를 0으로 설정할 수 없습니다.
00:08:43그리고 동일한 프롬프트가 2초에서 60초까지 걸릴 수 있습니다.
00:08:48프로덕션 환경에서 뚜렷한 이유 없이 P99가 갑자기 60초로 치솟는 현상을 목격하기도 했습니다.
00:08:53마법 같은 해결책은 없지만, 적어도 경로별 추론 수준을 수정하는 것부터 시작할 것을 권장합니다.
00:09:03라우터 모델의 경우, 어떤 모델을 실행할지 선택하는 추상화 계층을 여러분 뒤에 숨겨줍니다.
00:09:08예를 들어 실행할 모델을 직접 선택하는 식입니다.
00:09:11비결정론적인 시스템 속에서 최대한 결정론적인 방식으로 요청을 만들도록 신경 쓰라고 강력히 권장하고 싶습니다.
00:09:23또 다른 아이디어는 테일 지연 시간 헤징(hedging)입니다.
00:09:26기본 요청이 지연 시간 예산의 예를 들어 P90을 소모했다면, 또 다른 요청을 추가로 보낼 수 있습니다.
00:09:37이렇게 하면 서비스의 P99 테일 지연 시간을 효과적으로 헤지할 수 있습니다.
00:09:44좋습니다, 제가 가장 좋아하는 주제 중 하나입니다.
00:09:47모델을 안전하게 유지하려면 가드레일이 필요합니다.
00:09:53이를 통해 프롬프트 인젝션 공격으로부터 서비스를 방어하고, PII 필터를 유지하며, 유해성 필터를 적용해 LLM이 고객에게 욕설을 하지 못하도록 막는 등의 가드레일이 필수적입니다.
00:10:08이러한 모든 유익한 기능들이죠.
00:10:11하지만 모델 제공업체와 마찬가지로 여기에도 트레이드오프가 존재합니다.
00:10:15가드레일도 하나의 서비스와 같습니다.
00:10:18다운될 수도 있습니다.
00:10:19신뢰할 수 없을 수도 있죠.
00:10:21그래서 선택을 내려야 합니다.
00:10:24Fail Open(오픈 실패)으로 갈 것인가, Fail Close(클로즈 실패)로 갈 것인가?
00:10:27Fail Open이란 가드레일이 다운되더라도 요청을 계속해서 처리하는 것을 말합니다.
00:10:32Fail Close란 요청을 차단하고 “이용할 수 없습니다”라고 응답하는 것입니다.
00:10:36어느 정도는 가용성과 보안 사이의 트레이드오프라고 볼 수 있습니다.
00:10:41정답은 없으며, 실제 사용 사례에 따라 다릅니다.
00:10:45예를 들어 유해성 필터의 경우, 작동하지 않더라도 요청을 계속 처리할 수 있습니다.
00:10:53따라서 기본 선택은 감당할 수 있는 최악의 상황을 기준으로 해야 합니다.
00:11:02가드레일이 중단되거나 가드레일 자체의 안정성이 떨어질 때 시스템의 동작을 개선하기 위해 실제로 할 수 있는 몇 가지 방법이 있습니다.
00:11:17첫 번째는 시간 예산입니다.
00:11:20요청이 가드레일 타이밍에 묶여서는 안 됩니다.
00:11:25항상 속도를 결정하는 단계는 LLM이어야 합니다.
00:11:29따라서 타임아웃을 설정하고 해당 가드레일이 특정 시간 예산 내에서 실행되도록 하세요.
00:11:38또 다른 중요한 요소는 폴백입니다.
00:11:40모델 제공업체와 관련해서는 늘 폴백에 대해 이야기해 왔고 잘 알고 계실 겁니다.
00:11:47하지만 가드레일 역시 중요한 서비스이므로, 가드레일 제공업체에 장애가 발생했을 때 서비스를 유지하기 위해 폴백을 고려하고, 보조 제공업체와 보조 검사를 두고, 결정을 캐싱할 수 있습니다.
00:12:03가드레일과 관련해 흥미로운 또 다른 선택지는 가드레일의 배치 위치입니다.
00:12:10일반적으로 가드레일은 세 가지 방식으로 배치할 수 있습니다.
00:12:15입력에 대해 실제로 가드레일이 실행되는 사전 훅을 둘 수 있습니다.
00:12:19이 방식이 가장 안전할 수 있지만, 요청에 직렬 대기 시간이 추가됩니다.
00:12:26다른 하나는 병렬 처리입니다.
00:12:29제가 가장 좋아하는 방식 중 하나이지만, 여기서는 스트리밍이 잘 작동하지 않는다는 점을 참고하세요.
00:12:35따라서 특히 구조화된 출력을 생성하는 경우 스트리밍을 사용하지 마세요.
00:12:40대기 시간을 줄이고 구조화된 출력을 위해 이러한 가드레일을 동시에 실행해 보세요.
00:12:46또 다른 방식은 사후 훅입니다.
00:12:48이는 출력 모니터링, 출력 감사 등에 가장 적합합니다.
00:12:58자, 지금까지 의존성에서 발생할 수 있는 모든 문제에 대해 논의해 보았습니다.
00:13:06요청 경로 자체에 또 하나의 의존성, 즉 중앙 LLM 게이트웨이를 추가하고 있다는 점은 아직 이야기하지 않았습니다.
00:13:15LLM 게이트웨이를 개발하거나 사용 중이신 분들과 공유하고 싶은, 저희가 겪었던 문제들과 교훈들이 몇 가지 있습니다.
00:13:25첫째는 공유 제한입니다.
00:13:28API 키가 경로별, 유스케이스별로 가장 세분화된 수준까지 철저히 분리되도록 하세요.
00:13:40시끄러운 테넌트가 존재한다는 것은 여기서 가장 큰 문제 중 하나가 될 수 있습니다.
00:13:47다음은 부하 분산(로드 셰딩)입니다.
00:13:50런북이나 게임 데이의 일환으로 사용 중인 게이트웨이가 부하 분산을 지원하는지 확인해야 하는 기능입니다.
00:13:59재시도 폭풍이 발생하면 단순히 규모를 확장하기가 정말 어려워지기 때문입니다.
00:14:03재시도 폭풍을 겪고 있는 서비스는 단순히 확장할 수가 없습니다.
00:14:07그리고 이 모든 웹 서버에는 내부 큐가 있으며 설정이 가능합니다.
00:14:13큐가 제한되어 있는지 확인하고, 무제한으로 요청을 받아들이지 않도록 하세요.
00:14:19커스텀 로직을 원한다면 트래픽 우선순위 지정 기능을 도입하여 부하가 걸린 상황에서도 가장 중요한 유스케이스가 잘 처리되도록 할 수 있습니다.
00:14:29마지막으로 논의하고 싶은 주제는 중앙 게이트웨이 개념 자체입니다.
00:14:38이는 단일 장애점이 됩니다.
00:14:40따라서 전사적으로 두 개의 LLM을 위해 중앙 게이트웨이를 두려고 생각 중이시라면, 재고해보고 정말 필요한 이유가 무엇인지 파악해 보시는 것을 권장합니다.
00:14:52대부분의 시나리오에서 그들이 원한 것은 중앙 게이트웨이가 아니라는 점을 깨달았습니다.
00:14:57그들이 원한 것은 중앙화된 거버넌스였습니다.
00:15:00게이트웨이는 분산시키면서도 거버넌스는 중앙화할 수 있는 발전 방향이 존재합니다.
00:15:07그러므로 트래픽을 중앙화하려고 하지 말고, 플러그인이나 커스텀 코드를 활용해 거버넌스를 중앙화할 수 있습니다.
00:15:17거버넌스는 비용 추적, 속도 제한 관리 등의 형태로 이루어질 수 있으며 그 외의 솔루션도 가능합니다.
00:15:24따라서 회사 전체를 위한 단일 중앙 게이트웨이를 구축하기 전에 이러한 대안들을 먼저 살펴보세요.
00:15:30단일 팀에서 관리할 수는 있겠지만, 분산되어 있더라도 회사 전체를 위한 단일 배포 형태로 구축하는 것은 권장하지 않습니다.
00:15:43이 말을 끝으로 이번 발표를 개인적인 이야기로 마무리하고자 합니다.
00:15:47오늘은 제 아들의 생일인데, 저는 여기서 낯선 분들과 서킷 브레이킹에 대해 이야기를 나누고 있네요.
00:15:54그러니 저와 여러분의 고객을 위해 장애를 단 하나라도 막아주시는 것이 제가 부탁드릴 수 있는 전부입니다.
00:16:02감사합니다.
00:16:03질문 있으시면 말씀해 주세요.
00:16:06.