[WHY 시리즈 1] E.009 — BigQuery, CS ID, Index
‘코드와 서비스 만들기를 좋아하는 소프트웨어 엔지니어’로 일하고 있다. 엔지니어는 문제를 해결하는 사람이다. 문제를 해결하는 과정에는 여러 가지 선택이 존재할 수 있다. 가능한 최선의 결과를 위해, 항상 내 선택의 Why에 답할 수 있는 사람이 되고자 한다. 매주, 한 주 동안 내가 결정한 선택의 Why에 대해 정리하고자 한다.
마지막 WHY 시리즈 글을 작성한 지 약 3개월의 시간이 지났다. 약 3개월의 시간은 베트남에서 프로덕트를 오픈한 기간과 유사하다. 그동안 오픈한 서비스를 유지보수 하면서, 동시에 서비스 고도화를 진행하고, 운영팀 지원도 병행하면서, 새로운 백엔드 엔지니어 채용까지 병행하며 매우 정신없는 시간을 보내고 있었다. 아니 여전히 진행 중이다. 여유가(물리적인 시간 보다 오히려 마음의 여유) 생길 때까지 기다리며 다시 이 글을 쓸 수 있는 날을 기대했지만, 기대만 하다가는 언제 다시 시작할지 모른다는 두려움이 생겼다. 그래서 점심 먹고 나른한 주말 오후 맥북을 열고 일을 시작하는 대신 무작정 이 글을 써본다. 너무나 많은 일이 지나갔던 3개월을 돌아보며 그동안의 프로덕트를 위한 결정에 WHY를 던져본다.
Why?
1. BigQuery
프로덕트를 오픈하고 디자이너, 개발자, PM이 속해있는 우리 프로덕트팀도 정신없이 바쁘지만, 실제 프로덕트가 운영되면서 운영팀 역시 정신없는 시간을 보내고 있다. 운영팀 역시 필요한 영역에 맞게 다양한 파트로 이루어져 있으나 각 파트의 업무를 위해 주문 데이터를 자유롭게 얻고 분석할 수 있는 환경은 공통으로 필요했다. 꽤 괜찮은 환경을 구축하기에는 리소스가 부족했고, 우선순위가 높은 다른 작업들이 존재했다. 당시에 내린 결정은 우리의 관리자 도구에서 하루 동안의 주문 데이터를 CSV 형태로 다운받을 수 있도록 임시 기능을 제공 하자였고, 운영팀은 약 2개월 동안 이러한 열악한 환경에서 일을 해내고 있었다. 지금 우리는 Google Cloud에서 제공하는 빅 데이터 분석 플랫폼인 BigQuery로 분석 환경을 구축하고 있다.
- Why? 분석 목적에 맞게 원하는 데이터를 원하는 포맷으로 사용할 수 있다. 지금까지 관리자 도구에서 제공했던 임시 기능은 서버에서 전달하는 CSV 포맷으로만 그리고 주문 데이터에 한해서만 이용 가능했다. 당연히 각 운영 파트에서는 해당 데이터를 본인들이 원하는 포맷으로 확인할 수 있도록 2차 가공하여 사용하고 있었다. 현재는, 매일 그날의 주문 데이터가 BigQuery로 전달되고 원하는 사람들은 BigQuery 콘솔에서 직접 Query를 통해 원하는 데이터 포맷을 확인할 수 있다.
- Why? 서비스가 실행 중인 서버에 영향을 주지 않는다. 기존 관리자 도구의 임시 기능은 실제 프로덕트 서버를 통해 데이터베이스의 주문 데이터를 조회하고 가공하여 CSV 파일을 반환했다. 실제로 서비스 운영 시간 중, 해당 기능 요청이 한 번에 몰리는 상황이 있었고 아찔하게도 서비스 피크 타임과 겹치는 일이 발생했었다. 어쩌면, 이때 부터 우선순위가 높지 않다는 판단에 의심을 품기 시작하고 BigQuery 플랫폼으로 이전하는 작업을 진행한 것 같다. 어쨌든, BigQuery 플랫폼으로 주문 데이터를 전달하고 임시 기능을 제거했다. 이제는 분석을 위한 목적으로 데이터를 조회하고 가공하는 작업이 프로덕트 서버 그리고 사용자들에게 영향을 줄 것이라는 불안을 제거할 수 있게 됐고, 누구든 언제나 원하는 데이터를 좋은 성능으로 확인할 수 있는 환경을 갖게 되었다.
아직 개선해야 할 점이 많다. 당장 이번 주에는 주문 데이터 이외에도 다른 종류의 데이터가 BigQuery에 쌓일 수 있도록 해야 하고, BigQuery에 이 데이터들을 쌓는 게 최선일까 하는 의문을 나와 동료는 조금씩 갖고 있었는데 이 의구심들을 해소하기 위해 Research도 필요하다. 앞으로 데이터 분석 환경을 어떻게 개선해갈 수 있을지 역시 기대되는 포인트이다.
2. CS ID
우리 프로덕트의 핵심은 주문이다. 자연스럽게 시스템에서 주문을 식별하기 위한 고유한 ID를 부여하여 사용하고 있었다. 시스템상에서는 주문에 대한 고유한 ID 역할을 잘 수행하고 있었으나, 문제는 운영하는 과정에서 발생했다. 대소문자가 섞여 있는 주문 ID를 고객과 운영팀에서 커뮤니케이션할 때 발생할 수 있는 어려움의 크기를 예상하지 못했던 것이다. 그래서 우리는 CS를 위한 ID 필드를 ‘YYMMDD + 4자리 영어 대문자’ 포맷으로 추가했다.
- Why? 하루 동안의 주문을 하나의 그룹으로 간주하고, 그 안에서 식별할 수 있는 포맷을 생각했다. 하루 동안이라는 기준을 반영하기 위해 prefix로 YYMMDD를 적용했다. 하루 동안의 submit 된 주문 수를 고려하고 고객과 운영팀이 커뮤니케이션하는데 불편함이 없는 정도를 고려하여 4자리 영어 대문자를 추가했다. 4자리 영어 대문자라면 하루에 약 45만 개 정도의 주문 수를 커버할 수 있기에 충분하다고 판단했다.
- Why? 당연히 가장 큰 이유는 고객의 커뮤니케이션 불편함을 해소하기 위함이다. 내가 고객의 입장이어도, ‘UlTm1OHU1’ 이러한 주문 ID를 말하며 운영팀과 커뮤니케이션 하느니 그 주문을 포기할 수도 있겠다 싶다. 고객뿐만 아니라 실제로 운영팀 내부에서의 커뮤니케이션도 수월해졌다.
사소할 수 있는 이슈이지만 ‘왜 항상 만들기 전에는 생각하지 못할까?’ 싶은 아쉬움이 남는다. 프로덕트를 만들고 운영해가면서 스스로에게 바라는 점은 크고 대단한 것 보다, 사소하지만 실제로 프로덕트에 효과를 줄 수 있는 점을 미리 사고할 수 있는 태도이다.
3. 데이터베이스 index 최적화
우리 프로덕트 역시 검색 성능이 중요한 Collection이 존재한다. 사용자의 위치 및 거리를 기반으로 검색 결과를 반환하는 기능이 그것이다. 프로덕트 오픈과 동시에 존경하는 나의 동료는 데이터베이스 index 최적화 작업을 진행했다. 적절한 index 설정을 통해 우리는 일차적인 조회 및 검색 성능 개선이라는 결과를 얻었다.
- Why? 조회, 검색 성능 개선은 사용자가 체감하는 서비스 경험에 긍정적인 효과를 준다. 이를 위해, 우리 서버에서 사용하는 쿼리를 정리하고 해당 쿼리에서 조회 및 검색에 사용하는 필드들을 정리했다. 데이터의 양, 쿼리 빈도수, 중요도 등을 고려하여 index 처리가 필요한 필드들을 정리했다. 정리한 내용을 바탕으로 테스트 데이터 셋을 구축하고 Single index, Compound index를 설정하여 index 전후의 성능을 비교했다.
대부분의 기능에서 성능 향상을 보였지만, index 최적화 이후 Mongoose의 hydrate 처리 성능에 문제가 있는 것을 또(?) 발견했다. hydrate 제거 전후의 성능은 또 어떻게 개선될지 현재 Backlog로 남겨 둔 상태이고 다음 글에서 공유할 수 있기를 기대한다.
그 사이에 동료들에게 많은 변화가 있었다. 새로운 동료들이 많이 들어오고, 함께 프로덕트를 오픈했던 몇몇 동료는 새로운 길을 위해 떠나기도 했다. 우리 프로덕트는 감사하게도 비교적 좋은 데이터를 보여주고 있다. 프로덕트를 오픈하기 전, 무리한 예측이 아니냐며 웃어넘겼던 데이터 수치를 실제로 눈앞에서 확인하고 있으니 이 얼마나 감사한 일인가. 그만큼 할 일이 기하급수적으로 많아지고 있다는 의미이기도 하지만 어쨌든 요즘의 힘듦은 감사하고 기쁨의 힘듦이다. 더 잘 해내고 싶다.