2022년 중반쯤 데이터 솔루션을 만드는 새로운 회사를 가면서 데이터 수집 및 파이프라인 업무를 처음 해봤다. 전에는 BE에 가까운 업무를 했다. 익숙하지 않은 분야를 접하면서 느끼고 배운 점들을 공유해보려고한다. 다만 전체 경력도 주니어이고 이제 막 시작해서 틀린 점도 있을 수 있다. 이걸 감안하고 읽어줬으면 한다. 그리고 다루는 데이터 도메인은 이커머스라는 것도 참고 삼아 미리 언급한다.
데이터 활용을 위해서는 데이터 모델링이 필수다.
여러 소스에서 수집한 데이터들은 바로 사용하기가 어렵다. 왜냐하면 소스마다 데이터 스키마와 컬럼 정의가 제각각이기 때문이다. A 소스에서는 주문 상태가 10개일 수도 있고, B 소스에서는 주문 상태가 20개일 수도 있다. 회사 내부에서 데이터를 사용하기 위해서는 이 별개의 데이터들을 모델링 해줘야한다.
좀 더 정확하게 표현하면 데이터 웨어하우싱을 해야한다. 방금 들었던 예시로는 내부에서 주문 상태를 5개로 정의했다면 10, 20개를 정의한 5개에 맞게 맞춰줘야한다. 이때 모든 소스마다 일관성있게 정책을 가져가는게 정말 중요하다. 소스마다 달라진다면 혹은 하나의 소스내에서 다르게 가져간다면 데이터 정합성 때문에 고생을 하게 된다. 나중에 정책이 바뀐다면 기존에 테이블에 있던 로우들을 원본을 이용해 갈아엎어야한다. 😇
데이터 웨어하우싱이 궁금하다면 애자일 데이터 웨어하우스 디자인을 추천한다. 번역이 매끄럽지 않아 내용 이해가 어려울 수 있으므로 회사 스터디로 진행하는 걸 권장한다.
데이터가 변화하는 값을 가지는지 알아야한다.
데이터들은 대부분 시간에 따라서 동일 로우에 대해 컬럼 값이 변한다. 예를 들면 주문은 주문 상태가 결제 완료, 배송 중, 배송 완료 등 시간에 따라서 동일한 주문의 상태가 변화한다. 물론 로그처럼 한 번 생성된 뒤 변하지 않는 데이터도 있다.
만약 변화하는 데이터라면 높은 확률로 분석을 위해 최신값과 히스토리가 모두 필요하다. 즉, 데이터의 현재 값과 이전 값들이 필요하다. 현재 값은 보통 오늘의 통계에 사용하고 이전 값들은 지금이 아닌 그때 당시의 값을 현재에 계산할 때 사용할 수 있다. 혹은 변경 사이의 시간 차이를 알아낼 때 사용할 수도 있다. 데이터 정합성을 위한 디버깅을 할 때도 유용하게 사용할 수 있다. 물론 필자는 DA, DS가 아니므로 더 자세히는 모른다. 하지만 DA, DS 분들이 필요하다고 말씀을 많이 주셨다.
타임존은 신중하게 결정하자. 되도록 UTC를 사용하자.
DE에서 타임존은 DE가 담당하는 데이터뿐만 아니라 DA, DS의 분석에도 엄청난 영향을 준다. 영향력이 끝까지 전파된다. 특히 분석은 날짜를 기준으로 하는 경우가 엄청 많다. 그리고 보통 날짜를 기준으로 파티션을 구성한다. 따라서 타임존은 데이터를 물리적으로 구분하는 파티션에 어떤 로우가 들어갈지도 결정한다. 파티션은 쿼리 성능에 중요한 역할을 한다.
서비스가 특정 국가에서만 서빙되는 것을 100% 보장할 수 있다면 해당 국가의 타임존을 써도 괜찮을 것 같다. 하지만 요즘에는 글로벌 진출이 보편적이기 때문에 이런 경우는 많이 없을 것 같다. 그래서 타임존의 기준이 되는 +00:00 UTC를 사용하는 게 좋다. 한국은 적용이 안 되지만 썸머 타임의 영향도 받지 않고 많은 엔진에서 UTC를 기준으로 지원해주는 함수가 많기 때문이다.
특히 빅데이터 계열의 엔진에서는 TIMESTAMP 타입이 UTC를 기준으로만 하는 경우도 있다. (예를 들면, Athena의 기반인 presto) 그래서 다른 데이터 베이스에 있는 데이터를 가져올 때, 해당 데이터의 시간이 UTC가 아닌데 TIMESTAMP로 변환하면 그대로 UTC가 되는 오류가 날 수도 있다.
태스크 간의 의존도를 파악해야한다.
여기서 태스크는 개념적인 단위이지만 좀 더 구체적으로는 에어플로우의 태스크로 생각하면 좋을 것 같다. 의존도는 장애 영향도와 병렬 처리에 있어서 매우 중요하다. 서로 의존하지 않는 태스크를 의존하게 만들면, 즉 순차적으로 수행되게 만들면 안된다. 이전 태스크가 실패했을 때 관련없는 다음 태스크도 수행될 수 없기 때문이다. 또한 동시에 수행될 수 있음에도 순차적으로 수행해 수행 시간을 늘리기도 한다.
그리고 태스크 하나에 독립적인 여러 가지 데이터 처리가 포함되는 경우도 있다. 만약 하나의 처리가 실패해 재수행해야한다면 이미 성공한 처리도 처음부터 수행하므로 불필요한 수행 시간이 소요된다. 그래서 태스크 하나에는 관련있는 데이터 처리만 포함하는 게 좋다.
데이터 누락을 주의해야한다.
DE에서는 많은 건수의 데이터들을 한 번에 처리하다보니 누락이 충분히 있을 수 있다. 특히 데이터를 처리할 때 몇 건이 이상하다고 해서 오류를 발생시키고 처리하지 않을 수가 없다보니, 이상한 것들만 무시하고 처리하도록 로직을 짜는 경우가 많다. 이때 일정 비율 이상 혹은 전체라면 담당자가 노티를 받을 수 있어야한다. 그래야 무언가 잘못된 것을 파이프라인의 앞에서부터 알아차릴 수 있기 때문이다.
소스 자체가 망가져서 추출조차 못하는 경우도 있다. 특히 내부 시스템에서 가져오는 게 아니라 외부 시스템에서 가져온다면 빈번할 수 있다. 그래서 처리 로직뿐만 아니라 소스시스템에의한 누락도 신경써야한다.
파티션은 쿼리 성능에 엄청난 영향을 끼친다.
BE에서 인덱스로 쿼리 성능을 결정한다면 DE에서는 파티션으로 결정하는 것 같다. 파티션으로 스캔 범위가 결정되기 때문이다. 파티션은 파일 레벨로 보면 디렉토리이다. 특정 파티션에는 해당 기준에 맞는 로우들, 즉 파일들만 존재하게 된다
예를 들면, 파티션이 주문 날짜이면 2023–01–14 주문들은 2023–01–14 파티션에만 존재한다. 그래서 2023–01–14 주문만 조회해도 된다면 모든 주문을 스캔할 필요 없이 WHERE 절에 해당 날짜만 지정해서 필요한 주문만 조회할 수 있다. 빅데이터 엔진을 쓸 정도면 최소 로우가 몇백만 건은 존재하기 때문에 필요한 만큼만 조회하는게 성능에 있어서 매우 중요하다.
한 건의 오류를 그대로 레이즈하면 안 된다.
보통 BE에서는 요청에서 무언가 잘못된 경우 에러를 레이즈해서 클라이언트에게 오류를 알려준다. 이런 방식에 익숙해서 DE 업무를 할 때도 종종 그대로 적용했던 것 같다. 하나의 로우에서 오류가 있는 경우에도 에러를 그대로 레이즈했다. 하지만 하나의 처리 단위에 해당 로우만 있지 않을 확률이 크다.
그래서 에러를 레이즈하면 같은 처리 단위에 있는 다른 수많은 로우들도 처리되지 않으니 주의해야한다. 잘못된 것은 로그로 남기고 해당 로우만 결과에서 제외해야한다. 물론 이전에 언급한 것처럼 일정 수준 이상의 로우가 제외되면 노티를 받아야한다.
파이썬 pandas, spark 같은 라이브러리 혹은 프레임워크를 사용하면 단 건으로 처리하지 않는다. 그래서 이런 얘기가 익숙하지 않을 수도 있다. 하지만 순수하게 파이썬으로 처리 로직을 작성하거나 API의 응답에서 간단한 처리를 해서 저장할 때, 이런 상황을 마주치게 된다.
모니터링 도구를 사용하자.
처리에 문제가 있는 경우 담당자가 노티를 받아야한다. 이때 에러를 남용하면 안 된다. 위에서 언급한 이유 때문이다. 그렇다고 그냥 넘어가면 어떤 문제가 있는지 알 수가 없다. 이럴 때 센트리 같은 모니터링 도구를사용하면 된다. 처리에는 어떤 영향도 주지 않고 문제가 있는 부분만 노티를 받을 수 있기 때문이다. 처리를 아예 할 수 없는 에러와 처리 일부분에 문제가 있는 것을 구분해야한다.
데이터 처리에서는 최악을 가정해야한다.
제목 그대로이다. 데이터 처리를 할 때는 항상 최악의 경우를 가정해야한다. 예를 들면, 필수 컬럼이지만 컬럼 값이 없는 경우, 존재하지 않는 날짜인 경우, 기대한 포맷대로 오지 않는 경우 등등이 있다. 특히 외부 데이터를 처리한다면 더욱 O(N)으로 생각해야한다. 외부 데이터에 대한 문서가 존재하더라도 항상 문서에 정의된 것처럼 데이터가 입력되는 게 아니기 때문이다.
도메인 지식이 필요하면 주석을 남겨야한다.
데이터 추출 및 처리 로직을 작성하다보면 도메인 지식이 필요하다. 예를 들면, 특정 플랫폼에서 상품이 기간 할인인 경우 오늘 날짜를 포함해서 계산한다 등등이 있다. 이런 지식들은 데이터 자체로는 절대 파악할 수 없다. 그리고 코드만 봤을 때 왜 이렇게 하는 것인지 알기도 어렵다. 그래서 코드 작성자뿐만 아니라 나중에 다른 팀원들도 이해를 하기 위해 주석을 남겨야한다. 그렇지 않으면 이해를 위해서 다시 외부 데이터 제공처에 문의를 해야한다. 혹은 누구에게도 물어볼 수 없는 상황도 생기게된다.
데이터 처리 로직은 ETL 기반으로 작성하자.
거의 대부분의 데이터 처리 로직은 ETL을 따른다. 즉, 소스 시스템에서 Extract(추출)해 Transform(가공)한 뒤, 타켓 시스템에 Load(적재)한다. 이 로직에 맞춰 어플리케이션을 작성하면 각각의 흐름이 한 눈에 보인다. 또한 서로 의존하지 않고 독립적으로 테스트를 짜기도 쉬워진다. 자세한 건 여기를 참고하면 된다. Transformation 테스트는 필자가 작성한 이 글을 참고해도 된다.
DE의 고객은 DA, DS이다.
서비스 제공자로서 고객은 잘 대우(?)해드려야할 존재이다. DE에게 있어서 고객은 DA, DS이다. 그래서 DA, DS 분들의 고충을 잘 들어드리고 요구사항이 무엇인지 파악하는 게 중요한 것 같다. 데이터를 아무리 잘 수집해서 저장하더라도 DA, DS에 의해 잘 활용되지 못한다면, 데이터의 가치를 백퍼센트 사용하지 못하기 때문이다.
여러가지 느낀 점들을 쭉 나열해봤다. 물론 현실적인 어려움 때문에 실제로 업무를 할 때 잘 적용하지 못하는 부분도 있다. 특히 DA, DS 분들의 요구사항을 잘 못 들어드리는 것 같다. 🥲 그리고 아직 모르는 게 많기도 하다. 하지만 분명한 건 DE 업무를 하지 않았다면 이런 점들을 느낄 수 조차 없었다는 것이다. 앞으로 더 많은 것들을 배우고 적용해봐야겠다.