AppSignal을 사용하는 앱이 실행 중인 모든 서버는 30초마다 샘플과 메트릭 데이터를 저희 Push API로 전송합니다.
월 300억 건의 요청, 캐싱으로 쿼리 줄이기
각 요청에는 데이터가 어떤 앱에서 전송된 것인지 식별하는 키가 포함되어 있습니다. 이를 처리하려면 들어오는 모든 요청에 대해 데이터베이스를 조회해 해당 앱을 찾아야 합니다. 월 300억 건이라는 방대한 요청량을 감안할 때, AppSignal을 더 빠르게 만들기 위해서는 쿼리 수를 줄이는 방법을 끊임없이 고민해야 했습니다.
그래서 저희는 데이터베이스 클러스터의 부하를 줄이기 위해 캐싱을 도입했습니다. 데이터베이스에서 앱 정보를 가져올 때마다 Memcached에 1분간 저장하는 방식입니다. 하지만 이 변경 사항을 프로덕션에 배포한 후, 결과는 예상과 달랐습니다. 오히려 이전보다 쿼리가 더 많이 실행되고 있었던 것입니다. 캐시가 필요 이상으로 자주 무효화되고 있는 듯했는데, 문제의 원인을 파악하기 위해 커스텀 메트릭을 추가했습니다.
캐시 무효화 지점 추적하기
캐시가 무효화되는 지점은 여러 곳에 있습니다. 예를 들어 push 처리 시간이 갱신될 때, 혹은 새로운 네임스페이스가 감지될 때 등입니다.
어떤 무효화 경로가 문제의 원인인지 밝혀내기 위해 여러 개의 카운터를 추가했습니다. 아래 예제에서는 전체 무효화 횟수를 집계하는 app.cache.invalidate 카운터를 두고, 개별 무효화 사례에는 app.cache.invalidate_push_time, app.cache.invalidate_namespaces 같은 세부 키를 사용해 구분해서 기록합니다.
그래프로 드러난 진짜 원인
위와 같은 커스텀 메트릭을 추가하자 시간 흐름에 따른 캐시 히트 추이를 그래프로 확인할 수 있었습니다. 덕분에 어떤 캐시 키가 쿼리 급증의 원인인지 즉시 드러났습니다. 바로 app.cache.invalidate_namespaces 키가 매 요청마다 무효화되고 있었던 것입니다.

캐싱 가능한 전체 요청 수는 app.cache.maybe로 집계됩니다.
문제를 수정한 뒤 재배포한 결과, 앱의 네임스페이스가 업데이트되지 않는 한 무효화 횟수가 0으로 유지되었습니다.

커스텀 메트릭의 힘
커스텀 메트릭을 활용하면 무슨 일이 어디서, 언제, 얼마나 자주 발생하는지 훨씬 명확하게 이해할 수 있습니다. 이번 사례에서도 캐시 무효화 횟수를 파악하고 가독성 좋은 그래프로 시각화했기 때문에 문제를 신속하게 찾아낼 수 있었습니다. 특정 값을 증가시키는 코드 몇 줄과 대시보드 하나면 충분합니다.
커스텀 메트릭에 대해 궁금한 점이 있거나, 애플리케이션에 직접 설정하는 과정에서 도움이 필요하시다면 언제든지 알려주세요. 기꺼이 도와드리겠습니다!

Robert Beekman
공동창업자로서 Robert는 저희의 첫 번째 커밋을 작성한 인물입니다. 동시에 고객 지원 팀의 롤모델이며, 코드 속 가장 작은 디테일까지 꿰고 있습니다. 여행과 사진 촬영(동시에!)을 즐깁니다.