FLO의 정산시스템, 어떻게 이루어져 있을까?




안녕하세요. 드림어스컴퍼니 이용권&정산개발팀에서 정산개발을 담당하고 있는 Lucas입니다.

이번 글에서는 이용권&정산개발팀이 담당하고 있는 업무와 음원사용료 정산의 개념을 간단히 소개하고 FLO의 정산시스템이 어떻게 구성되어 있는지에 대해 소개해보려고 합니다.




이용권&정산개발팀을 소개합니다!


이용권&정산개발팀은 팀이름에서 알 수 있는것처럼 이용권 개발파트와 정산개발파트로 나눠져 있습니다.

이용권개발파트는 다양하게 기획된 이용권을 고객들이 구매할 수 있도록 서버 뒷단을 개발하고 CMS를 만들어 운영팀이 사용할 수 있도록 합니다.


그뿐만 아니라 이용권 결제 처리, 이용권 구독 처리, VOC 대응 등의 서비스에서 가장 중요한 시스템을 개발하고 있습니다.


정산개발파트는 이용권 결제내역과 고객이 청취한 이력을 기반으로 음원 제작에 참여했던 권리자들에게 음원 사용료가 투명하게 정산될 수 있도록 도와주는 시스템을 개발합니다.




음원사용료 정산


FLO와 같은 음원 스트리밍 서비스는 컨텐츠 권리자를 대행하여 고객에게 서비스를 제공하고 이를 통한 수익을 해당 권리자들에게 음원사용료 징수규정에 따라 계산하여 지급합니다.


컨텐츠 제작에 참여한 권리자들은 생각보다 많은데요.

예를 들어 제작자(유통사, 기획사), 저작자(작사, 작곡, 편곡자), 실연자(가수, 연주자) 등이 있습니다.


음원사용료 정산은 실물 음반판매에 대한 정산보다 복잡해서 전담 시스템을 갖추지 않고 처리하기에는

어려움이 많습니다.




정산시스템의 Mission


정산시스템이 다뤄야 하는 데이터는 종류가 다양하며 사이즈가 매우 큰 것이 특징입니다.


예를 들면 이용권 결제내역, 청취이력과 같은 데이터는 고객이 이용권을 구매하거나 음원을 재생할 때마다 생성되기 때문에 FLO를 사용하는 고객이 늘어나면 늘어날수록 데이터의 크기가 급증할 수 밖에 없습니다.


이렇게 시간이 흐를수록 사이즈가 점점 더 커지는 대량의 데이터를 조합하여 정산운영팀 및 파트너사에 제공할 정산결과를 빠르고 정확하게 만들어내는 것이 정산시스템의 mission 입니다.

정산 시스템이 생성한 정산 결과데이터는 재생된 음원과 이용권 종류별로 합산되어 산출되는데,

그 조합이 생각보다 큰 편이라 데이터 양도 상당합니다.


또 다른 Mission은 이렇게 생성된 대량의 정산 데이터를 정산운영자 또는 파트너사들의 관점에 맞게 조회 할 수 있도록 시스템을 만들어 제공하는 것입니다.


다음으로 정산시스템의 기술 스택에 대해서 설명 드리겠습니다. 😀




정산시스템의 기술 스택


※ 파란색 글씨를 누르면 해당 설명 페이지로 이동합니다!



인프라


기본적으로 관리형 Kubernetes(AWS EKS)에 API, batch, OpenFaaS가 정산 CMS의 뒤쪽에서 작동합니다.

데이터 가공과 조회를 위한 infra는 Amazon EMR의 Hive와 Presto를 사용합니다.


원본 데이터와 최종적으로 가공된 데이터는 Amazon S3에 저장되고, 데이터의 schema는 AWS Glue의 Data Catalog에 저장됩니다.


application과 system의 alert은 Sentry 를 통해 수집 및 알림이 발송되며, Kubernetes의 모든 log는 Loki 에 저장되어 Grafana 로 조회됩니다.




Kubernetes


정산시스템의 모든 기능은 container 기반으로 작성되어 있습니다.

초기 정산시스템에서는 Jenkins에서 batch job이 수행되고, AWS Elastic Beanstalk으로 API를 제공했습니다. 이런 구성은 기능적으로 충분했지만 몇 가지 불편한 점들이 있었습니다.

  • 컨테이너 단위 scaling이 아니므로 리소스를 효율적으로 사용하지 못함

  • 로그를 모으고 보여주기 위한 방식이 편리하지 않음

  • 복잡한 구성을 사용하려면 까다로운 설정 작업 필요

  • 서브 시스템(batch, API)들의 인프라 및 배포를 관리하는 방식이 분산됨


이런 문제점을 해결하기 위해 컨테이너화된 애플리케이션을 통일된 방식으로 관리하고 자동 배포, 스케일링 등을 훌륭하게 제공해주는 Kubernetes를 사용하기로 결정했습니다.


물론 Kubernetes 말고도 다른 좋은 대안들이 많지만 아래 사항을 중점적으로 고려하여,

Kubernetes로 결정을 하였습니다.

  • 개발팀 구성원들의 선호도

  • 특정 vendor의 인프라, 파편화된 OSS를 사용하는 것을 지양

  • 커뮤니티로부터 꾸준한 지원을 받을 수 있어야 함

  • 동일 기능에 대한 여러 가지 선택지가 있는지




Python


정산시스템의 대부분의 구현은 python 3.8로 되어있습니다.




프로젝트 초기에 어떤 언어로 개발할지 고민할 수 있는 시간이 주어졌었고 요구 사항은 아래와 같았습니다.

  • 개발자 모시기가 수월해야 함

  • data, cloud 관련 library들이 풍부해야 함

  • 문자열 조작이 쉬워야 함

물론 가장 중요한 것은 초기 개발자가 쓰고 싶은 언어여야했고, 이런 부분까지 모두 반영하여 결국 python 3.x 으로 결정했습니다.


초기 개발이 시작된 후로 2년 이상이 지났지만 여전히 발전하고 있는 언어라서 언어가 제공하는 혜택을 받으며 잘 사용하고 있습니다.


특히 python 3.6부터 도입된 type hint, f-string, decorator와 3.4부터 점진적으로 발전하고 있는 async-io를 즐겨 사용하고 있습니다.




Argo workflows


하루에 한 번 또는 한 달에 한 번 수행 되어야 하는 batch job을 수행하기 위해서 Argo workflows를 사용하고 있습니다.


Argo workflows는 소개페이지에 나와 있는것처럼 container-native workflow engine이며 Kubernetes 위에서 workflow를 실행하는 engine 입니다.


Kubernetes에서 제공하는 Job object 와의 가장 큰 차이점은 Job간의 종속성을 부여하여 workflow를 실행할 수 있다는 점입니다.


Kubernetes의 object를 yaml형식으로 기술하는것과 비슷하게 workflow template를 선언적으로 작성하고 여러 step 또는 task로 연결하여 단순한 순차실행, 병렬실행 뿐만아니라 task 사이의 종속성을 설정하여 복잡한 DAG를 작성하여 실행 시킬 수 있습니다.


또한 CronWorkflow의 schedule에 cron 표현식을 지정하여 주기적으로 실행되는 workflow를 작성할 수 있습니다.




OpenFaaS


정산시스템에서는 호출이 거의 없어서 cold start time이 중요하지 않은 요청을 대응하기 위해 serverless function platform을 도입하게 되었고, 시스템 요구 사항은 아래와 같았습니다.

  • Kubernetes 위에서 작동해야 함

  • 기존 Kubernetes 클러스터에 설치가 간편해야 함

  • 대부분의 시간에 호출이 없을 것이므로 scale to zero가 지원되어야 함

위의 요구사항으로 CNCF landscape의 serverless 카테고리에서 후보군을 탐색해보고 최종적으로 OpenFaaS를 선택했습니다.




이 글을 쓰는 시점에 확인해 보았을 때 OpenFaaS에서 기본적으로 제공하는 scale to zero 기능을 사용하려면 유료 모델(OpenFaaS Pro)을 사용해야 하는 것으로 보입니다.


관련글 : https://docs.openfaas.com/architecture/autoscaling/#scaling-down-to-zero




FastAPI


개발 초기에는 Python으로 API server를 구축하기위해 일반적으로 널리 사용되는 Flask 를 사용하려고

했지만 Flask를 사용하기에는 요구사항 중에 몇 가지가 부합되지 않았습니다.

시스템 요구 사항은 아래와 같았습니다.

  • 대용량 data streaming이 request 처리 성능 저하와 같은 문제가 없어야 함

  • code 자동완성, 코딩 시점에 오류 검출을 위해 type 기반 programming을 지원해야 함

  • 코드로부터 OpenAPI(swagger)로 제공이 용이해야 함

data를 streaming을 하기위해서는 비동기를 지원하며, type hint(python 3.6+)를 기반으로 하고 있는 최신의 web framework를 조사 했고, 그 중 요구사항에 딱 맞는 FastAPI 라는 web framework를 발견하게 됐습니다.


FastAPI는 성능이 뛰어나고, 배우기 쉬우며, 빠르게 개발 가능하고, 코드 중복을 줄일 수 있는 다양한 기능을 제공합니다.


Java 진영에서 유명한 Spring framework를 사용할 때와 유사한 개발 경험을 python에서도 할 수 있다는 느낌을 주었습니다. 무엇보다도 친절한 문서화와 활발한 커뮤니티가 가장 큰 장점이라고 생각합니다.




EMR (Hive/Presto)


종류가 다양하고 시간이 흐를수록 사이즈가 점점 더 커지는 대량의 데이터를 조합하여 일정한 시간내에 데이터를 가공하기 위해서는 기술 선택을 위해서는 다양한 선택지가 있을 수 있습니다.


일반적으로 online transaction 처리가 필요없고, 데이터량이 아주 많은 경우에는 Hadoop 계열의 기술을 사용하는것이 데이터 저장용량 비용, 데이터 처리 속도면에서 유리합니다.


요구사항은 아래와 같았습니다.

  • RDB, log file 등의 source data를 join 하여 데이터를 가공할 수 있어야 함

  • insert뿐만 아니라 select 속도도 빨라야 함

  • select 시 aggregation이 대량의 row에 대해서 여러 column에 걸쳐서 빠르게 처리되어야 함

몇 가지 선택지가 있었지만 Amazon EMR의 hive와 presto를 사용하기로 결정하였습니다.

그러한 선택을 했던 이유는 정산 CMS에서 조회되어야 하는 정산 데이터는 일 단위, 월 단위로 여러 column을 선택하여 조회해야 했기 때문입니다.


여기서 도전적이었던 부분은 특정 column들을 선택했을 때 곡, 앨범 또는 파트너사를 최소 단위로 합산하여 출력해야 하는 요구사항이었습니다.


이 요구사항을 만족시키기 위해서 일반적으로 할 수 있는 방법은 일 단위 데이터와 월 단위 데이터를 각각 미리 생성해놓고, 경우에 따라서 일부 데이터들을 aggregation 하는 것인데요.


이 방식은 데이터 생성 시점에 같은 원본데이터에 대해 여러 관점(해상도)에 따른 복수의 테이블을 만들어놓고 제공하는 방식입니다.


이 방식을 피하기 위해 presto를 활용하여 데이터 조회 시점에 빠르게 aggregation 하여 제공하고 있는데요. 무엇보다도 EMR을 사용하기 때문에 설치와 운영이 간편하고, autoscaling 기능이 자동으로 제공되는 부분이 편리합니다.




Monorepo


정산시스템을 구성하는 인프라 코드, API, batch, 기반 docker library, 문서를 하나의 github repository에서 관리하고 있습니다.

이렇게 monorepo로 구성하면서 몇 가지 장점을 얻을 수 있었습니다.

  • project 간의 의존성 관리가 용이

  • 개발 시 project 간 탐색비용 감소

  • 여러 project에 걸친 수정인 경우 하나의 repository에서 수정 및 관리



지속적 통합(CI)과 지속적 배포(CD)


CI/CD는 기본적으로 github을 통해서 이루어집니다.

미리 정해진 환경별(dev, stage, production) branch 관리 전략에 따라 해당 branch에 변경사항이 발생하면 해당 환경에 배포됩니다.


변경 사항을 반영하기 위한 PR(Pull Request)이 생성되면 Jenkins나 AWS Codebuild에서 빌드, 테스트, 정적분석이 바로 수행되어 PR에 결과를 보고하고, code review 후에 PR이 merge되면 자동으로 docker registry로 push가 수행되고, helm을 통해 Kubernetes dev 환경에 배포됩니다.

이후에 github release를 통해 각 branch에 git tag가 추가되면 staging, production 환경에 배포합니다.




향후 과제


FLO 정산시스템은 주기적으로 전산 감사를 받고 있습니다.

기존 전산 감사는 전통적인 on-premise 기반의 인프라와 이 분야에서 널리 쓰이고 있는 database를 기반으로 진행되기 때문에 그 외 다른 시스템을 사용할 경우 이런 간극을 메우기 위한 시스템적 보강이 필요합니다. 예를 들면 유저 접근 권한 관리, audit log, 데이터 암호화 등이 해당됩니다.


그 외에도 시스템의 대부분의 로직이 SQL query로 되어있어서 점점 커지는 쿼리의 복잡성을 통제하면서 데이터의 정합성을 유지하는 부분이 앞으로의 과제로 남아있습니다.




정리


다양한 workload들을 최소한의 비용으로 처리하기 위해서 정산시스템 개발 초기부터 여러 가지 노력이 있었습니다.


수년간 경험했던 인프라 추가 및 관리의 어려움을 극복하기 위해 public cloud를 도입했으며,

자원 관리를 효율화하여 비용을 줄이고, 개발 및 운영 효율을 극대화하기 위해서 기술 스택을 꾸준히

최신화하는 노력을 했습니다.


이러한 시스템을 만들기위해 팀에서 기술 선택에 대한 자유와 조사할 수 있는 시간을 지원해주셔서 많은 경험을 해볼 수 있었습니다.




Kubernetes 와 Python 기반의 빅데이터 프레임워크를 통해서 수백만명이 사용하는 서비스의 대규모 데이터 처리를 경험할 수 있는 이용권&정산개발팀은 항상 커리어를 고민하고, 새로운 기술에 관심을 가지는 팀원들로 구성되어있습니다 😀


이용권&정산개발팀에 Join 하고 싶은 분이라면 아래의 공고를 확인해주세요!