들어가며
이전 포스팅에서 언급했듯이 EATceed 서비스는 AI 영양사와 푸드렌즈 기능을 제공하고 있다. 이러한 기능이 안정적으로 동작하기 위해서는 정확하고 신뢰할 수 있는 음식 데이터가 필수적으로 요구된다. 특히, 공공데이터 포털에서 제공하는 전국통합식품영양성분정보(음식)표준데이터는 서비스의 핵심 기반이 되는 정보로, 이를 정기적으로 갱신하고 관리하는 작업은 매우 중요하다.
초기에는 데이터를 수작업으로 수집하고 내부 저장소(관계형 데이터베이스, 벡터 데이터베이스)에 직접 적재했지만, 시간이 지날수록 다음과 같은 문제들이 발생했다.
- 새로운 데이터가 등록되었는지 매번 공공데이터 포털에서 수동으로 확인해야하는 모니터링 부담
- 영양 성분 단위 변환 등 반복적 작업에서 발생하는 사소한 실수
- 지속적인 운영 리소스 낭비와 확장성 부족
이러한 비효율을 해결하고 운영 안정성과 자동화 수준을 높이기 위해 데이터 파이프라인을 구축하게 되었다.
이번 포스팅에서는 다음과 같은 내용을 다룰 예정이다.
- AWS Lambda(Serverless)를 선택한 이유
- 데이터 파이프라인에서의 전체 아키텍처 구성
- 각 단계(Extract, Transform, Validate, Load)별 구현 설명
왜 Serverless인 AWS Lambda를 선택했나?
먼저, 데이터 파이프라인 구축을 위해 서버리스(Serverless) 구조인 AWS Lambda를 도입한 이유에 대해 짚고 넘어가보자.
현재 EATceed의 AI 기능은 FastAPI 기반 서버를 AWS EC2에 구축해 운영하고 있다. 초기에는 이와같은 인프라 내에서 Python 기반 스케줄러인 APScheduler나 워크 플로우 프레임워크인 Airflow를 활용해 데이터 파이프라인을 구축하는 방안도 고려했다.
하지만 이번에 구축한 데이터 수집 파이프라인은 다음과 같은 특징을 가지고 있다.
- 하루에 한 번, 정해진 시간에만 실행
- 실행 시간은 수 분 이내로 짧은 축에 속함
- 상시 실행 불필요(idle 상태 유지 불필요)
이러한 조건에서는 EC2 상에서 항상 프로세스를 실행하는 방식은 리소스 낭비가 될 수 있다. 이에 따라 필요한 순간에만 실행되고 자동으로 종료되는 서버리스(Severless) 구조가 적합하다고 판단했다.
APScheduler와 Airflow를 왜 사용하지 않았나?
APScheduler는 FastAPI 내에서 사용할 수 있는 경량 스케줄러이지만, 운영 서버와 스케줄 작업이 물리적으로 묶이게 되는 단점이 있다. 즉, 한 쪽에 장애가 발생하면 서로 영향을 주고받을 위험이 존재한다. 예를 들어, 파이프라인 작업이 예기치 않은 이슈가 생길 경우 서비스를 운영해야할 서버가 함께 중단된다면? 생각하고 싶지않다..
Airflow는 현업에서 널리 사용되는 워크플로우 프레임워크이지만, "EATceed 데이터 파이프라인이 Airflow를 사용할만큼 복잡한 작업인가?"라는 질문에 대한 대답은 No이기 때문에 도입하지 않았다. 즉, 해당 파이프라인처럼 단일 작업 기반일 경우에서는 오히려 과도한 설정 및 관리 비용이 발생할 수 있고, Airflow가 제공하는 별도 서버 구축, DAG 파일 관리, Web UI 설정 등을 운영할 만한 규모가 아니라고 판단했기 때문이다.
AWS Lambda를 선택한 이유
위에서 서버리스 구조 채택 이유와 다른 기술 스택을 선정하지 않은 이유를 정리했으니, 최종정리 느낌으로 AWS Lambda를 선택한 이유에 대해 작성하고자 한다.
- 비용 효율성(Pay as you go)
- AWS Lambda는 실행 시간에 대해서만 과금되어 하루 한 번 몇 분간 실행되는 파이프라인에 가장 적합
- 운영 부담 감소
- 서버 운영, 인프라 유지보수, 모니터링 등 부가적인 관리를 거의 신경 쓸 필요가 없음
- EventBridge와 연동하면 스케줄링을 손쉽게 설정 가능
- 독립성 / 안정성
- 운영 서버(FastAPI 기반 EC2)와 물리적으로 분리되어 장애 전파 차단 가능
- 외부 서비스 연동 용이
- AWS Lambda는 다양한 외부 서비스(API)와 연동 가능
요약하자면, AWS Lambda는 구현해야할 데이터 파이프라인이 비교적 간단하지만 정기성이 있는 작업이기 때문에 오버엔지니어링을 지양하고, 비용 / 운영 측면을 고려할 때 합리적인 기술 스택이므로 선택하게 되었다.
데이터 파이프라인 구조
아래는 EATceed 데이터 파이프라인의 전체적인 흐름을 시각화한 아키텍처이다.
현재 그림 상에서는 Lambda를 하나로 표현되었지만, 실제로는 역할을 나눠 총 2개의 AWS Lambda 함수로 구성되어 있다.
- EATceed-Event: 추출(Extract)와 변환(Transform) 작업을 담당하며 EventBridge로 매일 트리거되어 실행
- EATceed-Gateway: 검증(Validate)와 적재(Load) 작업을 담당하며 Slack 메세지의 버튼 클릭시 API Gatway를 통해 호출
이제 각 단계 별 역할을 차근차근 살펴보자!
1️⃣ 추출(Extract)
공공데이터 포털에서 제공하는 전국통합식품영양성분정보(표준데이터)를 매일 오후 10시, EventBridge를 통해 Lambda가 트리거되어 자동으로 수집된다.
이때 "새로운 데이터"만 필터링하기 위해 다음 조건을 적용했다.
- 해당 데이터셋에는 "데이터생성일자"와 "데이터기준일자"가 존재하는데 해당 컬럼이 같은 날짜인 경우를 신규 등록된 데이터로 간주
- 공공데이터 포털 측에서 데이터를 등록하면 해당 두 컬럼이 자동으로 설정되기 때문에 이를 활용해 자동 감지 로직을 구현
- 요청 날짜는 트리거 실행 요일로 설정하여 요청 전 날짜인 데이터를 수집하지 않음(중복 수집 방지)
# 현재 날짜
today = datetime.now().strftime("%Y-%m-%d")
params = {
'serviceKey': decoded_api_key,
'pageNo': str(page),
'numOfRows': str(num_of_rows),
'type': 'json',
'crtYmd': today,
'crtrYmd': today
}
이렇게 수집된 데이터는 JSON 형태로 변환(Transform) 프로세스로 전달된다.
2️⃣ 변환(Transform)
수집된 원본 데이터는 다음과 같은 전처리 과정이 진행된다.
- 식품코드 정리: 'D-1234'와 같은 형태를 '1234' 형태로 정규화
- 식품중량 정리: '100g', '200ml'와 같은 단위를 제거하고 정수로 변환
- 영양성분 값 정리: 문자열로 된 수치를 float형으로 변환하고 누락된 값은 0.0으로 처리
- 식품중량 기준 환산: 모든 영양성분을 100g / 100ml 기준(영양성분함량기준량)으로 재계산
변환 과정이 수행된 후에는 Slack API를 통해 사전에 설정한 EATceed 팀 채널에 변환 완료 알림, 즉 데이터 검증 준비가 완료되었다는 알림이 전송된다. 참고로 Slack API 세팅 같은 경우 이 레퍼런스를 활용했다.
Slack Api - Bots 만들기 & 메시지 전송하기
슬랙에서 봇이 사용되는 것은 알고 있었으나 어떻게 만드는지에 대해 궁금해져서 오늘은 슬랙에서 봇을 직접 만들어보려고 합니다. 😆
velog.io
3️⃣ 검증(Validate)
Google Sheets에는 위와 같은 형식으로 데이터가 업로드된다. 일반적인 ETL 파이프라인과 달리 검증 과정을 추가한 이유는 데이터의 신뢰성 확보를 위해 Human in the loop 검증 프로세스를 반영한 것이다. 완전한 자동화를 도입하면 좋겠지만, 데이터의 안정성과 신뢰성이 본 서비스에서 중요하기 때문에 해당 프로세스를 도입했다.
검증이 완료가 되었다면 기존 "적재상태" 열의 값이 0인 것을 1로 변경하여 적재 준비가 완료되었음을 표시한다.
4️⃣ 적재(Load)
Google Sheets에 "적재상태" 열의 값이 1로 변경된 데이터는 최종적으로 Slack 워크플로우의 Load 버튼을 클릭함으로써 적재가 진행된다. 이때 EATceed-Gateway Lambda가 호출되어 다음의 작업을 수행한다.
- RDB에 음식 데이터 저장
- Vecgtor DB에 음식명 임베딩 데이터 저장
모든 적재가 완료되면 Slack을 통해 성공 메시지를 팀 채널에 전송하여 결과를 실시간으로 확인할 수 있다.
해당 과정을 진행할 때 API-Gateway와 Lambda를 연결하는 과정이 특히나 어려웠는데, API Gateay의 리소스 설정을 진행할 때 꼭 "통합 요청(Integration Request)"의 매핑 템플릿 내용을 위와 같이 구성해야 Slack에서 보낸 요청을 Lambda가 잘 받을 수 있도록 해야한다. 이 설정을 놓치면 Slack -> API-Gateway -> Lambda 간 연결이 실패할 수 있기 때문에 주의가 필요하다. 자세한 내용은 해당 레퍼런스를 확인해보자!
[Slack API] Interactivity Request URL with AWS API Gateway, Lambda - Reply in thread
이 글은 Slack API 두번째 글이다. 첫 번째 글과 이어지는 내용이니 첫 번째 글을 먼저 보고 오는 것을 추천한다. Slack이 Request URL로 보낸 요청을 처리하기 위한 Lambda를 먼저 만들어주자.일단 Slack에
velog.io
마무리하며: 자동화가 만든 변화
이번에 구축한 데이터 파이프라인은 규모는 크지 않지만 운영 효율성과 데이터 신뢰성 확보 측면에서 서비스에 큰 가치를 제공한 작업이었다. 처음에는 단순히 데이터를 자동으로 수집하는 수준으로만 생각했는데 실제 구현 과정에서는 검증 프로세스, Slack 연동을 통한 워크플로우 설계, 서버리스 구조 설계 등 다양한 기술적 고민이 동반되었고, 이 과정을 통해 많은 인사이트를 얻을 수 있었다.
무엇보다 자동화를 통해 운영 효율이 정량적으로도 크게 향상되었다. 기존에는 음식 데이터 10개를 수집하고 적재하는 데 약 10분(600초)가량이 소요되었지만, 파이프라인 구축 이후에는 약 1분 30초(90초) 내외로 줄어들어 기존 대비 처리 시간이 85% 감소를 달성하였다.
또한, 사람이 직접 개입해 검토할 수 있는 Human in the loop 구조를 병행함으로써 자동화와 신뢰성 간 균형도 맞출 수 있었다.
결과적으로 이번 경험은 단순한 코드 구현을 넘어 서비스의 운영성과 안정성을 함께 끌어올린 실질적인 설계 경험이었다. 앞으로도 이런 자동화 구조를 다양한 영역에 확장해 나가며, 운영 효율과 품질을 동시에 잡는 기술적 선택을 이어가도록 해야겠다!
'Project > EATceed' 카테고리의 다른 글
[EATceed] CH06. LLM 응답의 품질 검증과 안정적인 운영을 위한 Fallback 패턴 (0) | 2025.03.22 |
---|---|
[EATceed] CH05. 실서비스를 고려한 성능 최적화 (1) | 2025.03.22 |
[EATceed] CH04. 돌고 돌아 마침내 정식 출시까지 (0) | 2025.03.21 |
[EATceed] CH03. 2024년 상반기 개발 진행 과정 (1) | 2024.07.11 |
[EATceed] CH02. 프로젝트 소개 (0) | 2024.02.27 |