pile·
백엔드·티몬티몬·

실시간 항공권 검색 서비스, 이렇게 만들었어요!

티몬 항공서비스개발유닛이 실시간 항공권 검색 서비스를 만들며 다룬 대용량 데이터 처리 이야기다. 한 번의 검색에 1GB가 넘는 데이터를 처리해야 하는 이유부터 GDS 연동과 XML 파싱, 두 단계 가공, 필터링, 카우치베이스 적재까지 순서대로 짚는다. 서비스 오픈 후에 덧붙인 압축과 페이징 조치도 함께 나온다.

핵심 포인트
  • 좌석 잔여 수와 요금이 실시간으로 바뀌기 때문에 실시간 데이터가 아니면 검색 결과가 틀린다.
  • 항공 스케줄과 요금은 GDS라는 중개 업체에서 실시간 API로 받아오며 Sabre와 Amadeus를 연동해 쓴다.
  • 한 번의 검색에서 GDS와 주고받는 XML이 1GB를 넘는 경우가 많아 GDS별로 호출 서버와 인스턴스를 분리했다.
  • XML 파싱과 가공에는 Jaxb를 쓰고 필드 단위와 패키지 단위 두 방식으로 어댑터를 건다.
  • 검색 조건에 따라 스케줄 10만 개와 요금 100만 개가 나올 수 있어 최저가만 남기는 필터링을 건다.
  • 카우치베이스는 키 하나에 20MB 제한이 있어 GZIP으로 압축하고 넘치면 페이징해 적재한다.
상세 정리
  • 실시간이 필요한 이유 1: 예약 가능 좌석 수인 Avail이 실시간으로 바뀌므로 반영이 늦으면 예약할 수 없는 결과를 보여주게 된다.
  • 실시간이 필요한 이유 2: 항공사와 여행사가 정책과 수요에 따라 요금을 바꾸므로 지연된 데이터로는 정확한 가격을 낼 수 없다.
  • GDS의 존재 이유: 항공사가 각국 고객에게 직접 팔려면 언어와 지역 특성을 다 감당해야 해서 여행사와 연계하는데, 그 중개를 맡는 것이 GDS다.
  • 연동 현황: 하나투어·자유투어 계열의 Sabre와 모두투어·노랑풍선 계열의 Amadeus가 연동돼 서비스 중이고 Galileo도 작업 중이라고 밝힌다.
  • 데이터 규모: 검색 조건에 따라 다르지만 GDS와의 실시간 API 통신에서 1GB 이상을 처리해야 하는 경우가 많다. 서버를 분리해도 파싱과 가공 후 통합 단계가 남는다.
  • 1차 가공의 범위: trim, 특수문자 변환, 특정 필드 앞뒤에 고정 데이터 추가처럼 받은 데이터 자체를 손보는 작업이다.
  • 1차 가공 방법 1: 특정 필드는 XmlAdapter를 상속해 unmarshal과 marshal을 재정의한 클래스를 만들고 그 필드에 어노테이션을 붙인다. 요금 필드의 소수점 이하를 잘라내는 어댑터가 예시다.
  • 1차 가공 방법 2: 패키지 전체에 적용하려면 package-info에 어노테이션을 달아 해당 패키지의 대상 필드에 어댑터가 걸리게 한다.
  • 2차 가공의 범위: 여행사 정보와 스케줄, 요금을 내부 규격에 맞게 맞추고 정합성 조건으로 일부를 걸러낸다.
  • 필터링 기준: 같은 조건에서 요금이 유독 비싸거나 한 스케줄에 같은 여행사와 요금 조건이 중복되면 최저가만 남기고 나머지를 무의미한 데이터로 보고 제외한다.
  • 통합과 적재: GDS별 결과를 필터링·가공한 뒤 통합하고 검색 조건에 따라 정렬해 최종 결과를 만든다. 검색 조건으로 만든 키에 결과 리스트를 값으로 두는 맵 형태로 카우치베이스에 넣는다.
  • 용량 대응: 필터링을 거쳐도 키당 20MB 제한을 넘기는 경우가 많아 GZIP으로 압축하고 그래도 넘치면 페이징해 나눠 담는다. 여러 여행사가 입점하며 데이터가 커져 오픈 이후에 추가한 조치다.
  • 개선 방향: 스케줄과 요금 데이터를 분리하는 등 구조를 바꿔 압축 없이 카우치베이스를 쓰는 쪽으로 작업 중이라고 밝힌다.
  • 남은 과제: 한 번에 처리할 데이터가 커서 검색 응답이 느린 경우가 있고 서버 간 네트워크 트래픽과 전체 시스템 부하도 크다고 인정한다.
왜 읽나외부 대용량 XML API를 여러 곳에서 받아 합쳐야 하는 구조라면 Jaxb 어댑터 활용부터 캐시 키 용량 한계 대응까지 실제 선택지가 나온다.
티몬
티몬 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2