-
Google Firebase Analytics의 Logging 전략카테고리 없음 2025. 9. 25. 20:44
기획과 디자인 그리고 개발을 통해 출시된 서비스를 유저가 접하기까지 많은 수고가 필요하다. 매 순간 쏟아지던 서비스들 사이에서 AI 발전으로 인해 사람들은 더욱 많은 서비스가 출시되고 있고 그중 우리 서비스가 선택되기 위해선 더 많은 광고와 마케팅, 그에 따른 비용이 필요하다.
소비자는 친절하지 않다.
하지만 이렇게 공들여 데려온 유저가 서비스를 떠나버리는 건 너무나 쉽다. 불편한 UI / UX, 작동하지 않는 기능, 무차별적인 광고 등 유저 입장에서 마음이 돌아설 요소들을 제거하고 유저 이탈을 막는 것이 중요하다. 정말 고맙게도 스토어에 리뷰를 작성해 주는 유저도 존재하지만 이건 앱이 개선되어 더 편하게 사용하고 싶은 진성 고객에 해당한다. 대부분의 사용자는 마음에 들지 않으면 다른 서비스를 찾으러 간다. 그렇기에 유저 환경을 세심히 분석하고 문제를 제거해야 한다.
데이터 처리 방식의 궁금증
따라서 화면전환, 버튼 클릭, 이상 감지 등을 기반으로 모든 서비스 이용자의 행동을 자동으로 취합하고 분석할 필요가 있다. 안드로이드 진영에선 사용자 분석을 위해 Google Firebase Analytics를 사용해 정보를 수집, 분석하는 것이 일반적이다. Firebase Analytics는 무제한 리포팅을 무료로 제공하고 있다.
무한에 가깝게 업로드하는 환경에서 클라이언트의 부하를 줄이기 위해 Firebase Analytics는 어떤 전략을 이용했을지 궁금했다. 당장은 Firebase Analytics를 사용하는 정도에 그치겠지만 전략을 이해하고 있다면 로깅이 아닌 다른 데이터 처리 시 효율적인 처리를 할 수 있을 거란 생각도 있어 Firebase Analytics의 로깅 전략을 알아본다.
이벤트 처리 전략 1 - Caching
// https://firebase.google.com/docs/analytics/get-started?_gl=1*w3ia9i*_up*MQ..*_ga*MTgzMzI5NDI0LjE3NTg2OTk3MjA.*_ga_CW55HF8NVT*czE3NTg2OTk3MTkkbzEkZzAkdDE3NTg2OTk3MTkkajYwJGwwJGgw&platform=android#start_logging_events_2 firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_ITEM) { param(FirebaseAnalytics.Param.ITEM_ID, id) param(FirebaseAnalytics.Param.ITEM_NAME, name) param(FirebaseAnalytics.Param.CONTENT_TYPE, "image") }Firebase Analytics는 실시간으로 모든 이벤트를 즉시 서버로 전송하지 않는다. 사용자 이벤트가 발생했을 때 소스 코드 내부적으로 logEvent()가 호출되고 전달받은 이벤트 데이터는 로컬 데이터베이스에 저장된다. 이때 CPU나 메모리를 거의 사용하지 않는다. 이는 SQLite 데이터베이스에 데이터를 한 줄 삽입하는 것과 유사하며 마이크로초 단위로 끝나는 매우 가벼운 작업이다. for 루프에서 수천 번 돌리지 않는 한, 사용자나 디바이스에선 부담이 없는 수준이다. 메모리 또한 이벤트 객체를 생성하는 데 필요한 몇십, 몇백 바이트 수준의 메모리만 사용하며 바로 해제되므로 부담이 적다.
이벤트 처리 전략 1 - Batch
이벤트 데이터는 특정 조건이 충족될 때까지 기다리며 그동안 쌓인 이벤트들을 한 번에 묶어서 압축한 뒤, 단 한 번의 네트워크 연결로 서버에 전송한다. 마치 편지를 한 통씩 우체국에 보내는 게 아니라, 여러 통을 모아서 한 박스에 담아 한꺼번에 보내는 것과 같다. 업로드가 이루어지는 배치 전송 트리거는 다음과 같다.
1. 시간 기반: 약 1시간 주기로 업로드를 시도한다. 이 주기는 기기 상태나 앱 사용량에 따라 동적으로 조절될 수 있다. 2. 앱 생명주기 기반: 사용자가 앱을 백그라운드로 전환할 때 SDK는 업로드를 시도한다. 사용자가 앱을 사용하지 않을 때 처리하므로 성능 저하를 최소화 한다. 3. 네트워크 연결 상태 기반: 오프라인 상태에서 쌓인 이벤트들은 기기가 다시 온라인 상태가 되었을 때 다음 업로드 주기에 맞춰 전송된다.뿐만 아니라 안드로이드 시스템 기반으로 네트워크 종류, 충전 상태, 기기 유휴 상태(Doze) 등을 고려하여 적절히 데이터를 업로드한다. 업로드 시점엔 로컬 DB에서 이벤트를 읽어와 스키마 기반의 매우 가벼운 Protobuf 형식으로 직렬화하고 압축한다. 이를 통해 일반적인 Json보다 3~10배 정도 작은 크기로 데이터를 처리할 수 있다.
데이터 전송 방식
데이터를 아무리 압축해도, 데이터를 보내기 위해 연결을 맺는 TCP 3-way handshake 과정 자체에서 많은 시간과 메모리를 소비할 수 있다. 이 과정은 최소 1 RTT(Round-Trip Time, 데이터가 서버까지 갔다가 돌아오는 시간)를 소요하는데, 특히 네트워크 상태가 불안정한 모바일 네트워크 환경에서는 부담이 클 수밖에 없다.
Google은 통신 연결을 맺는 시간 자체를 줄이기 위해 다음 전략들을 사용한다.
네트워크 전략 1 - 연결 덜 하기
가장 간단한 개선 방법은 한 번 맺은 연결을 바로 끊지 않고 재활용하여 핸드셰이크 비용을 절약하는 것이다.
- TCP Keep-Alive
클라이언트와 서버가 한 번 TCP 연결을 맺으면, 당분간 통신할 수 있으니 통신 경로를 열어두자고 합의한다. 그리고 잠시 동안 연결을 유지한다. 만약 Firebase Analytics가 데이터를 업로드해야 할 때 이미 다른 Google 서비스(FCM, 구글 로그인 등)와의 통신으로 맺어진 연결이 살아있다면, 그 연결을 그대로 재활용하여 핸드셰이크 과정을 생략하고 바로 데이터를 보낸다. - HTTP/2 Multiplexing
Firebase 통신은 최신 HTTP/2 프로토콜을 사용한다. HTTP/1.1에서는 요청마다 별도의 TCP 연결이 필요했지만, HTTP/2는 단 하나의 TCP 연결 위에서 여러 개의 데이터 요청을 동시에 처리할 수 있다. 만약 Analytics만 이용하는 것이 아닌 Firebase의 Remote Config, Authentication, Database 등 여러 요청이 필요할 때, 연결을 딱 한 번만 맺고 모든 요청을 그 통로 위에서 처리해버립 수 있다.
네트워크 전략 2 - 연결 빨리하기
기존 연결이 없어 새로 연결을 맺어야 한다면, 연결 과정 자체를 단축시킨다.
- TCP Fast Open (TFO): 이전에 한 번이라도 통신했던 서버에 다시 연결할 때, 3-way handshake의 마지막 단계를 기다리지 않고 첫 패킷(SYN)에 암호화된 쿠키와 함께 보낼 데이터를 실어 보내는 기술이다. 서버는 쿠키를 검증하고 즉시 해당 데이터를 처리할 수 있다. 이를 통해 1 RTT를 절약하여 연결 지연 시간을 거의 절반으로 줄일 수 있다.
- QUIC (HTTP/3) 프로토콜: 구글이 개발하여 UDP 프로토콜 위에서 동작하는 TCP 대체용 전송 계층 프로토콜이다. TFO와 유사하게, 이전에 연결했던 서버와는 단 한 번의 핸드셰이크도 없이(0-RTT) 바로 암호화된 통신을 시작할 수 있으므로 지연 시간 관점에서 가장 이상적인 방식이다. 또한 여러 스트림이 독립적으로 동작하여 하나의 패킷이 유실되어도 다른 스트림은 영향을 받지 않는다. 이는 네트워크가 불안정한 모바일 환경에서 매우 큰 장점으로 작용된다.
Firebase 서비스를 사용하는 클라이언트가 두 방식을 어떤 식으로 조합해 사용하는지는 찾을 수 없었지만 Firebase 서버에 연결 요청 시 서로 QUIC를 지원하는 것을 알기에 우선 사용할 것으로 생각된다. 다만 QUIC는 UDP 433 포트를 사용하는데, 통신 과정에 있는 방화벽이 해당 포트를 차단하거나 구장비로 인해 실패하는 경우는 TFO로 연결을 맺지 않을까 싶다. 혹은 TFO와 QUIC를 동시에 보내고 먼저 연결이 온 프로토콜을 기억해 두고 네트워크의 변경이 없다면 해당 프로토콜로 처리하는 식의 동작을 처리할 수도 있을 것이다.
결과적으로, Firebase Analytics는 수많은 로깅 처리를 하기 위해 데이터를 압축 및 연결 횟수 자체를 최소화하고, 연결 과정을 최적화시킴으로써 클라이언트의 부하를 최소화한다.
마무리
사람들이 많이 쓴다는 기술을 무분별하게 가져와 쓰기보단 왜 이것을 사용해야 하는지, 내부동작이 대략적으로나마 어떻게 구성되어 있는지를 아는 것이 중요하다고 생각한다. 개발 과정에서 AI의 도움을 많이 받고 있는데 내가 이루고자 하는 목표를 이해하고 중심이 되어주었을 때 제대로 된 결과물을 제시해 준다. 힘이 없는 질문엔 방향이 없고 금방 무너진다. 쏟아지는 정보 속에서 끊임없이 질문하고 근거 기반의 이야기하는 힘이 필요한 요즘이다.
- TCP Keep-Alive