글램 데이터팀 — 서버리스 머신러닝 의사결정 서비스 구축기 (feat. AWS)

Cupist
큐피스트 블로그(Cupist Blog)
15 min readNov 16, 2021

안녕하세요, 글램 데이터 팀의 Data Scientist 다운입니다 🌱

이번 글에서는 글램 데이터 팀이 어떻게 글램 백엔드 서버와 독립적인 내부 머신러닝 서비스를 구축하고 운영했는지 소개하려고 합니다.

이 글을 통해 다음과 같은 내용을 파악할 수 있습니다.

  • 데이터 팀 (또는 머신러닝 팀)의 서비스 기능적 역할 분담 케이스
  • Serverless 프레임워크 및 AWS Lambda를 활용한 머신러닝 서비스 배포 전략

이 글은 이런 분들이 읽으시면 좋습니다!

  • 머신러닝과 유관된 로직만을 별도의 서비스로 구현하는 것을 고려하고 있는 분들
  • AWS의 인프라에 익숙하거나 이미 AWS 인프라를 사용중인 분들
  • 머신러닝 로직의 서버리스 배포를 고려하는 분들

이번 게시글에선 이 내용은 다루지 않습니다.

  • 구체적인 머신러닝 Architecture와 검증
  • 머신러닝 모델 학습 전략

도입 배경

변화하는 비즈니스 로직을 머신러닝 문제로 정의하기

유저와 유저간의 상호작용, 유저와 유저간의 신뢰도가 굉장히 중요한 데이팅 서비스인 글램에서는 유저가 등록한 프로필 사진이 데이팅의 목적에 적합한지를 빠르고 정확하게 판단하는 것이 서비스 운영 측면에서 굉장히 중요한 과업 중 하나입니다.

글램의 서비스 운영팀은 유저의 프로필 사진으로 등록된 사진이 서비스 운영 정책에 위배되는 직접적인 성적 노출을 포함하고 있거나, 성매매 등 불법적 / 외부적 광고가 포함되는 등 매우 다양한 케이스에 대해서 유저의 프로필 사진의 적합성을 심사하고, 승인하거나 반려처리 해야 합니다.

이 때 문제가 되는 것은, 문제를 효율적으로 정확하게 풀기 위해서 ‘어디까지를 머신러닝 문제로 정의하느냐’입니다. 만약 수십 가지의 서비스 운영 정책을 모두 설명할 수 있을 만큼 데이터가 충분하다면, 이 데이터를 모두 학습한 하나의 머신러닝 모델이 유저의 프로필 사진을 승인할지, 반려할지 결정할 수 있습니다.

하나의 머신러닝 모델이 의사결정을 끝내면 참 좋겠습니다.

그러나 현실은 그렇게 녹록지 않습니다. 승인과 반려의 기준은 서비스의 정책이 변경되거나 사회적 맥락 등에 따라서 하나씩 추가되는 경우도 있고, 빠지는 경우도 있고 상당히 정성적이기 때문에, 하나하나의 기준을 세부적으로 검토해야 할 필요가 있습니다.

백엔드 서버가 복수의 머신러닝 모델의 결과값을 통해 의사결정을 도출해야 하는 상황

그러나 이렇게 여러가지의 기준들을 여러가지 머신러닝 모델로 결정하다보면 머신러닝 모델이 업데이트 될 때 의사결정을 진행하는 백엔드 서버가 업데이트 돼야할 수 있습니다.

그 예시는 다음과 같습니다.

  • 머신러닝 모델이 반환한 확률값에 대한 Threshold 수치는 백엔드 서버에서 가지고 있어야 할까요? 모델이 업데이트 될 때마다 Threshold 수치가 변경될 수도 있을까요?
  • 머신러닝 모델이 단순히 성능차원에서만 업데이트되는 것이 아니라 입출력 데이터의 규격, 다양한 전처리와 후처리가 복합적으로 변경되면 어떻게 해야 할까요?
  • 머신러닝 모델이 단발적으로 출력을 내는 것이 아니라 ‘이전에 머신러닝 모델이 출력한 값을 함께 머신러닝 모델에 집어넣거나, 여러 머신러닝 모델의 출력값을 비교 / 조합하는 ‘메타 모델’이 존재하는 경우는 없을까요?

이런 상황들이 발생할 때마다 자연히 백엔드 엔지니어와의 커뮤니케이션 비용 또한 기하급수적으로 증가하고, 머신러닝 측면에선 간단한 업데이트를 진행할 때에도 백엔드 서버와의 규격을 맞추기 위해서 실 서비스 적용이 늦춰질 수 있습니다.

글램 데이터팀에서는 이 문제를 해결하기 위해서, 머신러닝 서비스의 R&R을 단순히 ‘머신러닝 모델에 대한 입력을 제공받으면 모델의 출력을 반환한다’ 가 아닌, ‘머신러닝 모델을 중심으로 비즈니스 의사결정에 대한 입력을 제공받으면, 의사결정을 제공한다’로 더 넓은 범주에서 정의했습니다.

백엔드 ↔ 머신러닝 의사결정 서비스 Artemis, 추상화된 다이어그램

이 서비스는 내부적으로 Artemis로 부르며, 서비스의 계층적인 구조는 다음과 같이 정의했습니다.

  • Artemis (마이크로서비스)
    a. Use Cases 1 (머신러닝 유관 비즈니스 로직, 예: 프로필 사진 검수)
    의사결정의 재료가 되는,
    클라우드 관리형 머신러닝 모델들
    (주로 REST API 또는 Cloud SDK를 통해서 호출합니다.)
    b. Use Cases 2 (머신러닝 유관 비즈니스 로직, 예: 소개 상대 추천)
    c. Use Cases 3 (머신러닝 유관 비즈니스 로직, 예: 컨텐츠 추천)
    d. …

Artemis는 복수의 Use Case에 대한 의사결정 요청을 받아 처리하며, 각 Use Case는 필요에 따라 복수의 머신러닝 모델 내지 산술 함수를 외부에서 호출하고 조합하여 최종 결정을 도출해냅니다.

실제 구현 방식

Artemis는 AWS Lambda를 이벤트 처리의 중심으로 삼고 백엔드 서버와 통신할 수 있는 호출지점으로 API Gateway를 활용하였으며, 데이터 저장 / 활용을 위해서 AWS S3와 Amazon Aurora RDB를 활용합니다. 개별 머신러닝 Task의 결과, Use Case에 대한 최종 처리 결과 등이 SQLAlchemy를 통해 정의한 ORM 모델에 따라 RDB에 저장되고, 필요한 경우 Use Case 내에서 저장된 값을 불러와 재활용하거나 조합합니다. 이 때, 대부분의 클라우드 인프라에 대한 설정을 serverless framework를 통해서 환경별로 하나의 configuration 파일로 정의할 수도 있고, 부분적으로 정의한 후 클라우드 콘솔 설정을 통해 연동할 수도 있습니다.

AWS Lambda

AWS Lambda는 서버를 관리하지 않고도 직접 작성한 함수를 배포할 수 있게 해주는 AWS의 서버리스 인프라입니다. AWS Lambda에 배포된 함수는 요청(이벤트)이 들어올 때마다 요청의 규모에 따라서 자동으로 스케일하고 실제 함수의 연산 시간단위로 비용을 지불할 수 있습니다. 2014년 최초로 공개된 이후로 오랜 기간동안 AWS Lambda는 사용할 수 있는 CPU, RAM, Storage 등 컴퓨팅 자원 및 컴퓨팅 시간이 제한되어 있어 머신러닝과 같은 고성능 워크로드에는 매우 부적합하다는 평가를 많이 받았습니다.

그러나 Lambda는 오랜 세월에 걸친 성능, 정책 및 기술적 개선을 통해서 컨테이너 이미지를 배포할 수도 있으며, 이벤트당 10GB의 RAM, 6 Core CPU라는 넉넉한 자원으로 연산을 수행할 수 있게 되었습니다.

Spectrum of Abstraction Level of AWS Infrastructure

Lambda는 서비스의 추상화 수준이 높기에 서버 운영에 대한 깊은 이해 없이도 구현과 관리가 편리하고, 비용 또한 손쉽게 절감할 수 있다는 매력적인 장점을 가지고 있기에, 이번 Artemis 서비스는 Lambda 플랫폼을 활용하기로 결정했습니다.

FastAPI + Mangum = 모든 요청을 수신하는 하나의 Lambda Function

AWS Lambda의 Function은 본디 하나의 요청을 하나의 격리된 함수가 실행하는 것을 기준으로 설계된 풀랫폼입니다. 그러나 본 서비스의 특성상 복잡한 비즈니스 로직을 수행하기 위해선 하나의 Lambda Function이 데이터베이스 ORM 모델 등 여러가지 종속성 모듈과 연결되어야 합니다.

만약 하나의 Lambda Function이 이 역할을 수행할 수 있다면 어떨까요? FastAPI는 백엔드 엔지니어가 아니더라도 손쉽게 API를 개발할 수 있도록 도와주는 웹 프레임워크입니다. FastAPI를 통해 다수의 원하는 비즈니스 로직들을 REST API들로 묶으면, Mangum은 이 FastAPI 앱을 단일 Lambda Function의 Handler 인터페이스로 만들어 배포하게 해줍니다. 이 배포방식을 활용한다면, 서비스 코드베이스가 Lambda 특유의 코딩 스타일에 종속되지 않게 되며 필요한 경우 추후에 동일한 패키지를 AWS Lambda가 아닌 VM 방식이나 Container 방식으로 배포하도록 변환하기도 용이해집니다.

다음 코드는 FastAPI로 딥러닝 모델을 호출하는 API를 만드는 간단한 예제 코드입니다.

app.py

mangum을 활용하기 위해선 mangum python 패키지를 설치한 이후 코드 두 줄만 추가해주면 됩니다.

app.py

이제 이 handler 객체를 통해서 AWS Lambda Function을 배포할 수 있습니다.

추가로 FastAPI를 활용하면 API 배포 시 자동으로 생성되는 Swagger API 문서를 통해서 API의 입력 데이터와 출력 데이터, URL 등의 정보를 백엔드 엔지니어와 손쉽게 공유해 규격을 맞출 수 있었습니다.

Serverless Framework로 개별 서비스를 더 추상적으로 쉽게 활용하기

한편 이렇게 만든 Lambda Function을 배포하기 위해선 외부 종속성 패키지를 함께 패키징하고, 환경변수를 설정하는 등 여러가지 고려를 해야 합니다. Function을 호출하는 Trigger 또는 Event가 필요합니다. Lambda는 자체적으로 HTTP 인터페이스를 제공하지 않기 때문에 API Gateway 등을 통해서 인터페이스를 만들 수 있습니다. Lambda의 Function 정의, 권한 설정, 네트워크 설정, Trigger 설정 등 어플리케이션의 요구사항이 하나 둘 증가함에 따라 엔지니어링 복잡도가 증가하게 되는데요, 이를 더 쉽게 추상화하고 사람이 읽을 수 있는 Configuration 파일로 정의해 몇 번이고 재사용할 수 있도록 도와주는 Framework가 Serverless Framework입니다.

serverless 사용법은 정말 간단합니다. 다음처럼 필요한 패키지를 설치하고,

serverless.sh

configuration 파일을 통해 사용해야 하는 클라우드 자원들과 패키징 방식을 정의하면 됩니다.

이제 configuration에 따라 서비스를 배포할 수 있습니다.

sls deploy --stage staging

그러면 몇 분 안에 배포가 완료되며 명령줄에서 다음과 같은 내용을 볼 수 있습니다.

Service Information
service: my-awesome-app
stage: staging
region: eu-west-1
stack: my-awesome-app-staging
resources: 12
api keys:
None
endpoints: # 배포한 API의 Endpoint를 여기서 찾을 수 있습니다!
ANY - <https://XXXXXXXXX.execute-api.eu-west-1.amazonaws.com/staging/>
functions:
app: my-awesome-app-staging-app
...

serverless에는 위 내용 외에도 배포한 Endpoint에 커스텀 도메인을 연결하는 serverless-domain-manager 등 다양한 커뮤니티 플러그인을 활용해 쉽게 확장할 수 있었습니다. 비슷한 역할을 해주는 다른 프레임워크로 zappa가 있었는데요, zappa의 경우 사용하는 언어가 python으로 제한되고, 최신 프레임워크나 클라우드 리소스에 대한 업데이트가 미비한 점 등이 아쉬워 serverless를 활용했습니다.

머신러닝 모델 배포 과정의 엔지니어링 비용 줄이기 = 관리형 서비스 활용하기

클라우드 머신러닝 관리형 서비스 원하는대로 골라담기 / 커스텀 모델 개발 & 배포하기

요청과 데이터를 처리하고, 다양한 머신러닝 모델의 결과를 취합하고 의사결정을 내릴 컨트롤 타워를 Lambda를 통해 정의했으니 이제 남은 것은 실제 로직에 활용되는 머신러닝 모델들을 관리형 서비스를 통해 배포하고 연결하는 것입니다.

엔지니어 구성원이 많지 않은 글램 데이터팀 특성 상, 유지보수에 최소한의 비용을 들이는 개발과 배포 방법론을 고민해야 했습니다. 일반적으로 머신러닝 모델은 학습 시 고성능의 워크스테이션 또는 클라우드 GPU 컴퓨팅 자원을 종량제로 활용하는 경우가 많지만, 이러한 자원은 유휴 시간이 증가하면 관리 비용 내지 클라우드 비용을 과도하게 소진시킬 수 있기에 적재적소에 필요한 만큼의 컴퓨팅 리소스만을 이용하기 위해선 많은 고려가 필요합니다. 이러한 고민을 덜고, 서비스의 워크로드가 급증하거나 유휴시간이 발생하는 유동적 상황 속에서 데이터 팀이 마음의 평화를 유지하기 위해 GCP, AWS 등 클라우드 플랫폼에서 제공하는 관리형 서비스를 적극적으로 활용해야 했습니다.

글램 데이터팀은 다음과 같은 기준으로 다수의 머신러닝 관리형 서비스를 검증하고 Artemis 내에서 활용했습니다.

  1. 우리 서비스 도메인 특유의 데이터를 활용한 유니크한 모델만 자체구현예: AWS SageMaker, GCP Cloud AI / ML Engine 관련 서비스를 통해 직접 작성한 머신러닝 코드를 통해 모델을 학습하고 관리
  2. 완벽한 모델 대신 적당한 모델 빠르게 검증하기
    a. 자체구현 모델이 항상 최고의 모델인 것은 아니다.
    b. 성능 개선은 모델의 비즈니스 효과성이 검증된 다음 스텝으로 고려하자.
    예: Google Cloud AutoML, AWS Rekogition, Google Cloud Vision
  3. 워크플로우를 효율적으로 만드는 킬러 기능이 있다면 멀티 클라우드도 고려하기
    예: GCP의 BigQuery를 활용해 대용량 데이터를 효율적으로 ML 서비스로 연결
    관련 문서: https://cloud.google.com/bigquery-ml/docs/bigqueryml-intro
  4. Job은 Batch 단위가 아닌 Event 단위로 요청하기

위 기준으로 고른 관리형 서비스를 통해서 배포한 머신러닝 모델은 AWS의 boto3, GCP의 Cloud Client 또는 REST API를 통해서 인프라나 모니터링에 대한 큰 걱정없이 손쉽게 호출해 사용할 수 있었습니다.

배포 & 운영 방식

이제 서비스의 구현이 완료됐습니다. 마지막으로 배포한 이후 장기적으로 서비스를 잘 운영하기 위한 안전장치들을 추가할 차례입니다.

글램 엔지니어링 조직에서는 코드 저장소로 GitHub를 활용하고 있으며, GitHub Actions를 통해서 CI & CD를 자동화해 운영하고 있는데요, Artemis 서비스 또한 운영의 주체가 데이터팀인 만큼 장기적인 엔지니어링 공수를 최소화하기 위해서 GitHub Actions를 활용해 유닛테스트 실행과 배포를 자동화하고 매 배포가 완료될 때마다 Slack 채널을 통해 알림을 받고 관련 팀원과 커뮤니케이션할 수 있도록 설정하였습니다.

마지막으로 Sentry를 서비스에 연결하여, 배포 시 예측하지 못한 오류가 발생하는 경우 이 또한 지정된 Slack 채널을 통해서 알림을 받고 빠르게 대처할 수 있도록 설정하였습니다.

앞으로의 과제

AWS Lambda가 하나의 요청을 수행할 수 있는 최대 시간은 2021년 10월 기준으로 상대적으로 넉넉한 300초입니다. 그러나 이 Lambda Function의 결과를 API Gateway를 통해서 내보낼 수 있는 시간은 최대 30초로 다소 제한적입니다.

API Gateway의 최대 Timeout 제한

ML Task들의 특성상 경우에 따라선 Event 단위에서 30초를 초과하는 긴 연산 시간을 요구하는 Task도 분명 존재할텐데요, 이를 대비하기 위해서는 API Gateway가 아닌 Kafka (Amazon MSK)등을 통해 이벤트 비동기적으로 생성하고 완료된 결과를 적재하는 방식 등을 추가해야 할 수 있습니다.

마무리

이번 글에서는 AWS 인프라 위에서 Data Scientist 또는 데이터 팀이 단독으로 머신러닝 관련 의사결정 서비스를 직접 구축하고 배포할 수 있는 시나리오에 대해 알아봤습니다. 작업을 진행하기에 앞서 Serverless 형태의 인프라가 성능이 제한적이라는 부분에 있어 많은 걱정과 고민이 있었는데요, 몇몇 AWS의 정책들이 허들이 되기도 했지만 우려와는 달리 큰 문제없이 요청을 처리할 수 있었습니다.

큐피스트는 사랑의 욕망을 충족한다는 사명을 달성하기 위해 국내 1위 소셜 데이팅 서비스 ‘글램’을 운영하는 회사입니다. 글램 프로덕트 조직은 비즈니스 문제를 효과적으로 해결할 수 있는 방법을 발 빠르게 실험하고 적용하고 있습니다. 우리와 함께 실제 유저의 경험을 증진하고 회사와 함께 성장할 다양한 직군의 인재를 찾고 있습니다. 많은 관심 부탁드립니다. 😉

👉 큐피스트 채용 공고 확인하기 👈

읽어주셔서 감사합니다.

--

--