[BoostCamp AI Tech / Product Serving] Serving의 종류와 다양한 패턴
머신러닝 모델을 실제 환경에 적용하는 다양한 Serving 방식에 대한 내용을 정리한 포스트입니다.
머신러닝에서 Model Serving 이란 데이터에 기반하여 모델의 예측 결과를 요청한 Client에게 제공하는 과정을 의마한다.
이를 음식 서빙에 비유할 수 있다.
- 예측 요청(Request) - 음식 주문 요청
- 예측 결과 - 음식
- Client - 고객
Model Serving을 좀 더 구체적으로 설명하면 다음과 같다.
- Production(Real World) 환경에 모델을 사용할 수 있도록 배포하는 것
- ‘머신러닝 모델의 서비스화’
- 모델을 연구하는 환경 이후에 진행되는 작업
- Input을 Model에게 주입하면 모델이 Output을 반환
- Model은 머신러닝 모델, 딥러닝 모델, LLM 등 다양할 수 있음
Serving의 대표적인 예시로 개인화 알고리즘을 통해 유튜브 메인 화면에 볼만한 영상을 추천하는 서비스, DeepL의 번역기가 있다.
Serving의 종류
Serving의 종류는 크게 2가지 방식을 많이 활용한다.
- Batch Serving
- 데이터를 일정 묶음 단위로 서빙
- ex. 14~15시 사이에 생성된 데이터
- 정기 배송
- Online(Real Time) Serving
- 클라이언트가 요청할 때 서빙
- ex. API Request
- 요청할 때 데이터를 같이 제공
- 주문 후 바로
그러면 어떤 상황에 어떤 Serving을 사용해야 할까?
Serving을 사용해야 하는 정해진 상황은 없다. 하지만 어떤 Serving을 사용할 지 결정 할 때 주로 문제 상황, 문제 정의, 제약 조건, 개발할 인력 수, 데이터 저장 형태, 레거시 유무 등에 따라 결정한다.
Batch Serving
Batch Serving을 주로 사용하는 상황은 다음과 같다.
- 실시간 응답이 중요하지 않은 경우 : 데이터 처리에 일정 시간이 소요되어도 괜찮은 경우
- 대량의 데이터를 처리할 때
- 정기적인 일정으로 수행할 때
Batch Serving이 Online Serving 보다 쉬울 수 있으며 이때, 데이터는 RDB, 데이터 웨어하우스 형태로 저장한다.
- 1시간 단위, 4시간 단위, 24시간 (하루) 단위로 예측 후 DB에 저장하고 서비스(웹/앱)는 DB에 있는 예측 결과를 활용한다.
ex. Batch Serving의 예시
- DoorDash의 레스토랑 추천
- Netflix의 추천(2021년)
Online Serving
Online Serving을 사용하는 상황은 다음과 같다.
- 실시간 응답이 중요한 경우 : 즉각적으로 응답을 제시해야 하는 경우
- 개별 요청에 대한 맞춤 처리가 중요할 때
- 동적인 데이터에 대응할 때 : 데이터가 지속적으로 변하는 경우
API 서버, 실시간 처리 등의 경험이 필요하며 데이터는 요청할 때 같이 데이터가 제공되어야 한다.
- 요청(Request)이 오면 바로 요청에 대한 응답(Response)을 제공한다.
ex. Online Serving의 예시
- 유튜브의 추천 시스템(새로고침)
- 번역
- 은행의 사기 탐지 시스템 : 실시간으로 거래의 이슈 탐지
디자인 패턴
소프트웨어 개발 분야에도 패턴이 존재한다. 이를 디자인 패턴 이라고 한다.
소프트웨어에서 디자인(Design)은 다음과 같은 의미를 가지고 있다.
- 소프트웨어 개발 분야에서는 단순히 외관을 의미하지 않음
- 소프트웨어의 구조, 구성 요소의 관계, 시스템의 전반적인 행동 방식
즉, 소프트웨어를 어떻게 구성하고, 어떻게 상호 작용할지를 담은 내용이다.
디자인 패턴 = 템플릿 이라고 생각할 수도 있다.
- 과거부터 문제를 해결한 사람들이 반복된 내용을 패턴으로 정리
- 코드의 재사용성, 가독성, 확장성 등을 향상시키기 위한 목적으로 도입
- 주로 객체 지향 프로그래밍에서 사용되지만 다른 프로그래밍 패러다임에서도 유용
- 개발 과정의 커뮤니케이션에서 이런 패턴을 사용하기도 함
- ex. 이번 서빙은 Batch 패턴으로 구현하시죠!
- 안티 패턴 : 보통 좋지 않다고 알려진 패턴
머신러닝 디자인 패턴
머신러닝의 특수성으로 별도의 디자인 패턴이 생겼다. 일반적인 소프트웨어 개발에서는 오직 Code만 있었지만 머신러닝에서는 Data, Model, Code가 있다.
머신러닝 서비스를 개발하다 생기는 특수한 포인트는 아래와 같은 상황이 있다.
- 대용량 Model Load
- Model 관리
- 데이터를 대량으로 가져와서 전처리
- 데이터를 통계적으로 확인해서 이상치 제외
- 예측 요청 후 반응 시간이 오래 소요될 수 있음(모델이 연산하는 과정 이슈)
학습, 예측, 운영하면 생기는 노하우를 패턴화하였으며 지금도 계속 변화하고 있다. 대표적으로 LLM 이후에도 LLMOps라는 새로운 분야가 생겼으며 계속 새로운 시도가 생길 것이다.
상황이 다를 수 있기 때문에 머신러닝 디자인 패턴이 항상 Best는 아니지만 구현하기 전에 참고할 수 있으며 여러 패턴을 합쳐서 하나의 패턴으로 만들 수도 있다.
머신러닝에는 대표적으로 4가지 패턴이 있다.
- Batch Serving
- Batch 패턴
- Online Serving
- Web Single 패턴
- Synchronous 패턴
- Asynchronous 패턴
💡 용어 정리
- 예측 서버 : 서비스 서버러부터 모델 입력을 받아 추론을 진행한 후 결과를 서비스 서버에 전달
- 데이터베이스
- 서비스 서버 : 프론트에 입출력할 데이터를 전달하며 예측 서버와 데이터베이스끼리 상호작용한다.
Batch 패턴
만약에 영화 추천 모델 개발이 완료되고 이 모델을 가장 간단하고 최대한 적은 비용으로 운영 환경에 배포하고 싶으면 어떻게 하면 될까?
- 주기적으로 이 추천 모델에 사용자가 본 영화 데이터를 Input Data로 넣어서 예측하고, Output 으로 나오는 사용자 별 추천 영화를 DB에 저장
- 추천 결과를 활용하는 서버쪽에서는 이 DB에 주기적으로 접근해 추천 결과를 노출
핵심은 실시간성이 필요 없는 경우에 주기적으로 예측 결과를 DB에 저장하고, 활용하는 쪽은 DB에서 결과를 읽어와서 사용한다.
Job Management Server- 작업을 실행하는 서버
- Apache Airflow 등을 주로 사용
- 특정 시간에 주기적으로 Batch Job을 실행시키는 주체
Job- 어떤 작업 실행에 필요한 모든 활동
- Job이 실행되는 과정에 Model Load, Data Load도 포함
- Python Script를 그냥 실행시키는 경우도 있고, Docker Image로 실행하는 경우도 존재
Data- 서비스에서 사용하는 DB(AWS RDS 등) 또는 데이터 웨어하우스에 저장
- 서비스 서버에서도 데이터를 불러오는 스케줄링 Job이 존재 → 특정 시간 단위로 가져옴
장점은 기존에 사용하던 코드 재사용이 가능하고 API 서버를 개발하지 않아도 된다. 그리고 리소스를 유연하게 관리할 수 있다(오래 걸릴 Job에 서버 리소스 추가 투입).
단점은 별도의 스케줄러(ex. Apache Airflow)가 필요하다.
사용하는 상황은 다음과 같다.
- 예측 결과를 실시간으로 얻을 필요가 없는 경우
- 대량의 데이터에 대한 예측을 하는 경우
- 예측 실행이 시간대별, 월별, 일별로 스케줄링해도 괜찮은 경우
Web Single 패턴
- Web: 웹 기반 애플리케이션
- Single: 단일, 하나의 요청 처리
위의 Batch 패턴으로 서빙했더니, 결과 반영에 시간 텀이 존재했다.
- 예 : 영화 추천 결과가 DB에 1시간 단위로 업데이트 되니, 유저 입장에서 최신 결과를 받기까지 1시간이라는 시간이 필요
- 물론 1시간에서 30분으로 모델 서빙 주기를 줄여도 괜찮지만, 결국 또 유저가 기다려야 하는 것은 동일.
이보다 더 실시간에 가깝게 할 수는 없을까?
- 모델이 항상 Load 된 상태에서 예측을 해주는 API 서버를 만들고, 추천 결과가 필요한 경우 서비스 서버에서 이 예측 서버에 직접 요청
핵심은 API 서버 코드에 모델을 포함시킨 뒤 배포한 후 예측이 필요한 곳(클라이언트, 서버 등)에서 직접 Request 요청하는 것이다.
예측/추론 Server- FastAPI, Flask 등으로 단일 REST API 서버를 개발 후 배포
- 예 : POST api-server-url/predict로 예측
- API 서버가 실행될 때 모델을 로드
- API 로직 내에 전처리도 같이 포함
Client- 앱에서 예측 서버에 직접 요청
- 앱이 서비스 서버에 요청하고 서비스 서버가 예측 서버에게 또 요청할 수도 있음(개발을 어떻게 했는지에 따라 다름)
- 웹페이지라면 브라우저에서 요청
Data- 요청할 때 같이 데이터를 담아 요청
- 상황에 따라 데이터의 용량 제한이 있을 수 있음
Load Balancer- 트래픽을 분산시켜서 서버에 과부하를 걸리지 않도록 해줌
- Nginx, Amazon ELB(Elastic Load Balancing) 등을 사용
장점은 보통 하나의 프로그래밍 언어로 진행하고 아키텍처가 단순하다. 또한 처음 사용하기에 좋은 방식이다.
단점은 구성 요소 하나(모델, 전처리 코드 등)가 바뀌면 전체 업데이트가 필요하고 모델이 큰 경우는 로드가 오래걸릴 수 있다. 요청 처리가 오래 걸리는 경우는 서버에 부하가 걸릴 수 있다.
사용하는 상황은 다음과 같다.
- 예측 서버를 빠르게 출시하고 싶은 경우
- 예측 결과를 실시간으로 얻을 필요가 있는 경우
- Web Single 패턴을 기본으로 삼고 이어지는 패턴들을 적용
Synchronous 패턴
Synchronous(동기식)은 하나의 작업이 끝날 때까지 다른 작업을 시작하지 않고 기다리고, 작업이 끝나면 새로운 작업을 시작하는 방식이다.
FastAPI로 모델을 Web Single 패턴으로 구현을 하고 클라이언트는 API 서버로 요청을 한 뒤 이 요청이 끝날 때까지 기다려야 되는 경우에 사용하는 패턴이다.
즉, Web Single 패턴을 동기적(Synchronous)으로 서빙하는 방식이며 이때 대부분의 REST API 서버는 동기적으로 서빙한다.
장점은 아키텍처의 단순하며 예측이 완료될 때까지 프로세스가 다른 작업을 할 필요가 없어서 Workflow가 단순해진다.
단점은 예측 속도가 병목이 되며(동시에 1000개의 요청이 올 경우 대기 시간이 길어지거나 Drop 혹은 Timeout) 예측 지연으로 사용자 경험이 악화될 수 있다.
주로 사용하는 상황은 다음과 같다.
- 예측의 결과에 따라 클라이언트의 로직이 즉각적으로 달라져야 하는 경우
- ex. 예측 결과가 강아지냐, 고양이냐에 따라 클라이언트에서 보여주어야 하는 페이지가 다른 경우
Asynchronous 패턴
Asynchronous(비동기식)은 하나의 작업을 시작하고, 결과를 기다리는 동안 다른 작업을 할 수 있으며 작업이 완료되면 시스템에서 결과를 알려주는 방식이다.
Synchronous 패턴으로 서빙하니까, API 서버에서 이제 수많은 요청을 감당할 수가 없어지는 상황일 때 사용하는 패턴이다.
- API 서버가 계속 부하가 걸려서 모든 요청에 대한 응답이 느려지기 시작
- 응답이 느려지니, 클라이언트에서도 응답 받은 이후의 로직을 진행하지 못함
- API 서버의 cpu와 memory를 증가하면 해소가 되긴 하겠지만, 단기간의 해결이고 요청이 늘어나며 결국 똑같아짐
이러한 문제가 생기지 않게 하기 위해서는 API 서버의 부하가 늘지 않게 요청을 하며 다 처리할 수 있어야 하며 클라이언트는 당장 결과를 받지 않더라도, 최종적으로 결과를 받아야 한다.
Queue- 클라이언트와 예측 서버 사이에 메시지 시스템(Queue)을 추가
- 대표적인 메시지 프레임워크 : Apache Kafka
- 지하철 물품 보관소와 유사한 역할
- Push : 메시지 저장
- Pull : 메시지를 가지고 와서 작업(예측) 수행
장점은 클라이언트와 예측 프로세스가 분리되어 관계가 의존적이지 않으며 클라이언트가 예측을 기다릴 필요가 없음
단점은 메시지 Queue 시스템을 만들어야 하기 때문에 전체적으로 구조가 복잡해진다. 또한 완전한 실시간 예측엔 적절하지 않음(메시지를 가져갈 때 시간이 소요될 수 있음).
주로 사용하는 상황은 다음과 같다.
- 예측과 클라이언트 진행 프로세스의 의존성이 없는 경우
- 예측 요청을 하고 응답을 바로 받을 필요가 없는 경우
- 예측을 요청하는 클라이언트와 응답을 반환하는 목적지가 분리된 경우
Anti Serving 패턴
Anti Serving 패턴은 권장되지 않는 Serving 패턴, 즉 주의해야 할 패턴이다.
대표적인 2가지 패턴이 있다.
- Online Bigsize 패턴
- 실시간 대응이 필요한 온라인 서비스에 예측에 오래 걸리는 모델을 사용하는 경우
- ex. 서버가 실행되는데 몇 분씩 소요되고, 요청에 대해 응답이 몇 초씩 걸릴 경우
- 일반적으로 Bigsize 모델은 배포할 때 서버 실행과 서빙이 느리며 속도와 비용 Tradeoff를 조절해 모델 경량화하는 작업이 필요한 문제점들이 있음
- 대안으로는 실시간이 아닌 배치로 변경하는 것도 가능한지 검토하거나 중간에 캐시 서버를 추가하고, 전처리를 분리하는 것도 Bigsize를 탈피하는 방법이 있다.
- 실시간 대응이 필요한 온라인 서비스에 예측에 오래 걸리는 모델을 사용하는 경우
- All-in-one 패턴
- 하나의 서버에 여러 예측 모델을 띄우는 경우
- ex. predict1, predict2, predict3으로 나눠서 하나의 서버에서 모두 실행하는 경우
- 라이브러리 선택 제한이 존재하거나 장애가 발생할 경우(서버가 갑자기 다운) 시스템이 마비(SPOF, Single Point Of Failure)되는 문제점이 있다.
- 모델 별로 서버를 분리하여 배포 (Microservice 패턴)하는 대안이 있다.
- 하나의 서버에 여러 예측 모델을 띄우는 경우
이 글은 비밀번호로 보호되어 있습니다.



