분석 데이터를 프로덕션에서 쉽게 사용할 수 없을까?

분석 데이터를 프로덕션에서 쉽게 사용할 수 없을까?

이번 글에서는 분석 테이블을 API로 만들 수 있는 데이터서빙 서비스를 만들었던 과정을 소개 드리겠습니다.

뱅크샐러드에서는 S3, Airflow, Spark 기반의 데이터 파이프라인을 통해 매일 수백종의 분석이 진행되고 있습니다. 데이터 파이프라인과 관련한 자세한 내용은 이전 글 데이터 분석가가 직접 정의, 배포, 관리하는 뱅크샐러드 데이터 파이프라인을 참고해주세요. 🙂

데이터 파이프라인이 늘어나면서 자연스럽게 “데이터 파이프라인에서만 계산할 수 있는 데이터를 제품에서 사용할 수는 없을까?”는 고민을 하게 되었습니다. 이런 고민에서 “새소식”, “사용자 분석 태그” 등의 제품을 고안하게 되었습니다.

새소식 서비스 <새소식 서비스>

먼저 새소식은 각종 소비, 건강, 자산 생활 소식을 사용자 별로 알려주는 서비스입니다. 월급날을 알려준다거나, 지난주 소비를 요약하고, 소비 패턴을 분석해주기도 합니다. 지금까지의 모든 누적 가입자에게 새소식을 발행하는 것은 비효율적이기에 새소식 발송 대상을 추출하고 대상에게만 새소식 내용을 계산하여 보낼 필요가 있는데요, 예를 들자면, 최근에 급여 이체 내역이 있는 사용자에게 월급날 새소식을 보내고, 지난주 소비 내역이 연동된 사용자에게 주간 소비리포트를 보내야 합니다. 그런데 “급여 내역이 존재”, “지난주 소비 내역이 연동됨” 같은 조건을 프로덕션 데이터베이스에서 계산하는 것은 꽤 어렵습니다. 계산에 필요한 데이터가 여러 서비스에 걸쳐 있고, 긴 기간 데이터에 복잡한 연산이 필요하기 떄문입니다. 그렇기에 새소식 발송 대상에 해당하는 각종 조건들을 데이터 파이프라인에서 쿼리로 계산하여 새소식 서비스에 매일 전송하기 위해 데이터 파이프라인을 활용하게 되었습니다.

사용자 분석 태그 <사용자 분석 태그>

사용자 분석 태그는 각종 데이터 분석을 통해 파악되는 사용자 속성을 서빙하는 서비스입니다. 미혼/기혼, 부모, 출산 예정, 구독중인 상품이 있는지, 자차 보유 여부, 부동산 구매 준비 여부 등 다양한 사용자 속성을 분석하고 사용자 별로 태깅합니다. 사용자별 태그는 각종 서비스와 어플리케이션 화면에서 사용자별 최적화 경험을 보여주는데 사용됩니다. 이런 사용자 분석 역시 여러 서비스와 여러 일자에 걸치는 복잡한 계산이 필요합니다. 그렇기에 사용자 분석 태그 서비스를 데이터 파이프라인을 통해 각 태그를 계산하고 매일 서비스 데이터베이스에 계산된 태그를 넣는 구조로 구현했습니다.

문제 - 분석 테이블을 서비스에서 쉽게 사용 할 수 없을까?

분석 데이터를 프로덕션에 사용하는 사례가 늘어남에 따라 파이프라인에서 어떻게 프로덕션 서비스에 데이터를 넣어주고, 명세를 약속하고, 서비스 API를 설계할지 매번 논의하게 되었습니다. 정해진 틀이 없었기에 매번 다른 아키텍처로 설계되곤 했는데요, 파이프라인이 프로덕션 서비스를 직접 호출하기도 하고, 프로덕션 데이터베이스에 데이터를 넣어주기도 하고, 서비스에서 분석 쿼리 서비스를 호출하여 배치로 데이터를 가져가기도 했습니다. 또, 앞서 설명 드린 새소식, 사용자 분석 태그 보다 작은 분석 데이터 제품을 만들 때면 이 제품 만을 위해 새로운 서비스를 만들어야 할지 고민 되기도 했습니다. 무엇보다, 매번 아키텍처 고민이 필요했기 때문에 데이터 제품을 만들기 위해서는 서버 엔지니어의 기여가 항상 필요했습니다.

따라서 저희는 분석 테이블을 프로덕션에서 활용하기 위한 적절한 추상화를 제공하기 위해, 분석 테이블을 프로덕션 API로 만들 수 있는 일종의 플랫폼을 구축할까 고민하게 되었습니다. 플랫폼에 필요한 요구사항은 다음과 같았습니다.

• 데이터 분석가가 서버 엔지니어의 최소한의 도움을 받아 직접 API를 구축할 수 있어야 한다.
• 분석 테이블 API는 protobuf로 명세가 정의되고 idl에서 관리되어야 한다.
• 조건을 조합해서 filter 할 수 있어야 한다.
• …

이런 요구사항에서 dataserving이라는 서비스를 개발하게 되었습니다.

구조

데이터 분석가가 직접 정의, 배포, 관리하는 뱅크샐러드 데이터 파이프라인에서 소개드린 것 처럼 뱅크샐러드 분석 파이프라인은 서비스에서 발생하는 데이터를 모아 S3, Glue 기반의 저장소에 저장하고 분석하고 있습니다.

dataserving 구조 개괄

dataserving은 분석 파이프라인과 프로덕션 사이에서 데이터 저장과 서빙을 담당합니다. datapipe 파이프라인은 dataserving에 분석 테이블을 주기적으로 업데이트합니다. 뱅크샐러드 클라이언트와 서비스에서는 dataserving API를 호출하여 데이터를 사용할 수 있습니다. 예를 들어, 새소식 서비스는 데이터 파이프라인이 계산한 새소식 발송 타겟을 dataserving에 요청해서 받아가게 되었고, 제품 화면에서 사용자의 분석 태그가 필요한 경우 클라이언트가 직접 dataserving에 요청하게 바뀌었습니다. 새소식 발송 타겟과 사용자 분석 태그는 datapipe의 파이프라인에서 일정 주기로 계산하여 갱신 됩니다.

Amazon DocumentDB

dataserving은 Amazon DocumentDB를 백엔드로 사용합니다. DocumentDB는 AWS에서 제공하는 MongoDB 호환 완전관리형 도큐먼트 데이터베이스입니다. 완전관리되는 대규모 성능 데이터베이스이면서 유연한 JSON 문서 모델과 효율적인 인덱싱을 제공하는 것이 특징인데요, 다양한 스키마와 조회 조건이 필요한 분석 테이블을 서빙하기에 적절한 백엔드라고 판단했습니다.

한편 datapipe에서 dataserving에 분석 테이블 데이터를 넣어주고 클라이언트에서 dataserving 데이터를 요청할 때, idl로 데이터를 명세합니다. financial_product_search_card이라는 새로운 데이터셋을 dataserving으로 내보낸다면, 아래와 같이 새로운 메시지를 작성하여 protobuf를 수정하게 됩니다.

  message DatasetMessage {
    google.protobuf.StringValue id_key = 1;
    oneof dataset {
      FinancialProductSearchLoan financial_product_search_loan = 2;
+     FinancialProductSearchCard financial_product_search_card = 3;
    }
  }

+ message FinancialProductSearchCard {
+   int64 banksalad_card_id = 1;
+   // 카드 명
+   // ex) 씨티 리워드 카드, NH올원카드
+   string card_name = 2;
+   // 기관 guid
+   // ex) CRD0001, CRD0002
+   string organization_guid = 3;
+   // 최소 연회비
+   int64 minimum_annual_cost_amount_krw_0f = 4;
+   // 최대 연회비
+   int64 maximum_annual_cost_amount_krw_0f = 5;
+   // 최소 전월 실적
+   int64 minimum_card_condition_amount_krw_0f = 6;
+   ...
+ }

수정한 protobuf를 idl에 커밋하게 되면 dataserving, datapipe 그리고 각종 서비스에서 해당 데이터셋을 사용할 준비가 끝났습니다.

그리고 datapipe에서는 테이블, 데이터셋 이름, 조회 조건 key 이름 등을 포함하여 insert operator를 생성합니다. 매일 데이터 파이프라인은 mart_financial_product_search.card 테이블을 읽어 dataserving에 financial_product_search_card 데이터셋를 업데이트하도록 요청합니다.

insert_card = DataservingInsertOperator(
    table="mart_financial_product_search.card",
    dataset_name="financial_product_search_card",
    filter_key=dict(
        FILTER_KEY_BANKSALAD_CARD_ID_INT64="banksalad_card_id",
        FILTER_KEY_ORGANIZATION_GUID_STRING="organization_guid",
        ...
    ),
)
mart_financial_product_search.card.set_downstream([
    insert_card,
])

datapipe 배포까지 데이터 파이프라인이 생성하는 분석 테이블을 dataserving API로 제공하는 배포 과정이 모두 끝나게 됩니다.

소결론 - dataserving 사용해서 데이터 제품 만들게 되었습니다.

금융 쇼핑 <금융 쇼핑>

dataserving의 첫번째 고객은 “금융쇼핑”이었는데요, 마이데이터로 수집한 금융상품과 실제 고객이 받는 혜택을 탐색할 수 있는 제품입니다. 내부 구현은 마이데이터를 통해 들어오는 각종 금융 데이터를 상품 단위로 정리하는 데이터 파이프라인과 상품 데이터 API를 제공하는 dataserving으로 이루어져 있는데요, 제품에서 보이는 모든 데이터를 dataserving으로 제공했습니다. 마이데이터로 수집되는 금융 데이터 양이 많았기에 데이터 파이프라인으로 계산하기에 적당한 제품이었던 것 같습니다.

한편 이 제품은 서버 엔지니어 없이 데이터 분석가가 직접 명세를 정의하고 클라이언트 개발자와 소통하여 만든 제품이기도 했습니다. 물론 데이터 분석가가 데이터 파이프라인도 직접 개발했었습니다.

그런데 데이터 서빙 문제는 좀 더 복잡했습니다

그런데 다양한 데이터 프로덕트 개발을 위한 데이터 서빙 문제는 좀 더 복잡했습니다. 데이터 종류에 따라 접근 제어(public, per-user, private)가 필요하기도 했고, 실시간성을 위해 서비스 API와 조합이 필요하기도 했습니다. 유저 이벤트와 같은 스트림 데이터가 필요한 기능도 있었습니다.

현재의 dataserving 구조 <현재의 dataserving 구조>

여러번의 개선을 거듭해 현재는 위와 같은 구조가 되었습니다. 데이터 파이프라인에서 계산한 배치 데이터를 서빙한다는 중심은 같지만, 데이터 프로덕트 API, 서비스 호출 및 데이터 조합, 유저 이벤트 스트림 등 여러 구성요소가 추가로 개발되었습니다.

결론

dataserving이 개발 되면서 이전보다 훨씬 다양한 데이터 제품을 출시할 수 있게 되었습니다. 앞서 소개 드린 “금융 쇼핑”부터, 나와 비슷한 집단의 자산을 비교해주는 “내 자산 순위”, 투자 수익률이 높은 투자 고수들의 주식 매수를 알려주는 “고수들의 투자 전략”, 내가 가진 보험의 보장 정도와 또래와 비교해주는 “보험 진단”, 내 자산에 대해 여러가지 지표 추이를 제공해주는 “자산 분석 보드”까지 많은 데이터 제품이 dataserving 기반으로 만들어졌습니다.

여러가지 데이터 서비스

서비스에서 직접 계산하기에는 많은 연산과 여러 데이터의 조합이 필요한 제품들이었는데, dataserving과 뱅크샐러드 데이터 파이프라인이 있었기에 제품 개발이 가능했던 사례였습니다.

다수의 데이터 제품이 출시되면서 dataserving 역시 중요한 서비스가 되었는데요, 그렇기에 분석 데이터 안정성이나 실시간성, 그리고 운영 효율 등 개선점이 많이 보이기도 했습니다. 더 간편하고 효율적이면서도 안정적으로 데이터를 서빙하기 위해 앞으로도 많이 개선할 예정입니다.

뱅크샐러드 데이터 제품에 많은 기대 부탁 드립니다. 글 읽어주셔서 감사합니다.

보다 빠르게 뱅크샐러드에 도달하는 방법 🚀

지원하기

Featured Posts

post preview
post preview
post preview
post preview
post preview

Related Posts