스택드라이버 로깅을 테스트 하고자 로컬 환경에서 로그를 올리기 위해서 fluentd를 설치했는데
일단 설치는 서비스 어카운트를 다운 받아서 하면 되긴 하는데, 실행을 하고 로그를 전송하려면 아래와 같은 이유가 난다.
2019-04-02 01:20:36 +0900 [error]: #0 Failed to access metadata service: error_class=Errno::EHOSTUNREACH error="Failed to open TCP connection to 169.254.169.254:80 (No route to host - connect(2) for \"169.254.169.254\" port 80)" 2019-04-02 01:20:36 +0900 [info]: #0 Unable to determine platform 2019-04-02 01:20:36 +0900 [error]: #0 Failed to set monitored resource labels for gce_instance: error_class=RuntimeError error="Cannot construct a gce_instance resource without vm_id and zone"
169.254.169.254 로 호출을 하게 되어 있는데, 이게 구글 클라우드와 AWS IP대역에서만 호출할 수 있는듯.
이론적으로는 Fluentd를 사용하기 때문에, 다른 인프라에서도 될줄 알았는데. IP 대역을 막아놨네 그랴..
얼마전에 구글 클라우드의 모니터링 솔루션인 stack driver에서 profiler 기능이 발표되었다. (https://cloud.google.com/profiler)
우리가 일반적으로 생각하는 성능 분석을 위한 profiling 도구로, 구글 클라우드 뿐만 아니라, 여러 서버에서 동작하는 Java/node.js/Go 애플리케이션의 성능을 모니터링할 수 있다.(파이썬은 곧 지원 예정)
장점은 코드 수정없이 간단하게 에이전트만 추가함으로써 프로파일러 사용이 가능하고, 프로파일링된 결과를 stackdriver 웹 콘솔에서 바로 확인이 가능하다는 것이다.
JDB등 전통적인 프로파일러가 있기는 하지만 보통 프로파일러가 적용되면, 애플리케이션의 성능이 극단적으로 느려지기 때문에, 운영환경에 적용이 불가능한데, Stack driver profiler의 경우에는 성능 저하가 미비하여 운영환경에도 적용이 가능하다.
"Stackdriver Profiler uses statistical techniques and extremely low-impact instrumentation that runs across all production application instances to provide a complete picture of an application’s performance without slowing it down."
아래는 자바 애플리케이션을 프로파일을 하기 위해서 프로파일러 바이너리를 agentPath에 추가한 형태이다
아래는 자바 애플리케이션을 프로파일을 하기 위해서 프로파일러 바이너리를 agentPath에 추가한 형태이다
애플리케이션은 http://bcho.tistory.com/1247 에서 사용한 간단한 REST API를 사용하였다.
코드를 실행해서 프로파일링 데이타를 얻고 나면 아래와 같이 구글 클라우드 콘솔에서 프로파일링 결과를 확인할 수 있다.
위의 뷰는 WALL뷰로, 전체 프로그램이 수행되는 중에, 어느 코드가 시간을 얼마나 사용했는지를 프로파일링 해준결과이다.
이 외에도 CPU 시간으로 볼 수 도 있고, 메모리 사용률등 다양한 뷰
대규모 분산 서비스나 MSA 구조에 적합하도록 프로파일 결과를 볼 수 있는 범위를 선택이 가능한데, 상단의 메뉴를 보면 프로파일링 결과를 볼 서비스와, 프로파일 타입 (CPU,WALL:메서드별 실행시간, 메모리 사용률), 그리고 서비스가 배포된 클라우드 존, 서비스 버전 등에 따라서 선택이 가능하다. 아래는 언어별로 지원하는 프로파일 타입이다.
Profiler의 뷰는 애플리케이션 타입에 상관이 없이 순수 프로그래밍 플랫폼에만 연관된 뷰로만 보여준다.
무슨이야기인가 하면, 보통 웹 애플리케이션은 멀티 쓰레드 타입으로 동작하고, REQUEST가 들어오면 쓰레드가 하나의 요청을 처리하고 빠지는 형태이기 때문에, 쓰레드별로 어떤 메서드가 순차적으로 실행되었는지등의 뷰를 선호하는데, JENNIFER나 오픈 소스 스카우터와 같은 APM (Application Peformance Monitoring)툴이 이러한 뷰를 제공한다.
위의 샘플을 보더라도, 톰캣서버의 쓰레드들이 대부분 모니터링 될뿐 직접 코딩한 메서드들이 관측 되지는 않는다. (사용자 코드가 적고, 실행시 별로 크게 시간을 소요하지 않는 것도 원인이기는 하지만)
만약에 REQUEST에 대한 메서드별 소요 시간 모니터링 및 병목 구간 확인을 하려면, Stack driver profiler보다는 Stack driver trace를 사용하는 것이 적절하다. http://bcho.tistory.com/1245
그래서 Stack Driver는 성능 모니터링 (APM)제품군을 Trace, Profiler, Debugger 3가지로 묶고 있고, (Debugger는 나중에 시간이 되면 테스트하고 다루도록 하겠다.) 각기 다른 뷰로 상호 보완적인 관점에서 성능 모니터링이 가능하도록 하고 있다.
스택드라이버는 구글 클라우드에서 서비스로 제공되는 시스템 로그 및 모니터링 시스템이다. CPU,메모리사용량과 같은 하드웨어에 대한 정보에서 부터 웹서버나 OS와 같은 미들웨어 및 애플리케이션 로그를 수집, 검색 및 분석할 수 있으며, 여러 오픈 소스 (MongoDB, CouchDB, Redis - https://cloud.google.com/monitoring/agent/plugins/ )등에 대한 모니터링도 가능하다.
구글 클라우드 뿐 아니라, AWS에 대한 모니터링을 통합으로 지원하는 등, 상당히 많은 기능을 가지고 있다.
이 글에서는 스택드라이버를 이용하여 애플리케이션 로그를 수집하고 이를 분석하는 방법에 대해서 설명하고자 한다.
자바를 기반으로 애플리케이션 로깅을 설명한다. 자바 애플리케이션에서 스택드라이버로 로그를 남기는 방법은 여러가지가 있으나, 일반적으로 자바 프로그래밍 언어에서 많이 사용하는 로깅 프레임웍은 SL4J 를 이용한 로깅과, 스택드라이버 SDK를 이용하여 JSON 형태로 로그를 저장하는 방법에 대해서 알아보도록 한다.
API 인증
스택 드라이버를 사용하기 위해서는 로그 API에 대한 인증이 필요하다. 인증에는 여러가지 방법이 있는다. 사용이 쉬운 방법을 설명한다.
로컬 환경 또는 타 환경에서 인증
로컬 개발환경이나 클라우드에서 인증을 하는 방법은 서비스 어카운트 (Service Account)를 사용하는 방법이 있다. 서비스 어카운트는 구글 클라우드 콘솔에서 IAM 메뉴에서 생성할 수 있다. 서비스 어카운트 메뉴를 아래와 같이 선택한 다음.
상단 메뉴에서 Create Service Account 버튼을 누르고 서비스 어카운트 생성한다.
서비스 어카운트에는 서비스 어카운트의 권한을 설정할 수 있는데, Project Owner로 설정하면 모든 권한을 다 가질 수 있고, 여기서는 로깅 권한만을 줄것이기 때문에, Logs Writer 권한만을 지정한다.
계정 생성을 하면 json 파일이 다운로드 된다.
이 파일은 환경 변수 GOOGLE_APPLICATION_CREDENTIALS 에 파일 경로를 지정해주면 된다.
구글 클라우드 VM내에서 자바 코드를 실행할 경우 VM 자체에 API 접근 권한을 부여할 수 있다. 보통 운영환경에서는 이 방법이 권장된다.
아래와 같이 VM 생성시 “Identity and API access” 에서 API 접근 권한을 주면 된다. Set access for each API를 써서 Logging write 권한만을 줄 수 있고, 아니면 Allow full access to all Cloud APIs 를 이용해서 전체 API에 대한 권한을 줄 수 도 있다.
SL4J를 이용한 로깅
sl4j를 이용한 로깅은, 기존의 sl4j 로거를 그대로 사용하기 때문에 코드 변환이 거의 없고, 단지 maven 에서 라이브러리 의존성을 스택드라이버 로거로만 변경해주면 되기 때문에 별도의 학습이 필요없고 사용법이 단순하다는 장점이 있다. sl4j 로깅은 단순하다.
sl4j는 사용이 간편한 반면에 텍스트 문자열로 로깅이 되기 때문에, 구조화된 정보 (JSON)이나 여러 필드를 가지는 로그를 남기기가 쉽지 않다는 단점을 가지고 있다. 스택드라이버 전용 SDK를 사용하면, JSON등 다양한 포맷으로 로그를 쉽게 남길 수 있다. (sl4j의 경우에도 LoggingEnahncer를 사용하면 가능하기는 하다)
이 예제는 JSON 포맷으로 데이타를 저장하는 방법인데, 단순하게 1 레이어의 JSON을 저장하도록 하였다. Map을 이용하여 jsonMap을 정의하고, put을 이용하여 key, value 값을 저장한다.
String text = "Hello, world!";
Map<String, Object> jsonMap = new HashMap<String, Object>();
jsonMap.put("elapsedtime", 11);
다음 로그를 저장하기 위해서는 LogEntry 객체를 이용해야 하는데, LogEntry는 LogEntry.newBuilder(PayLoad)를 이용하여 생성한다. Text 로그를 저장하는 TextPayLoad를 사용하거나 다른 페이로드도 있지만 여기서는 JsonPayLoad를 사용하였다.
LogEntry.newBuilder(JsonPayload.of(jsonMap))
다음 로그 Serverity (INFO,ERROR,WARNING)는 setServerity로 정할 수 있다. 스택 드라이버 로그는 정보 구조에서 계층 구조를 가질 수 있는데, 다음과 같은 개념을 가지고 있다.
리소스
리소스는 이 로그가 어떤 자원에 속하는지를 정의한다. 예를 들어, VM, 빅쿼리와 같이 어떤 인프라에 속하는지를 정의할 수 있는데, 애플리케이션의 경우 일반적으로 “global” 리소스로 정의한다.
리소스 명은 setResource메서드를 이용해서 지정이 가능하다.
라벨
다음 로그에 라벨을 달 수 있다. 예를 들어 이 리소스가 VM인데, 어떤 VM인지 식별을 하기 위해서 키를 name, 값을 인스턴스명 등으로 지정할 수 있다. 또는 개발/운영 환경인지를 구별하기 위해서 env 라는 키를 이용해서 환경에 따라 값을 dev,qa,prod 등으로 달 수 있다. 하나의 로그에는 여러개의 라벨을 붙이는 것이 가능하다. 라벨은 키,밸류 형태로 .addLabel(키,값)으로 추가가 가능하다.
로그 이름
로그 이름은 로그를 그룹핑할 수 있는데, 애플리케이션 종류등으로 그룹핑을할 수 있다. 이 로그는 사용자 로그, 게임 로그 등으로 그룹핑이 가능하다. 그룹 명을 setLogName으로 지정이 가능하다.
아래는 리소스를 global, 로그 이름을 LOG_NAME, 라벨에 instancename을 키로, instance-1이라는 값을 지정한 코드 예제이다.
로그는 구글 클라우드 콘솔에서 STACKDRIVER > Logs 항목에서 확인이 가능하다.
위 그림과 같이 메뉴로 진입한 후에, 로그를 볼 수 있다.
리스트 박스에서 첫번째 박스는 리소스를 선택하는 화면으로 애플리케이션 로그는 앞의 예제에서 리소스를 global로 선택하였기 때문에, global을 선택한다. 그리고 두번째는 로그 이름을 고르는 화면인데, 앞에 예제에서 terry-tutorial로 로그 이름을 지정하였기 때문에 terry-tutorial을 선택한다.
다음 위의 화면에서 버튼을 누르면 실시간으로 로그를 볼 수 있는데, 통상 1분이내의 딜레이가 소요된다고 보면 된다.
로그에서 각 항목을 펼쳐보면 디테일을 볼 수 있다. 아래는 하나의 디테일인데, 중요한 부분은 timestamp에서 시간이 기록되고, serverity에 에러 레벨이 기록된다. 그리고 앞에서 지정한 Json PayLoad가 jsonPayLoad 라는 항목으로 들어간다. 라벨은 labels라는 항목에 키/밸류 형식으로 지정이 되는 것을 볼 수 있다.
로그 검색 및 필터링
스택드라이버의 강력한 기능중 하나가 로그에 대한 검색과 필터링인데, 스택 드라이버 콘솔 상단 화면에서 필터링(검색) 조건을 넣으면 각 필드 값에 따라서 다양한 형태로 로그 검색이 가능하다.
이 조건은 resource가 global이고, 그중에서 jsonPayload.count 가 900 보다 큰 로그만을 추출하는 방법이다. (Advanced filter를 사용하엿음)
스택 드라이버의 다른 장점 중의 하나는 저장된 로그를 다른 시스템으로 EXPORT할 수 있는데, 크게 다음 3가지로 EXPORT가 가능하다.
GCS (파일) : Google Cloud Storage에 파일로 로그를 저장이 가능하다.
Pub/Sub (실시간 스트리밍) : 실시간으로 로그를 Pub/Sub 큐로 저장이 가능하다. Pub/Sub 뒤에 컨슈머를 둬서 다양한 처리가 가능하고 (알럿등) Apache Beam (Dataflow)연동을 통해서 실시간으로 로그를 분석 하는 것이 가능하다
BigQuery (데이타 베이스) : 실시간으로 데이타를 대용량 데이타 베이스는 빅쿼리에 저장하여 다양한 쿼리 및 시각화가 가능하다.
로그 EXPORT는 상단 메뉴의 CREATE EXPORT 버튼을 이용하면 EXPORT 정의가 가능하다.
이때 흥미로운 점은 로그 EXPORT시 필터에 조건을 걸어놓으면, 필터에 맞는 조건에 있는 로그만 EXPORT가 된다. 즉 로그 레벨이 CRITICAL한 로그만 Pub/Sub으로 로깅해서 알럿을 보내는 것과 같은 작업이 가능하게 된다.
빅쿼리로 EXPORT
그럼 그중에서 빅쿼리로 로그를 EXPORT하는 방법에 대해서 알아보기로 한다.
빅쿼리로 EXPORT하기 위해서는 CREATE EXPORT를 누른 후에, 로그 SINK 명을 지정하고 데이타셋을 지정해야 하는데, 데이타셋을 새로 생성하면 된다.
이 예제에서는 필터를 추가하여 label에서 instancename이 “instance-1”인 로그만 빅쿼리로 저장하도록 EXPORT 설정을 하였다.
http://bigquery.google.com에 들어가면 앞에 지정한 이름으로 데이타셋이 생긴것을 확인할 수 있고, 테이블명은 앞에서 지정한 로그명인 terry_tutorial 로 지정된것을 확인할 수 있다.
다음은 로그 시간과, JsonPay로드의 elapsedtime과, count 값을 조회하는 쿼리와 결과 이다.
쿼리 결과
데이타 스튜디오를 이용한 로그 시각화
이렇게 빅쿼리에 저장된 데이타는 구글 데이타 스튜디오를 이용하여 손쉽게 시각화가 가능하다.
https://datastudio.google.com에 접속한 후에, Start New Report에서 Blank Report 만들기를 선택한다.
새로운 리포트 화면이 나오면 우측 하단의
를 선택하여 빅쿼리 테이블과 연결을 한다.
좌측 커넥터를 선택하는 화면에서 BigQuery를 선택한후
MY PROJECT에서 내 프로젝트를 고르고, 데이타셋과 테이블은 선택한다.
다음으로 상단의 CONNECT 버튼을 눌러서 테이블을 연결한다. 또는 프로젝트를 선택하는 대신 CUSTOM QUERY를 누르면, 직접 SQL을 써서 특정 필드만 조회할 수 있다.
여기서는 전체 테이블을 불러오는 것으로 진행하도록 한다.
다음 화면에서는 필드 선택 및 제거, 그리고 타입 설정등이 가능하다.
적절하게 사용할 필드를 선택하고, 타입을 지정한후, 우측 상단의 ADD TO REPORT를 선택한다.
타임 스탬프는 일반적으로 일단위로 컨버팅 되기 때문에, 세밀한 로그를 원하면 분단위 등으로 변경하거나 커스텀 쿼리를 이용해서 초단위 값으로 컨버팅하기를 권장한다.
다음 메뉴에서 그래프나 표를 선택하여 적절하게 그리고, X 축은 Deminsion에 설정한다. 아래는 Dimension을 timestamp로 선택하고, Y축은 Metric 값으로 jsonPayload.count를 준 예이다.
혹시 테이블을 그린후에 데이타가 나오지 않는 경우가 있는데, 이 경우는 대부분 DataStudio의 Time zone과 빅쿼리에 저장된 Time이 맞지 않아서, 쿼리 범위에서 제외되는 경우인데, 이 경우는 그래프의 Property에서 날짜 범위를 다음과 같이 조정해주면 된다.
구글 클라우드 VM에 서버를 설치한 후 웹을 접근하고자 할때, 설치한 애플리케이션이 ACL (접근 제어) 처리가 안되어 있는 애플리케이션이 있을 수 있다. 특히 관리자 콘솔 같은 경우에 이런 경우가 많은데, 아파치 에어플로우 역시도 설치 후에 웹 서버를 띄우면 포트가 모두 퍼블릭으로 오픈되기 때문에 관리자만 액세스가 가능하도록 ACL 처리를 할 필요가 있다.
이를 위한 방법으로는 몇가지가 있는데
방화벽으로 특정 포트만 허용 하는 방법
앞에 nginx나 apache를 넣어서 HTTP BASIC AUTH등 인증 방식을 추가하는 방법
Google Cloud Identity Aware Proxy를 이용하여, 구글 클라우드 계정 사용자에게 접근 권한을 부여 하는 방법
해당 HTTP 포트를 SSH로 터널링 하는 방법
1번 방법은 IP 가 바뀌면 접근 제어 하기가 번거로우니 패스, 2번은 웹서버 깔아야 하니 패스, 3번은 제일 좋은 방법인데, 로드밸런서등 구체적인 설정을 해야 해서 패스. 그래서 오늘은 가장 간단한 4번 방법을 설명한다.
4번 방법은 로컬에서 localhost:2222를 접속하면 구글 클라우드 상의 인스턴스:8080 으로 포워딩을 해준다. 이때 프로토콜을 SSH를 통해서 터널링이 된다.
매우 간단하게 할 수 있는데, 로컬에 gcloud SDK가 깔려 있을때
gcloud compute ssh {인스턴스명} --project {내프로젝트ID} --zone {인스턴스가 있는 존 이름} --ssh-flag="-L" --ssh-flag="{랩탑에서 접속할 포트번호}:localhost:{인스턴스의 포트 번호}"
로 기입해주면 된다.
예를 들어 terrycho-ml 프로젝트의 us-central1-f 존에 있는 hello-airflow 인스턴스의 8080 포트를 로컬에서 localhost:2222로 접근하도록 포워딩 설정을 할 경우 다음과 같이 하면 된다.
구글 클라우드 펑션은 서버리스 아키텍쳐를 구현하기 위한 구글 클라우드 서비스이다. 아마존 웹서비스의 람다와 같은 기능이라고 보면 된다.
이벤트가 발생하면, 이벤트에 따라서, 코드를 수행해주는 형태인데, 이벤트의 종류는 다음과 같다.
Pub/Sub 메세지 큐에서 들어오는 메세지
Firebase 모바일 SDK에 의해서 발생되는 이벤트
Google Cloud Storage 서비스에 의해서 파일이 생성,수정,삭데 되었을때
마지막으로 HTTP로 들어오는 요청 (REST API)
개발환경
프로그래밍 언어는 node.js 6.9.1 버전을 기반으로 되어 있으며, node.js의 package.json을 이용하여 왠만한 의존성 모듈은 설치가 가능하다. (node.js express 등) 개발을 위해서는 로컬에 에뮬레이터를 설치하여 개발이 가능하다. https://cloud.google.com/functions/docs/emulator
Hello World
그러면 간단하게, 구글 클라우드 펑션을 사용해보자
클라우드 펑션은 크게 두가지 타입의 펑션이 있는데
HTTP 펑션 HTTP 펑션은 HTTP 로 입력을 받는 형태로 function 펑션이름(req,res) req는 HTTP Request, res는 HTTP Response 이다.
백그라운드 펑션 백르라운드 펑션은 GCS,Pub/Sub 등의 이벤트로 트리거링 되는 펑션으로 function 펑션이름(event,callback)형태로 정의된다. event 객체 안에, GCS나 Pub/Sub 에서 발생된 이벤트 정보가 전송된다.
간단하게 웹에서 Hello World를 출력하는 펑션을 개발해보자.
예제 코드
Index.js 에 다음과 같은 코드를 작성한다
exports.helloworld = function helloworld (req, res) {
switch(req.method){
case 'GET':
res.send('Hello world');
}
};
위의 코드는 helloworld 라는 이름의 펑션으로 HTTP GET 요청이 들어왔을때, ‘Hello world’ 문자열을 출력하도록 하는 펑션이다.
배포 하기
배포는 크게 Web UI와 CLI (Command Line Interface) 두 가지로 할 수 있다.
배포에 앞서서, 먼저 GCS (Google Cloud Storage) 버킷을 생성해야 한다. 클라우드 펑션은 배포 코드를 클라우드 스토리지 버킷에 저장해놓고 (스테이징 용도) 배포하기 때문이다.
클라우드 스토리지 버킷은 Web UI에서도 생성할 수 있지만 간단하게 CLI 명령을 이용해서 다음과 “terrycho-cloudfunction”이라는 이름의 버킷을 생성한다
%gsutil mb gs://terrycho-cloudfunction
Command Line Interface (CLI)로 배포하기
CLI로 배포하기 위해서는 CLI 명령인 gcloud 명령을 업그레이드 해야 한다. 다음 명령을 수행하면 쉽게 업그레이드할 수 있다.
앞에서 만든 펑션은 us-central1에 배포하였고, 프로젝트명은 terrycho-sandbox이고 펑션 이름은 helloworld 이기 때문에 URL과 실행 결과는 다음과 같다
모니터링
모니터링은 CLI와 웹콘솔 양쪽으로 모두 가능하지만 웹 콘솔에서 로그를 확인해보겠다. 펑션 화면에서 펑션을 선택한 후에 우측 메뉴에서 아래 그림과 같이 “See logs”를 누룬다.
로그를 확인해보면 다음과 같다.
펑션이 시작된 것을 확인할 수 있다. 7d로 시작하는 펑션과 de로 시작하는 펑션 인스턴스 두개가 생성된 것을 볼 수 있고 7d로 시작된 펑션의 실행 시간이 702 ms가 걸린것을 확인할 수 있다.
가격 정책
가격 정책 계산 방법은
(가격) = (호출 횟수) + (컴퓨팅 자원 사용량 ) + (네트워크 비용)
으로 구성된다.
호출 횟수는 클라우드 펑션이 호출되는 횟수로 한달에 2백만건까지 무료이며 2백만건 이후로는 백만건당 0.4$ 가 부과 된다.
컴퓨팅 자원은 사용한 메모리와 CPU 파워를 기반으로 100ms 단위 과금이다.
예를 들어 1.4GHz CPU 1024MB 메모리를 250 ms 사용했다면, 컴퓨팅 자원 사용 비용은 0.000001650 * 3 (250ms는 올림하여 300ms로 계산한다.)
네트워크 비용은 들어오는 비용은 무료이며 인터넷으로 나가는 비용에 대해서만 월 5$를 부과한다.
무료 티어
무료 티어는 매달 2백만콜에 대해서 400,000GB 초, 200,000GHZ 초의 용량 + 5GB 아웃바운드 트래픽에 대해서 무료로 제공한다
결론
사실 클라우드 펑션과 같은 서버리스 서비스는 새로운 기술은 아니다.
그러나 구글 클라우드 플랫폼과 연계되어서, 간단한 HTTP 서비스 개발은 물론, GCS에 저장된 파일에 대한 ETL 처리등 다양한 분야에 사용이 가능하며
특히나 타 클라우드 대비 특징은, 모바일 SDK 파이어베이스의 백앤드로 연동이 가능하기 때문에 모바일 개발자 입장에서 복잡한 API 인증등을 개발할 필요 없이 간단하게 서버 백앤드를 개발할 수 있다는 장점을 가지고 있기 때문에 개발 생산성 향상에 많은 도움이 되리라고 본다.
https://cloud.google.com/logging/quota-policy 를 보면 스택드라이버 로깅에 쿼타 제한이 초당 500건/계정으로 잡혀있어서. 일반적인 경우는 최대 500 TPS의 성능을 낼 수 있습니다. 그 이상의 성능이 필요하면, 여러 계정을 사용해야 합니다 또는 구글에 별도의 쿼타 증설 요청을 해야 합니다.
하루에, 최대 2천5백만건의 로그를 하나의 프로젝트를 통해서 수집이 가능합니다.
또한 프리티어의 경우에는 한달에 로그를 5GB 까지 수집이 가능한데, 이게 넘으면 로그가 더이상 수집되지 않습니다. 그래서 아래 내용 처럼 빅쿼리로 Export를 해서 로그가 5GB 이상 스택드라이버에 저장되지 않도록 해야 합니다. (차기전에 데이타를 퍼나르는)
애플리케이션 로그 이외에도, VM 로그등도 이 5GB의 용량을 공유하기 때문에, VM 로그등도 차기전에 GCS로 퍼 나르거나 또는 구글 Support 티켓을 통하여 애플리케이션 로그 이외의 로그를 수집하지 않도록 별도 요청해야 합니다. (로그 저장 용량에 대해서 비용을 지불하면, 이런 제약은 없음)
백앤드 시스템에서 중요한 컴포넌트중의 하나가, 클라이언트로 부터 로그를 수집 및 분석하는 시스템이다.
오늘 설명할 내용은 500 TPS (Transaction Per Sec)가 넘는 대용량 로그 수집 및 분석 시스템을 managed 서비스를 이용하여, 쉽고 빠르게 구축할 수 있는 방법에 대해서 소개하고자한다.
일반적인 로그 수집 및 분석 시스템 아키텍쳐
일반적으로 클라이언트에서 로그를 수집하여 분석 및 리포팅 하는 시스템의 구조는 다음과 같다.
앞단의 API 서버가 로그를 클라이언트로 부터 수집하고 데이타를 정재한다.
로그 저장소가 순간적으로 많은 트래픽을 감당할 수 없는 경우가 많기 때문에, 중간에 Message Q를 넣어서, 들어오는 로그를 Message Q에 저장하여 완충을 한다.
이 Message Q로 부터 로그를 Message Consumer가 순차적으로 읽어서 Log Storage에 저장한다.
저장된 로그는 Reporting 툴을 이용하여 시각화 한다.
이런 구조 이외에도 API 서버에서 파일로 로그를 저장한 후, Fluentd나, LogStash 등의 로그 수집기를 이용하는 방법등 다양한 아키텍쳐가 존재한다.
이런 시스템을 구축하기 위한 일반적인 솔루션들은 다음과 같다.
컴포넌트
솔루션
API 서버
node.js, ruby, php 등 일반적인 웹서버
Message Q
Rabbit MQ와 같은 일반적인 큐 Kafaka 와 같은 대량 큐
AWS SQS나 구글 Pub/Sub 같은 클라우드 큐
Message Consumer
Multi Thread(or Process) + Timer를 조합하여 메세지를 폴링 방식으로 읽어오는 애플리케이션 개발
Log Storage
Hadoop, HBase 와 같은 하둡 제품
Drill,Druid와 같은 SQL 기반 빅데이타 플랫폼
Elastic Search
Reporting
Zeppeline, Jupyter 와 같은 노트북류
Kibana
구조나 개념상으로는 그리 복잡한 시스템은 아니지만, 저러한 솔루션을 모두 배우고, 설치하고 운영하는데 시간이 들고, 각각의 컴포넌트를 구현해야하기 때문에 꽤나 시간이 걸리는 작업이다.
그러면 이러한 로그 수집 및 분석 작업을 클라우드 서비스를 이용하여 단순화 할 수 없을까?
스택 드라이버
스택 드라이버는 구글 클라우드의 모니터링, 로깅 및 애플리케이션 성능 분석등 모니터링 분야에서 다양한 기능을 제공하는 서비스 이다.
그중에서 스택드라이버 로깅은 구글 클라우드나 아마존 또는 기타 인프라에 대한 모니터링과, Apache, MySQL과 같은 써드 파티 미들웨어에 대한 로그 수집 및 모니터링을 지원하는데, 이 외에도, 사용자가 애플리케이션에서 로깅한 데이타를 수집하여 모니터링할 수 있다.
스택 드라이버 로깅의 재미있는 기능중 하나는 로그 EXPORT 기능인데, 로그 데이타를 구글 클라우드 내의 다른 서비스로 로그 데이타를 내보낼 수 있다.
GCS (Google Cloud Storage)로 주기적으로 파일로 로그 데이타를 내보내거나
Pub/Sub이나 Big Query로 실시간으로 데이타를 내보낼 수 있다.
그렇다면 스택 드라이버를 통해서 빅쿼리에 로그 데이타를 직접 저장한다면 복잡한 Message Q나, Message Consumer 등의 구현도 불필요하고, 로그 저장도 복잡한 오픈 소스를 이용한 개발이나 운영도 필요 없이, 매니지드 서비스인 빅쿼리를 이용하여 간략하게 구현할 수 있다.
스택 드라이버 로깅을 이용한 로그 수집 시스템 구현
스택 드라이버 애플리케이셔 로깅 기능을 이용하여 클라이언트로 부터 로그를 수집하여 분석하는 시스템의 아키텍쳐를 그려 보면 다음과 같다.
API 서버를 이용하여 클라이언트로 부터 로그를 수집하고, API 서버는 스택 드라이버 로깅 서비스로 로그를 보낸다. 스택 드라이버 로깅은 Export 기능을 이용하여, 수집된 로그를 실시간으로 빅쿼리로 전송한다. 빅쿼리에 저장된 로그는 구글 데이타 스튜디오 (http://datastudio.google.com)이나 제플린, 파이썬 주피터 노트북과 같은 리포팅 도구에 의해서 시각화 리포팅이 된다.
API 서버쪽에서 스택 드라이버 로깅으로 로그를 보내는 부분을 살펴보자
아래는 파이썬 Flask 를 이용하여 로그를 스택 드라이버로 보내는 코드이다.
import uuid
from flask import Flask
from google.cloud import logging
app = Flask(__name__)
logging_client = logging.Client()
tlogger = logging_client.logger(‘my-flask-log’)
slogger = logging_client.logger('struct_log')
@app.route('/')
def text_log():
logstring = "This is random log "+ str(uuid.uuid4())
tlogger.log_text(logstring)
return logstring
@app.route('/slog')
def struct_log():
struct = "This is struct log "+ str(uuid.uuid4())
slogger.log_struct({
'name':'myterry',
'text':struct,
'key' : 'mykey'})
return struct
if __name__ == '__main__':
app.run('0.0.0.0',7001)
google.cloud 패키지에서 logging 모듈을 임포트한 다음에, 로깅 클라이언트로 부터
tlogger = logging_client.logger(‘my-flask-log’)
slogger = logging_client.logger('struct_log')
로 각각 “my-flask-log”와 “struct_log”라는 이름을 가지는 logger 둘을 생성한다.
(뒤에서 언급하겠지만, 이 로거 단위로, 로그를 필터링 하거나, 또는 이 로거 단위로 로그 메세지를 다른 시스템으로 export 할 수 있다.)
다음, 로그를 쓸 때는 이 logger를 이용하여 로그를 써주기만 하면 된다.
tlogger.log_text(logstring)
는 텍스트로 된 한줄 로그를 쓰는 명령이고,
slogger.log_struct({
'name':'myterry',
'text':struct,
'key' : 'mykey'})
는 JSON과 같이 구조화된 계층 구조를 로그로 쓰는 방식이다.
이렇게 개발된 로그 수집용 API 서버의 코드는 직접 VM을 만들어서 Flask 서버를 깔고 인스톨 해도 되지만 앱앤진을 사용하면 코드만 배포하면, Flask 서버의 관리, 배포 및 롤백, 그리고 오토 스케일링등 모든 관리를 자동으로 해준다. 앱앤진을 이용한 코드 배포 및 관리에 대한 부분은 다음 문서 http://bcho.tistory.com/1125 를 참고 하기 바란다.
스택 드라이버에서 로그 확인
코드가 배포되고, 실제로 로그를 기록하기 시작했다면 스택 드라이버에 로그가 제대로 전달 및 저장되었는지 확인해보자. 구글 클라우드 콘솔에서 스택 드라이버 로깅으로 이동한 다음 아래 그림과 같이 리소스를 “Global” 을 선택한 후, 앞에 애플리케이션에서 남긴 “my-flask-log”와 “struct-log” 만을 선택해서 살펴보자
다음과 같이 로그가 출력되는 것을 확인할 수 있으며, struct_log의 예를 보면 로그의 내용은 time_stamp 와 프로젝트 정보와 같은 부가 정보와 함께, 애플리케이션에서 남긴 로그는 “jsonPayload” 앨리먼트 아래에 저장된것을 확인할 수 있다.
빅쿼리로 Export 하기
스택 드라이버로 로그가 전달되는 것을 확인했으면, 이 로그를 빅쿼리에 저장해보자. Export 기능을 이용해서 가능한다. 아래와 같이 스택 드라이버 로깅 화면에서 상단의 “CREATE EXPORT” 버튼을 누른다.
다음 리소스 (Global)과 로그 (struct_log)를 선택한 다음에,
Sink Name에 Export 이름을 적고 Sink Service는 BigQuery를 선택한다. 다음으로 Sink Destination에는 이 로그를 저장할 Big Query의 DataSet 이름을 넣는다.
마지막으로 Create Sink를 누르면, 이 로그는 이제부터 실시간으로 BigQuery의 structlog라는 데이타셋에 저장이 되면 테이블명은 아래 그림과 같이 strcut_log_YYYYMMDD와 같은 형태의 테이블로 생성이 된다.
테이블 프리뷰 기능을 이용하여 데이타가 제대로 들어갔는지 확인해보자. 아래와 같이 위의 코드에서 저장한 name,key,text는 테이블에서 jsonPayload.name, jsonPayload.key, jsonPayload.text 라는 필드로 각각 저장이 되게 된다.
빅쿼리는 실시간으로 데이타를 저장할때는 초당 100,000건까지 지원이 가능하기 때문에 이 시스템은 100,000TPS 까지 지원이 가능하고, 만약에 그 이상의 성능이 필요할때는 로그 테이블을 나누면(Sharding) 그 테이블 수 * 100,000 TPS까지 성능을 올릴 수 있다. 즉, 일별 테이블을 10개로 Sharding 하면, 초당 최대 1,000,000 TPS를 받는 로그 서비스를 만들 수 있으며, 이 테이블 Sharding은 빅쿼리 테이블 템플릿을 사용하면 쉽게 설정이 가능하다. (정정 빅쿼리는 100K TPS를 지원하나, 스택 드라이버가 500 TPS로 성능을 제한하고 있음)
이렇게 간단하게, 코드 몇줄과 설정 몇 가지로 100,000 500 TPS 를 지원하는 로그 서버를 만들어 보았다.
스택 드라이버를 이용한 로그 분석 수집 시스템의 확장
이 외에도 스택 드라이버는 빅쿼리뿐 아니라 다른 시스템으로의 연동과 매트릭에 대한 모니터링 기능을 가지고 있어서 다양한 확장이 가능한데, 몇가지 흥미로운 기능에 대해서 살펴보도록 하자.
실시간 스트리밍 분석 및 이벤트 핸들링
스택 드라이버 로깅의 Export 기능은, 하나의 로그를 여러 연동 시스템으로 Export를 할 수 있다. 앞에서는 빅쿼리로 로그를 Export 하였지만, 같은 Log를 Dataflow에 Export 하였을 경우, 로그 데이타를 실시간 스트림으로 받아서, 실시간 스트리밍 분석이 가능하다.
또는 실시간 스트리밍이 아니라, 로그 메세지 하나하나를 받아서 이벤트로 처리하고자 할 경우, Pub/Sub 큐에 넣은 후에, 그 뒤에 GAE또는 Cloud function (https://cloud.google.com/functions/) 에서 메세지를 받는 구조로 구현이 가능하다.
앞에서 스택 드라이버 로깅을 이용한 로그 수집 시스템을 만드는 방법을 알아보았지만, 부가적인 몇가지 기능이 같이 제공되는데 다음과 같다.
필터를 이용한 특정 로그 핸들링
logger를 통해서 수집된 로그에는 필터를 걸어서 특정 로그만 모니터링할 수 있다.
예를 들어서 text 문자열에 “error” 가 들어간 로그나, latency가 1초이상인 로그와 같이 특정 로그만을 볼 수 있다.
다음은 jsonPayload.text 로그 문자열에 “-a”로 시작하는 문자열이 있는 로그만 출력하도록 하는 것이다.
이 기능을 사용하면, 로그 메세지에서 특정 로그만 쉽게 검색하거나, 특정 에러 또는 특정 사용자의 에러, 특정 ErrorID 등으로 손쉽게 검색이 가능해서 로그 추적이 용이해진다.
매트릭 모니터링
다음은 메트릭이라는 기능인데, 로그를 가지고 모니터링 지표를 만들 수 있다.
예를 들어 하루 발생한 에러의 수 라던지, 평균 응답 시간등의 지표를 정의할 수 있다.
이렇게 정의된 지표는 대쉬보드에서 모니터링이 가능하고 또는 이러한 지표를 이용하여 이벤트로 사용할 수 있다. 응답시간이 얼마 이상 떨어지면 오토 스케일링을 하게 한다던가 또는 이메일로 관리자에게 ALERT을 보낸다던가의 기능 정의가 가능하다.
매트릭 생성
지표 정의는 로그 화면에서 필터에 로그 검색 조건을 넣은 채로, CREATE METRIC 버튼을 누르면 사용자가 지표를 매트릭으로 정의할 수 있다.
대쉬 보드 생성
이렇게 정의된 매트릭은 스택 드라이버 대쉬 보드 화면에서 불러다가 그래프로 시각화가 가능한데, 다음 그림은 struct_log의 전체 수와를 나타내는 매트릭과, struct_log에서 log text에 “-a”를 포함하는 로그의 수를 나타내는 메트릭을 정의하여 차트로 그리는 설정이다.
위에 의해서 생성된 차트를 보면 다음과 같이 전체 로그 수 대비 “-a” 문자열이 들어간 로그의 수를 볼 수 있다.
지금까지 스택드라이버 로깅과 빅쿼리를 이용하여 간단하게 대용량 로그 수집 서버를 만드는 방법을 살펴보았다. 두개의 제품을 이용해서 로그 수집 시스템을 구현하는 방법도 중요하지만, 이제는 개발의 방향이 이러한 대용량 시스템을 구현하는데, 클라우드 서비스를 이용하면 매우 짧은 시간내에 개발이 가능하고 저비용으로 운영이 가능하다. 요즘 개발의 트랜드를 보면 이렇게 클라우드 서비스를 이용하여 개발과 운영 노력을 최소화하고 빠른 개발 스피드로 개발을 하면서, 실제로 비지니스에 필요한 기능 개발 및 특히 데이타 분석 쪽에 많이 집중을 하는 모습이 보인다.
단순히 로그 수집 시스템의 하나의 레퍼런스 아키텍쳐에 대한 이해 관점 보다는 전체적인 개발 트렌드의 변화 측면에서 한번 더 생각할 수 있는 계기가 되면 좋겠다.
빅쿼리에서 count(distinct) 문을 사용하면, 종종 값이 부 정확하게 나오는 경우가 있다.
예를 들어서 아래의 두 쿼리는 같은 결과가 나와야 하는데, 아래 count(distinct id)를 쓴 쿼리는 다른 값을 리턴한다.
select count(*)
where id="mykey"
from mytable
select count(distinct id)
where id="mykey"
from mytable
빅쿼리에는 쿼리가 빅쿼리에 최적화된 SQL과 유사한 Legacy SQL 쿼리가 있고, ANSI SQL을 따르는 스탠다드 쿼리가 있다.
Legacy SQL 쿼리의 경우 확인해보니, 동작 방식이 다소 상이한 부분이 있다.
COUNT([DISTINCT]field[,n])
Returns the total number of non-NULL values in the scope of the function.
If you use theDISTINCTkeyword, the function returns the number ofdistinctvalues for the specified field. Note that the returned value forDISTINCTis a statistical approximation and is not guaranteed to be exact.
Count(distinct) 함수의 경우 리턴 값이 1000이 넘을 경우에는 성능 향상을 위해서 정확한 값을 리턴하지 않고, 근사치 값 (approximation)을 리턴하도록 되어 있습니다. 그래서 상이한 결과가 나온다.
count(distinct platformadid,10000) 으로 하게 되면 리턴값이 10000을 넘을 경우에만 근사치 값을 리턴하게 됩니다. 즉 리턴값이 10000 이하이면 정확한 값을 리턴한다.
만약에 Legacy SQL에서 근사치 값이 아닌 정확한 값을 리턴 받으려면 count(distinct)
EXACT_COUNT_DISTINCT(field)
Returns the exact number of non-NULL, distinct values for the specified field. For better scalability and performance, useCOUNT(DISTINCTfield).
함수를 사용하시는 방법이 있고, 아니면 Legacy SQL 의 특성에 의한 오류를 방지하시려면 쿼리를 ANSI SQL 모드로 실행하시면 됩니다.
ANSI SQL 모드로 수행하는 방법은 아래와 같이 "Use Legacy SQL" Box를 unchecking 하시고, 테이블 이름을 []로 감싸지 마시고 ``로 감싸서 사용하시면 된다.
오늘 도커 밋업에서 Kubernetes 발표가 있어서, 발표전에 데모를 준비하다 보니, 구글 클라우드의 Kubernetes 서비스인 GKE (Google Container Engine)에서 Kubernetes UI를 지원하는 것을 확인했다.
Google Container Service (GKE)
GKE는 구글 클라우드의 도커 클라우드 서비스이다. 도커 컨테이너를 관리해주는 서비스로는 Apache mesos, Docker Swarm 그리고 구글의 Kuberenetes 가 있는데, GKE는 이 Kuberentes 기반의 클라우드 컨테이너 서비스이다.
대부분의 이런 컨테이너 관리 서비스는 아직 개발중으로 운영에 적용하기에는 많은 부가적인 기능이 필요한데, 사용자 계정 인증이나, 로깅등이 필요하기 때문에, 운영환경에 적용하기는 아직 쉽지 않은데, GKE 서비스는 운영 환경에서 도커 서비스를 할 수 있도록 충분한 완성도를 제공한다. 이미 Pocketmon go 서비스도 이미 GKE를 사용하고 있다.
Kubernetes UI
예전에 Kubernetes를 테스트할 때 단점은 아직 모든 관리와 모니터링을 대부분 CLI로 해야 하기 때문에 사용성이 떨어지는데, 이번 GKE에서는 웹 UI 콘솔을 제공한다.
구글 GKE 콘솔에서 Kuberentes 클러스터를 선택하며 우측에 Connect 버튼이 나오는데,
이 버튼을 누르면, Kubernetes 웹 UI를 띄울 수 있는 명령어가 출력된다.
아래와 같이 나온 명령어를 커맨드 창에서 실행시키고 htt://localhost:8001/ui 에 접속하면 Kubernetes 웹 콘솔을 볼 수 있다.
Kubernetes 의 웹콘솔은 다음과 같은 모양이다.
Kubernetes의 주요 컴포넌트인 Pods, Service, Replication Controller , Nodes 등의 상태 모니터링은 물론이고, 배포 역시 이 웹 콘솔에서 가능하다.
예를 들어 gcr.io/terrycho-sandbox/hello-node:v1 컨테이너 이미지를 가지고, Pod 를 생성하고, Service를 정의해서 배포를 하려면 다음과 같은 명령을 이용해야 한다.
1. hello-node 라는 pod를 생성한다.
% kubectl run hello-node --image=gcr.io/terrycho-sandbox/hello-node:v1 --port=8080
배포가 완료된 후에는 각 Pod의 상황이나, Pod를 호스팅하고 있는 Nodes 들의 상황등 다양한 정보를 매우 쉽게 모니터링이 가능하다. (cf. CLI를 이용할 경우 CLI 명령어를 잘 알아야 가능하다.)
GKE에 대한 튜토리얼은 https://cloud.google.com/container-engine/docs/tutorials 에 있는데,
추천하는 튜토리얼은
가장 간단한 튜토리얼 node.js 웹앱을 배포하는 http://kubernetes.io/docs/hellonode/
와 WordPress와 MySQL을 배포하는 https://cloud.google.com/container-engine/docs/tutorials/persistent-disk/
을 추천한다.
도커가 아직까지 운영 환경에 사례가 국내에 많지 않고, GKE도 GUI 가 없어서 그다지 지켜보지 않았는데, 다시 파볼만한 정도의 완성도가 된듯.
참고로 테스트를 해보니 VM을 3개 만들어놓고 컨테이너를 7개인가 배포했는데, VM은 3개로 유지된다. 즉 하나의 VM에 여러개의 컨테이너가 배포되는 형태인데, 작은 서비스들이 많은 경우에는 자원 사용 효율이 좋을듯. 이런 관점에서 봤는때는 VM 기반의 서비스보다 컨테이너 서비스를 쓰는 장점이 확실히 보이는듯 하다
일반적으로 모바일 로그 분석은 클라우드 기반의 무료 솔루션을 이용하다가 자체 구축으로 가는 경우가 많다.
클라우드 기반의 무료 로그 분석 솔루션으로는 구글 애널러틱스, 야후의 플러리, 트위터의 패브릭 그리고 구글의 파이어베이스 등이 있다.
이런 무료 로그 분석 솔루션들을 사용이 매우 간편하고, 핵심 지표를 쉽게 뽑아 줄 수 있으며, 별도의 운영이 필요 없다는 장점을 가지고 있다.
그러나 이런 클라우드 기반의 무료 솔루션의 경우에는 요약된 정보들만 볼 수 있고 또한 내가 원하는 지표를 마음대로 지정을 할 수 없기 때문에, 어느정도 서비스가 성장하고 팀의 여력이 되면 별도의 로그 수집 및 분석 솔루션을 만드는 것이 일반적이다.
오픈 소스 기반의 분석 솔루션
오픈 소스를 조합해서 모바일 로그 수집 시스템을 만들면 대략 다음과 같은 모양이 된다.
API 서버에서 로그를 수집해서 카프카등의 큐를 통해서 로그를 모으고, 실시간은 스파크 스트리밍, 배치는 하둡이나 스파크 스트리밍 프레임웍을 이용합니다. 대쉬 보드는 만드는 곳도 있지만, 주피터 노트북이나 제플린 노트북과 같은 노트북을 이용한다.
요즘은 데이타 저장 및 분석에 ELK (Elastic Search + Logstash + Kibana)와 같은 솔루션도 많이 사용하고 있다.
그런데 이런 오픈 소스 솔루션 기반으로 로그 분석 시스템을 개발하면 몇가지 문제가 발생한다.
개발에 드는 노력 이런 오픈소스 스택으로 시스템을 개발하려면, 이 프레임웍에 대해서 잘 아는 전문가가 필요합다. 일반적인 스타트업에서는 구하기도 힘들고, 기업이 어느정도 규모가 되더라도 빅데이타 관련 기술을 다룰 줄 아는 엔지니어는 여전히 귀한 엔지니어이고, 이런 엔지니어들이 있다하더라도, 시스템 설계및 구현에는 수개월의 기간이 소요 되게 된다.
시스템 구매와 운영 다음 문제는 모바일 데이타는 양이 많기 때문에, 위에서 언급한 빅데이타 관련 오픈 소스를 사용하게 되는데, 이러한 시스템은 하드웨어 자원이 수십에서 수백대가 필요하거니와, 이를 설치하고 운영하는 것 역시 쉽지 않다. 로그를 수집하고 분석하는 로직을 만들어야 하는 엔지니어들이 정작 데이타 분석 보다는 시스템 운영과 유지보수에 많은 시간을 낭비해야 한다는 문제가 발생한다. 규모가 작은 스타트업이나 엔지니어링 능력이 되지 않는 기업들은 이런 빅데이타 분석은 엄두도 내지 못하는 상황이 되고, 디테일한 데이타 분석을 하지 못하게 되니 자연히 경쟁력이 떨어지게 될 수 있다.
연산 시간 그리고 수집 수백대의 서버를 가지고 있다하더라도, 데이타 연산 시간은 수십분에서 수시간이 소요된다. 특히 데이타 분석 서버들이 분석을 하고 있을때는 다른 분석을 하고 싶은 사람들은 연산이 끝날때 까지 기다려야 하고, 수시간을 들여서 연산한 결과라도 연산이 잘못되었으면 다시 로직을 수정해서 수시간 동안 다시 연산을 해야 한다. 비지니스 조직 입장에서는 지표 분석 결과를 얻는데, 수시간이 걸리니 의사 결정의 민첩성이 떨어지게 된다.
클라우드 기반의 분석 솔루션
근래에 이런 빅데이타 분석이 클라우드 컴퓨팅 기술과 만나면서 한번의 큰 변화를 겪게 되는데, 흔히들 빅데이타의 민주화라고 이야기 한다. 빅데이타 분석이 클라우드 컴퓨팅과 만나면서 겪은 큰 변화는 다음과 같다 .
클라우드 스케일의 연산
먼저 스케일이 달라집니다. 클라우드의 대용량 자원을 이용하여, 연산을 하기 때문에, 훨씬 더 빠른 연산을 저 비용에 할 수 있다.
예를 들어 구글의 빅쿼리의 경우에는 1000억개의 문자열(ROW)를 Regular expression을 이용하여 스트링 Like 검색을 하고 이를 group by 로 그룹핑하여 연산 하는 쿼리를 수행할때
“8600개의 CPU, 3600개의 디스크, 350GB의 네트워크 대역폭"
이 사용이 되고, 쿼리 수행 시간은 약 20~30초, 클라우드 사용 비용은 20$ (2만원) 정도가 소요 된다.
오픈 소스 기반으로 왠만한 규모로는 동시에 단일 연산으로 이렇게 수천개의 CPU를 같이 돌릴 수 있는 인프라를 사내에 가지고 있기도 힘들뿐 더러, 이만한 리소스를 20$라는 저렴한 비용에 사용하기란 거의 불가능에 가깝다.
이런 빠른 연산으로 인해서, 현업에서는 연산 결과를 기다리지 않고 바로바로 볼 수 있고, 비용 역시 저렴하기 때문에, 어느정도 자금력과 개발력이 있는 기업이 아니더라도 고성능의 빅데이타 분석 시스템 구현이 가능하게 된다.
NoOPS
다음 장점으로는 운영이 필요 없다는 것인데, 앞에서도 설명했듯이, 오픈 소스를 이용해서 빅데이타 분석 시스템을 직접 구축한 경우에는 시스템 인스톨과, 구성, 그리고 운영에 많은 시간이 소요 되는데, 클라우드 기반의 빅데이타 솔루션은 설정과 운영을 클라우드 서비스 제공자가 대행을 하기 때문에, 엔지니어링 팀은 별도의 설정과 유지보수 없이 본연의 역할인 데이타 분석에만 집중할 수 있게 된다. (아마 직접 하둡이나 스파크 클러스터를 운영해본 사람이라면 이 의미를 잘 이해하리라 본다.)
이렇게 클라우드가 빅데이타 영역에 도입되면서 이제는 빅데이타 분석이 뛰어난 엔지니어링 지식과 자금력이 없더라도 단시간내에 저비용으로 효율적인 데이타 분석이 가능하게 되었기 때문에, 이를 빅데이타의 민주화라고 부른다.
파이어베이스 애널러틱스
파이어베이스는 얼마전에 구글이 인수해서 클라우드 서비스 형태로 제공하고 있는 통합 모바일 개발 프레임웍이다. 웹은 지원하지 않고 모바일만 지원하는 형태의 프레임웍이며, 리얼타임 데이타 베이스, 광고 네트워크 통합, 푸쉬 서비스, 사용자 개인 인증 서비스등 여러가지 기능을 가지고 있는데, 그 중에서, 파이어베이스 애널러틱스는 모바일 빅데이타 분석에 최적화된 시스템이다.
빅쿼리와 파이어베이스의 조합
게임 체인저
파이어베이스는 모바일 데이타 분석에서 거의 게임 체인저라고 할만한 기술인데, 기존의 클라우드 기반의 모바일 데이타 분석 솔루션은 가장 큰 문제점이, 개발자가 정의한 로그 이벤트 (커스텀 로그)를 수집할 수 없다는 문제와 그리고 수집한 원본 데이타를 볼 수 없기 때문에, 원하는 지표를 마음대로 수집하고 분석하는 것이 불가능했다.
그런데 파이어베이스 애널러틱스는 이 두가지 기능을 지원하기 시작하였다.
커스텀 이벤트 정의를 통해서 개발자가 원하는 로그를 손쉽게 정의해서 수집이 가능하고, 또한 수집한 로그는 모두 구글의 빅데이타 저장 및 분석 플랫폼인 빅쿼리에 저장되고 바로 분석이 가능하다.
빅쿼리
파이어베이스 애널러틱스의 데이타는 빅쿼리에 저장이 되는데, 앞에서 예를 든것과 같이, 빅쿼리는 한번 연산에 수천개의 CPU와 디스크를 사용하여, 하둡이나 스파크에서 수시간이 걸리는 연산을 불과 수십초만에 처리가 가능하다.
빅쿼리의 또 다른 장점중의 하나는 이런 연산 속도 뿐만 아니라 RDBMS와는 다르게 JSON과 같이 트리형 (계층 구조를 가지는) 데이타형을 그대로 저장하고 쿼리가 가능하다는 것이다.
파이어베이스 애널러틱스는 뒤로는 빅쿼리 연동을 통해서 모든 원본 데이타의 수집과 분석을 지원하고 앞으로는 파이어베이스 에이전트를 모바일 디바이스에 탑재 하는 방식으로 최소한의 코드 개발로 모바일 앱으로 부터 모든 데이타를 수집할 수 있다. 파이어베이스 애널러틱스는 안드로이드와 iOS 플랫폼을 지원한다.
게임 프레임웍 지원
반가운 소식중의 하나는 파이어베이스 애널러틱스가 이제 유니티3D나, 언리얼(C++) 과 같은 게임 엔진을 지원한다. 현재 두 플랫폼에 대한 지원은 베타로 공개되어 있다.
기본적으로 gradle 빌드 스크립트에 파이어베이스 애널러틱스 모듈을 import 하고, FirebaseAnalytics 객체만 선언해주면 기본적인 사용자 로그 (앱 실행, 종료등), 일일 방문자, 동시 접속자, 접속 디바이스 종류, 사용자 연령과 성별들을 모두 수집해준다.
빌드 스크립트 수정 및 소스코드에 한줄의 코드만 추가해주면 된다.
다음으로, 각각의 이벤트를 추가하고자 한다면, 위와 같이 Bundle 객체를 정의해서, 넘기고자 하는 인자를 정의해주고 logEvent라는 메서드를 호출해주면 파이어베이스로 로그가 전달된다.
유니티 3D 예제 코드
유니티 3D에서 파이어베이스에 로그를 남기는 것도 다르지 않다.
다음 코드를 보자
Firebase.Analytics.Parameter[] param = {
new Firebase.Analytics.Parameter("sessionid", sessionid),
new Firebase.Analytics.Parameter("score", (string)ApplicationModel.score.ToString())
Parameter라는 배열로, 파이어베이스에 남길 로그의 인자들을 정의한후에, LogEvent 메서드를 이용하여 이벤트 명과, 앞에서 정의된 인자들 (Parameter)를 남겨주면 로그는 자동으로 파이어베이스로 전달된다.
파이어베이스 애널러틱스를 이용한 모바일 데이타 분석
그러면 파이어베이스를 이용하여 모바일 로그 분석을 어떻게 할 수 있는지 알아보자. 마침 유니티 3D가 얼마전 부터 베타로 지원이 되기 때문에, 간단한 게임을 이용한 로그 수집을 설명한다.
샘플 게임 설명
샘플에 사용한 게임은 간단한 RPG 형태의 게임으로 다음과 같이 구성된다.
시작 화면
시작화면에서는 로그 분석을 위해서, 사용자의 나이와 성별을 입력 받는다.
게임 화면
다음 게임이 시작되면, 화면을 터치하여 토끼 캐릭터를 이동 시키고, 돼지를 클릭하면 돼지를 공격한다.
돼지를 공격할때 마다 데미지는 돼지의 종류에 따라 일정 값 범위내에서 랜덤으로 판정되고, 생명 값이 남아있지 않으면 돼지가 죽게 된다.
맵내에 돼지는 7개가 유지되도록 되어 있으며, 돼지가 줄면, 돼지는 하늘에서 부터 떨어지게 되어 있다.
게임은 120초 동안 진행되며, 120초가 지나면 자동으로 종료된다.
종료 화면
게임이 종료되면 점수를 표시한다.
데이타 분석 지표 디자인
그러면 이 게임으로 어떻게 데이타를 분석할것인지에 대해서 고민해보자.
일일 접속 사용자나 사용자에 대한 사용 시간,횟수등은 파이어베이스 애널러틱스에서 기본적으로 수집이 되기 때문에, 조금 더 의미 있는 데이타를 수집해보도록 한다.
캐릭터 이동 히트맵
이 예제에서 다소 중점을 둔 부분중의 하나는 캐릭터 이동 히트맵이다.
게임에서 난이도 조정등에 사용할 수 있는 정보중의 하나가 NPC 캐릭터의 이동 동선과, 플레이어 캐릭터의 이동 동선이다. 주로 플레이어가 죽는 위치를 데드존 (Dead zone)이라고 하면, 이 데드존 위치를 찾아낼 수 있고, 이 데드존에서 플레이어와 NPC의 타입,레벨 등을 조사하여 난이도를 조정한다거나, 또는 AI(인공지능) 플레이어 캐릭터의 경우에는 이동 동선을 추적함으로써 맵 내에서 AI가 원하는 데로 잘 움직이는지를 추적해볼 수 있다.
아래는 데드존을 기반으로 캐릭터와 NPC의 레벨을 분석해놓은 예제이다.
<그림. 게임맵상에서 데드존의 플레이어와 NPC 캐릭터간의 레벨 분석 >
아래는 흥미로운 분석중의 한예인데, 게임맵에서, 각 위치별로 자주 발생하는 채팅 메세지를 표시한 내용이다.
<그림. 게임맵상에서 자주 사용되는 채팅 메세지 분석>
그림 출처 : http://www.cs.cornell.edu/courses/cs4152/2013sp/sessions/15-GameAnalytics.pdf
이런 시스템 역시 쉽게 개발이 가능한데, 파이어베이스 애널러틱스를 이용하여 채팅 로그를 수집한 후, 자연어 분석 API를 이용하면, 명사와 형용사등을 추출하여 자주 오가는 말들을 통계를 낼 수 있다.
다음으로 일반적인 분석 시스템에서 수집되지 않는 커스텀 로그 분석 시나리오중 사용자 나이별 점수대를 분석해본다.
게임실행에서 종료까지 실행한 사용자
마지막으로 유용하게 사용되는 퍼널 분석의 예로 게임을 시작해서 종료할때까지의 도달율을 측정해봤다.
게임을 인스톨하고 시작한다음, 캐릭터를 움직이고, 캐릭터를 이용하여 공격을하고, 2분동안 플레이해서 게임을 종료한 사용자의 비율을 분석해본다.
로그 메세지 디자인
그러면 이러한 게임 로그를 분석하기 위해서 수집할 로그 메세지는 어떤 형태가 될지 디자인을 해보자.
로그 이벤트는 아래와 같이 7가지로 정의한다.
START_SESSION,END_SESSION 은 게임을 시작과 끝날때 발생하는 이벤트이다.
NPC_CREATE,NPC_MOVE,NPC_DIE 는 NPC(돼지)를 생성하고 이동하고, 그리고 죽었을때 각각 발생하는 이벤트이다. 이동은 이벤트의 수가 많기 때문에, 10초 단위로 수집하였다.
PLAYER_MOVE,PLAYER_ATTACK 은 플레이어 캐릭터의 이동과 NPC를 공격하는 이벤트를 수집한다.
각 이벤트를 플레이하는 판과 연결하기 위해서 각 플레이는 고유의 sessionid가 생성되서 게임이 시작될때부터 끝날때 까지 모든 이벤트에 저장된다.
Event name
Param
Key
Value
Type
Note
START_SESSION
This event is triggered when player press “START” button after submitting player’s age & gender
sessionid
Unique session Id for this play
String
age
Player’s age
String
sex
Player’s gender
String
true : man
false : woman
PLAYER_MOVE
It record location of player in game map periodically (every 2sec)
sessionid
Pos_X
Pox_Z
PLAYER_ATTACK
This event is occurred when player attack NPC.
sessionid
Unique session Id for this play
npc_id
Attacked NPC ID
type
Type of NPC
pos_X
NPC location X
pos_Z
NPC location Y
damage
Damage that NPC get in this attack
life
Left life for this NPC
NPC_CREATE
When new NPC is created, this event is logged.
sessionid
Unique session Id for this play
npc_id
Attacked NPC ID
type
Type of NPC
pos_X
NPC location X
pos_Y
NPC location Y
NPC_MOVE
Every 2sec for each NPC, it records the location of NPC.
sessionid
Unique session Id for this play
npc_id
Attacked NPC ID
type
Type of NPC
pos_X
NPC location X
pos_Y
NPC location Y
NPC_DIE
It is triggered when NPC is dead by attack
sessionid
Unique session Id for this play
npc_id
Attacked NPC ID
type
Type of NPC
pos_X
NPC location X
pos_Y
NPC location Y
END_SCENE
It is triggered when game stage(session) is over
sessionid
Unique session Id for this play
score
Score for this play
이렇게 정의된 로그는 파이어베이스 애널러틱스에 의해서 빅쿼리로 자동으로 저장되게 된다.
실시간 디버깅
이런 로깅을 삽입하면, 로그가 제대로 저장이 되는지 확인이 필요한데, 파이어베이스 애널러틱스는 특성상 로그 이벤트가 1000개가 쌓이거나 또는 컨버전 이벤트가 발생하거나 또는 1시간 주기로 로그를 서버에 전송하기 때문에 바로 올라오는 로그 메세지를 확인할 수 없다.
그래서 이번에 새로 소개되니 기능이 “DEBUG VIEW”라는 기능인데, 이 특정 디바이스에 디버깅 옵션을 지정하면, 실시간으로 올라오는 로그를 확인할 수 있다.
로그는 모바일앱에서 업로드한 후 약 10~20초 후에, 화면에 반영된다.
대쉬 보드를 이용한 지표 분석
대쉬 보드는 파이어 베이스 애널러틱스에서 기본으로 제공되는 지표로 모바일 서비스에 공통적으로 필요한 지표들을 분석하여 웹으로 출력해준다.
DAU/WAU/MAU 분석
가장 기본적인 지표로는 월간,주간,일간 방문자 수로를 그래프로 출력해준다.
평균 플레이 시간 분석
다음은 평균 플레이 시간으로, 사용자가 하루에 평균 얼마나 앱을 사용하였는지, 동시 접속자수 (Session)과, 한번 접속했을때 얼마나 오래 앱을 사용 하였는지 (Session duration)등을 분석하여 그래프로 출력해준다.
국가별 접속 내역 분석
다음은 국가별 접속 내용으로, 글로벌 서비스에는 필수로 필요한 분석 내용이다.
사용자 데모그래픽 정보 분석
사용자에 대한 데모 그래픽 정보 즉 성별과, 나이를 분석해주는데, 앱에 별도로 사용자 로그인 기능이 없거나, 사용자 정보를 추적하는 기능이 없더라도, 파이어베이스 애널러틱스는 여러군데에서 수집한 로그를 기반으로 사용자의 성별과 나이를 분석해 준다.
특정 이벤트에 대한 분석
다음은 특정 이벤트에 대한 분석이 가능하다. 게임에서 사용자가 스테이지를 넘어가는 이벤트등 파이어베이스에 정의된 이벤트 이외에도 사용자가 정의한 이벤트에 대한 분석이 가능하다.
또한 이벤트가 발생한 사용자에 대한 데모 그래픽 정보 (연령,성별,국가)를 같이 분석해서 해당 이벤트가 어떤 사용자 층에서 발생하였는지를 분석해 준다.
예를 들어 게임의 보너스 스테이지를 많이 클리어한 사용자의 통계만을 볼 수 있고, 그 보너스 스테이지를 클리어한 사용자의 나이,성별, 국가 정보등을 볼 수 있다.
게임 플레이 완료율에 대한 퍼널 분석
다음은 앞에서 데이타 분석 모델을 정의할때 정의한 문제로 사용자가 게임을 시작해서 플레이를 끝낸 사용자 까지를 퍼널(깔때기) 분석을 적용한 예이다.
해당 시간에 총 93번의 게임이 플레이 되었으며, 캐릭터까지는 이동하였으나, 공격을 하지 않은 플레이는 3번, 그리고 끝까지 게임 플레이를 끝낸 사용자는 총 62번으로 측정되었다.
이외에도 상품 구매에 대한(인앱)에 대한 분석이나, 디바이스 종류, 앱 버전, 그리고 어느 광고 네트워크에서 사용자가 인입되었는지 등의 분석등 다양한 분석이 가능한데, 대쉬보드의 자세한 지표에 대해서는 http://bcho.tistory.com/1132 를 참고하기 바란다.
노트북을 이용한 커스텀 로그 분석
앞에서는 파이어베이스에서 제공되는 로그와 분석 방법에 대해서만 분석을 진행하였다. 이번에는 커스텀 로그와 원본(raw)데이타를 이용한 데이타 분석에 대해서 알아보자.
모든 원본 데이타는 앞에서도 언급했듯이 구글의 빅쿼리에 저장되기 때문에, SQL 쿼리를 이용하여 자유롭게 데이타 분석이 가능하고 그래프로도 표현이 가능하다.
별도의 개발이 없이 자유롭게 쿼리를 실행하고 그래프로 표현할 수 있는 도구로는 노트북이 있는데, 빅쿼리는 주피터 노트북과 제플린이 지원된다. 주피처 노트북 오픈소스를 구글 클라우드에 맞춘 버전은 Google Cloud Datalab이라는 것이 있는데, 여기서는 데이타랩을 이용하여 분석하였다.
캐릭터 이동 히트맵 분석
앞에서 NPC_MOVE와 PLAYER_ATTACK을 이용하여, NPC의 이동 동선과, PLAYER가 공격을 한 위치를 수집하였다.
이를 히트맵으로 그려보면 다음과 같다.
좌측은 NPC가 주로 이동하는 경로이고 우측은 플레이어가 NPC를 주로 공격한 위치로, 많이 간곳일 수록 진하게 칠해진다.
NPC 캐릭터는 전체 맵에 걸쳐서 이동을 하는 것을 볼 수 있고, 주로 우측 나무 근처를 많이 움직이는 것을 볼 수 있다. 오른쪽 사용자가 공격한 위치를 보면 주로 중앙에 모여 있기 때문에 우측 나무 근처로 움직인 NPC는 생존 확률이 높았을 것으로 생각해볼 수 있다.
그리고 NPC 이동 맵에서 중간중간에 진하게 보이는 점은 NPC 가 생성되는 위치이기 때문에, 이동이 많이 관측되었다.
연령별 플레이 점수 분석
다음으로 플레이어 연령별 점수대를 보면, 최고 점수는 30대가 기록하였고, 대략 4900점대인데 반해서, 전체적인 평균 점수는 40대가 높은 것을 볼 수 있다. (이 데이타는 연령별로 수집된 데이타의 양이 그리 많지 않기 때문에 정확하지는 않다. 어디까지나 분석 예제용으로만 이해하기 바란다.)
분석에 사용된 코드는 아래에 있다. 이 코드는 데모용이고 최적화가 되어있지 않기 때문에, 운영 환경에서는 반드시 최적화를 해서 사용하기 바란다.
참고로, 모든 데이타 분석은 주로 파이썬을 이용하였는데, 근래에 빅데이타 분석용 언어로 파이썬이 많이 사용되기 때문에, 파이썬을 공부해놓으면 좀 더 쉽게 데이타 분석이 가능하다. 또한 파이썬으로 데이타를 분석할때 많이 쓰이는 프레임웍으로는 팬다스 (pandas)와 넘파이 (numpy)가 있는데, 이 둘 역시 같이 익혀놓는것이 좋다.
파이어베이스 노티피케이션 서비스를 통한 이벤트 기반의 푸쉬 타게팅
파이어베이스 애널러틱스와 연계해서 유용하게 사용할 수 있는 기능은 파이어베이스 노티피케이션 이라는 서비스가 있다.
파이어 베이스 노티피케이션 서비스는 파이어베이스에서 제공되는 웹 콘솔을 이용하여 관리자가 모바일 서비스에 손쉽게 푸쉬 메세지를 보낼 수 있는 서비스이다.
푸쉬 타게팅을 위한 별도의 서버 시스템을 개발하지 않고도 마케팅이나 기획자등 비 개발인력이 타게팅된 푸쉬 메세지를 손쉽게 보낼 수 있게 디자인된 서비스인데, 특히 파이어 베이스 애널러틱스와 연계가 되면 세세한 타게팅이 가능하다.
이벤트 로그 기반의 타케팅
푸쉬 타겟을 정할때, 파이어베이스 애널러틱스에서 수집한 이벤트를 조건으로 해서 푸쉬를 타게팅할 수 있다.
예를 들어
게임 스테이지 3 이상을 클리어한 플레이어한 푸쉬를 보낸다.
NPC를 10,000개 이상 죽인 플레이어에게 푸쉬를 보낸다.
아이템을 100개이상 구매한 사용자에게 푸쉬를 보낸다.
와 같이 서비스에서 수집된 이벤트에 따라서 다양한 조건을 정의할 수 있다.
<그림. 파이어베이스 노티피케이션에서 특정 사용자 층을 타게팅 해서 보내는 화면 >
이런 타게팅은 파이어베이스 애널러틱스에서 Audience로 사용자 군을 정의한 후에, (로그 이벤트 조건이나 사용자 이벤트 조건 등), 이 조건에 타겟해서 푸쉬를 파이어베이스 노티피케이션 서비스에서 정의한다.
사용자 정보 기반의 타게팅
서비스의 로그 이벤트 정보뿐 아니라, 사용자에 대해서도 푸쉬 타게팅이 가능한데, 특정 성별이나 나이에 대해 푸쉬를 보내거나, 특정 단말을 사용하는 사용자, 특정 국가에 있는 사용자등 다양한 사용자 관련 정보로 푸쉬를 보낼 수 있다.
사용자 정보 역시 앞의 이벤트 로그 정보처럼 개발자가 커스텀 필드를 추가하여 사용자 정보를 로그에 수집할 수 있다.
스케쥴링
이런 타게팅 푸쉬는 바로 웹에서 보낼 수 도 있지만, 특정 시간에 맞춰서 미리 예약을 해놓는 것도 가능하다.
비용 정책 분석
파이어베이스 애널러틱스에서 원본 데이타를 수집 및 분석 하려면 빅쿼리를 연동해야 하는데, 빅쿼리 연동은 파이어베이스의 무료 플랜으로는 사용이 불가능하다. Blaze 플랜으로 업그레이드 해야 하는데, Blaze 플랜은 사용한 만큼 비용을 내는 정책으로 다른 서비스를 사용하지 않고, 파이어베이스 애널러틱스와 빅쿼리 연동만을 사용할 경우에는 파이어베이스에 추가로 과금되는 금액은 없다. (0원이다.)
단 빅쿼리에 대한 저장 가격과 쿼리 비용은 과금이 되는데, 빅쿼리 저장 가격은 GB당 월 0.02$ 이고, 90일동안 테이블의 데이타가 변하지 않으면 자동으로 0.01$로 50%가 할인된다.
노트북은 비지니스에 전달하기 위한 멋진 액셀이나 대쉬보드와 같은 리포트 보다는 데이타를 다루는 데이타 과학자와 같은 사람들이 사용하는 분석도구인데, 제품의 이름 처럼 노트북의 개념을 가지고 있다.
예를 들어서 설명해보자 우리가 수학문제를 풀려면 연습장을 펴놓고 공식을 사용해가면서 하나하나 문제를 풀어나간다. 이처럼, 빅데이타 분석을 하려면, 여러데이타를 분석해가면서 그 과정을 노트하고 노트한 결과를 기반으로 다음 단계의 문제를 풀어나가는 것이 통상적인데, 노트북 소프트웨어는 문제 풀이에 있어서 기존의 연습장 노트와 같은 사용자 경험을 제공한다.
이러한 노트북 소프트웨어의 특징은 메모를 위한 글과, 계산을 위한 소스 코드를 한페이지에 같이 적을 수 있고, 이 소스 코드는 노트북 내에서 실행이 가능하고 결과도 같은 페이지에 출력해준다.
다음 화면은 본인이 작성했던 노트북의 일부로 딥러닝 프레임웍인 텐서플로우에 대해서 공부하면서 간단하게 문법과 샘플 코드를 노트북에 정리한 예이다.
데이타랩
구글의 데이타랩(https://cloud.google.com/datalab/) 은 오픈소스 주피터 노트북을 구글 클라우드 플랫폼에 맞게 기능을 추가한 노트북이다. 기본이 되는 주피터 노트북이 오픈소스이기 때문에, 데이타랩 역시 오프소스로 코드가 공개되어 있다.
데이타랩은 기본으로 파이썬 언어를 지원하며, 빅쿼리 연동등을 위해서 SQL과, 자바 스크립트를 지원한다.
또한 머신러닝의 딥러닝 프레임웍인 텐서플로우도 지원하고 있다.
데이타랩에서 연동할 수 있는 데이타는 구글 클라우드상의 VM이나, 빅쿼리, Google Cloud Storage
데이타랩은 오픈소스로 별도의 사용료가 부가되지 않으며, 사용 목적에 따라서 VM에 설치해서 실행할 수 도 있고, 로컬 데스크탑에 설치해서 사용할 수 도 있다. 도커로 패키징이 되어 있기 때문에 도커 환경만 있다면 손쉽게 설치 및 실행이 가능하다.
이번에는 차트를 사용하는 방법을 알아보자, 안드로이드 로그에서 이벤트 로그중에, 많이 나오는 로그 20개에 대한 분포도를 파이 차트로 그려내는 예제이다.
%%sql --module events
SELECT event_dim.name as event_name, COUNT(event_dim.name) as event_count
FROM [firebase-analytics-sample-data:android_dataset.app_events_20160601]
GROUP BY event_name
ORDER BY event_count DESC
LIMIT 20
쿼리 결과를 --module 명령을 이용하여 events라는 모듈에 저장한후
%%chart pie --fields event_name,event_count --data events
title: Event count
height: 400
width: 800
pieStartAngle: 20
slices:
0:
offset: .2
구글 차트 명령을 이용하여 pie 차트를 그린다. 필드는 앞의 모듈에서 쿼리한 event_name과 event_count 필드를 이용하고, 데이타는 앞에서 정의한 “events” 모듈에서 읽어온다.
차트 실행 결과는 다음과 같다.
이외에도 Tensorflow 연동이나 GCS를 연동하는 방법, 그리고 구글 차트 이외에 일반 plot 함수를 이용하여 그래프를 그리는 등 다양한 기능을 제공하는데, 이에 대한 자세한 설명은 데이타랩을 설치하면 /docs/README.md 파일을 참조하면 다양한 가이드를 찾을 수 있다.
파이어베이스 애널러틱스의 대단한 기능중의 하나가, 모바일에서 올라온 모든 원본 로그를 빅쿼리에 저장하고, 이를 빅쿼리를 통해서 분석할 수 있는 기능이다. 대부분의 매니지드 서비스 형태의 모바일 애널리틱스 서비스는 서비스에서 제공하는 지표만, 서비스에서 제공하는 화면을 통해서만 볼 수 있기 때문에, 상세한 데이타 분석이 불가능하다. 파이어베이스의 경우에는 빅쿼리에 모든 원본 데이타를 저장함으로써 상세 분석을 가능하게 해준다.
아울러, 모바일 서비스 분석에 있어서, 상세 로그 분석을 위해서 로그 수집 및 분석 시스템을 별도로 만드는 경우가 많은데, 이 경우 모바일에 설치될 로그 수집 에이전트에서 부터 로그를 수집하는 API 서버, 이를 저장하기 위한 분산 큐(카프카 Kafka)와 같은 복잡한 백앤드 시스템을 설계 구현해야 하는데, 파이어베이스 애널러틱스의 로깅 기능을 이용하면 별도의 이런 인프라 구현이 없이도 손쉽게 로그를 수집 및 분석할 수 있다. (일종의 무임 승차라고나 할까?)
가격 정책
그렇다면 가장 고민이 되는 것이 가격 정책일 것이다. 파이어베이스 애널러틱스에서 빅쿼리에 데이타를 저장하려면 파이어베이스 플랜중 무료가 아닌 유료 플랜인 Blaze 플랜을 사용해야 한다.
그러나, 다행이도 Blaze 플랜은 “Pay as you go” 모델로 사용한 만큼 비용을 지불하는 모델인데, “Google Cloud Integration”은 별도의 비용이 부과 되지 않는다.
단지 빅쿼리에 대한 비용만 부담이 되는데, 빅쿼리의 경우 데이타 로딩은 무료이고, 저장 요금 역시 GB당 월 0.02$ (약 22원)이며, 90일동안 해당 데이타를 사용하지 않으면 이 요금은 50%로 자동 할인되서 GB당 월 0.01$(약 11원)만 과금된다. 이외에 쿼리당 비용이 과금되는데, 쿼리당 비용은 쿼리에서 스캔한 데이타 용량 만큼만 과금이 된다. TB를 쿼리 했을때 5$가 과금이되는데, 이역시 전체 테이블을 스캔을 하는것이 아니라, 쿼리에서 스캔하는 컬럼에 대해서만 과금이 되고, 전체 테이블이 아니라, 쿼리에서 스캔하는 날짜만 과금이 되기 때문에, 실제 과금 금액은 미미하다고 볼 수 있다. 실제로 실 서비스에서 모 앱의 하루 데이타를 수집한 경우 17만건의 이벤트가 수집되었는데 저장 용량은 전체 350 MB에 불과하다. 전체 컬럼을 스캔한다고 하더라도 (전체 컬럼을 스캔할 일은 없겠지만….) 쿼리 비용은 0.00175$에 불과하다.
파이어베이스 애널러틱스와 빅쿼리를 연동하여 데이타 수집하기
파이어베이스 애널러틱스에서 데이타를 빅쿼리로 수집하기 위해서는 앞에서 언급한바와 같이 먼저 파이어베이스 플랜을 Blaze로 업그레이드 해야 한다. 파이어베이스 콘솔 좌측 하단을 보면 아래와 같이 UPGRADE 버튼이 있다. 이 버튼을 눌러서 Blaze 플랜으로 업그레이드를 하자
다음으로 파이어베이스 애널러틱스 프로젝트를 빅쿼리와 연결을 해줘야 한다.
파이어베이스 콘솔 좌측 상단에서 설정 버튼을 누른 후에, Project settings 메뉴를 선택한다.
프로젝트 세팅 메뉴에 들어가서 상단 메뉴중에 ACCOUNT LINKING이라는 메뉴를 선택한다.
그러면 구글 플레이나 광고 플랫폼등과 연결할 수 있는 메뉴와 함께 아래 그림처럼 빅쿼리로 연결할 수 있는 메뉴와 “LINK TO BIGQUERY”라는 버튼이 화면에 출력된다.
이 버튼을 누르면 작업은 끝났다. 이제부터 파이어베이스의 모든 로그는 빅쿼리에 자동으로 수집되게 된다.
만약에 수집을 중단하고 싶다면 위의 같은 화면에서 LINK TO BIGQUERY라는 버튼이 MANAGE LINKING으로 바뀌어 있는데, 이 버튼을 누르면 아래와 같이 App Details가 나온다.
여기서 스위치 버튼으로 Send data to BigQuery를 끔 상태로 변경해주면 된다.
이제 부터 대략 한시간 내에, 데이타가 빅쿼리에 수집되기 시작할 것이다.
수집 주기
그러면 파이어베이스 애널러틱스에서는 어떤 주기로 데이타를 수집하고 수집된 데이타는 언제 조회가 가능할까? 이를 이해하기 위해서는 앱 로그 수집에 관여되는 컴포넌트와 흐름을 먼저 이해할 필요가 있다.
로그 수집이 가능한 앱은 크게, 구글 플레이 스토어에서 배포되는 앱, 구글 플레이 스토어를 통하지 않고 배포되는 앱 그리고 iOS 앱 3가지로 나눌 수 있다.
이 앱들이 파이어베이스 서버로 로그를 보내는 방식은 앱마다 약간씩 차이가 있다.
플레이스토어에서 다운 받은 앱 : 각 개별 앱이 이벤트 로그를 수집하여 저장하고 있다가 1시간 주기로, 모든 앱들의 로그를 모아서 파이어베이스 서버로 전송한다.
플레이스토어에서 다운받지 않은 앱 : 플레이스토어에서 다운로드 받은 앱과 달리 다른 앱들과 로그를 모아서 함께 보내지 않고 한시간 단위로 로그를 모아서 개별로 파이어베이스에 전송한다.
iOS 앱 : 앱별로 한시간 단위로 로그를 모아서 파이어베이스 서버로 전송한다.
이렇게 앱에서 파이어베이스 서버로 전송된 데이타는 거의 실시간으로 구글 빅쿼리에 저장된다.
그러나 파이어베이스 애널러틱스의 대쉬 보다는 대략 최대 24시간 이후에 업데이트 된다. (24시간 단위로 분석 통계 작업을 하기 때문이다.)
이 전체 흐름을 도식화 해보면 다음과 같다.
수집된 데이타 구조
그러면 빅쿼리에 수집된 테이블은 어떤 구조를 가질까?
테이블 구조를 이해하기 전에 테이블 종류를 먼저 이해할 필요가 있다.
앱에서 수집한 로그는 안드로이드와 iOS 각각 다른 데이타셋에 저장되며, 테이블 명은
app_events_YYYYMMDD
가 된다. 2016년 8월30일에 수집한 로그는 app_events_20160830 이 된다.
Intraday 테이블
여기에 intraday 테이블이라는 개념이 존재하는데, 이 테이블은 app_events_intraday_YYYYMMDD 라는 이름으로 저장이 되는데, 이 테이블은 실시간 데이타 수집을 목적으로 하는 테이블로 오늘 데이타가 저장된다. 예를 들어 오늘이 2016년9월1일이라면, app_events테이블은 app_events_20160831 까지만 존재하고, 9월1일자 데이타는 app_events_intraday_20160901 이라는 테이블에 저장된다.
9월1일이 지나면 이 테이블은 다시 app_events_20160901 이라는 이름으로 변환된다.
intraday 테이블의 특성중의 하나는 몇몇 필드들은 값이 채워지지 않고 NULL로 반환된다. 모든 데이타를 수집하고 배치 연산을 통해서 계산이 끝나야 하는 필드들이 그러한데, LTV 값과 같은 필드가 여기에 해당한다.
여기서 주의할점 중의 하나가 intraday 테이블이 하나만 존재할것이라는 가정인데. 결론 부터 이야기 하면 최대 2개가 존재할 수 있다. 9월1일 시점에 app_events_intraday_20160901 테이블이 존재하다가 9월2일이 되면 app_events_intraday_20160902 테이블이 생성된다. app_events_intraday_20160901 를 app_events_20160901 테이블로 변환을 해야 하는데, 단순히 복사를 하는 것이 아니라, 배치 연산등을 수행하기 때문에 연산에 다소 시간이 걸린다. 그래서 연산을 수행하는 동안에는 app_events_intraday_20160901 테이블과 app_events_intraday_20160902이 동시에 존재하고, 9월1일 데이타에 대한 연산이 종료되면 app_events_intraday_20160901 은 app_events_20160901 로 변환 된다.
테이블 스키마
빅쿼리에 저장된 데이타의 테이블 구조를 이해하기 위해서 빅쿼리의 데이타 저장 특성을 이해할 필요가 있는데, 빅쿼리는 테이블 데이타 구조를 가지면서도 JSON과 같이 컬럼안에 여러 컬럼이 들어가는 RECORD 타입이나, 하나의 컬럼안에 여러개의 데이타를 넣을 수 있는 REPEATED 필드라는 데이타 형을 지원한다.
<그림. 레코드 타입의 예>
레코드 타입은 위의 그림과 같이 Name이라는 하나의 컬럼 내에 Last_name과 First_name이라는 두개의 서브 컬럼을 가질 수 있는 구조이다.
아래는 REPEATED 필드(반복형 필드)의 데이타 예인데, Basket이라는 컬럼에 Books,Galaxy S7, Beer 라는 3개의 로우가 들어가 있다.
<그림. 반복형 필드 예>
이런 구조로 인하여, 빅쿼리는 JSON과 같이 트리 구조로 구조화된 데이타를 저장할 수 있고, 실제로 파이어베이스 애널러틱스에 의해 수집되어 저장되는 데이타도 JSON과 같은 데이타 구조형으로 저장이 된다.
많은 데이타 필드가 있지만, 큰 분류만 살펴보면 다음과 같은 구조를 갖는다.
하나의 레코드는 하나의 앱에서 올라온 로그를 나타낸다. 앱은 앞의 수집 주기에 따라서 한시간에 한번 로그를 올리기 때문에, 하나의 레코드(행/로우)는 매시간 그 앱에서 올라온 로그라고 보면 된다.
가장 상위 요소로 user_dim과, event_dim이라는 요소를 가지고 있다.
user_dim은 사용자나 디바이스에 대한 정보를 주로 저장하고 있고, event_dim은 앱에서 발생한 이벤트들을 리스트 형태로 저장하고 있다.
user_dim에서 주목할만한 것은 userid에 관련된 것인데, userid는 사용자 id 이지만, 파이어베이스가 자동으로 수집해주지는 않는다. 개발자가 앱의 파이어베이스 에이전트 코드에서 다음과 같이 setUserId 메서드를 이용해서 설정해줘야 빅쿼리에서 조회가 가능하다. (앱 서비스의 계정을 세팅해주면 된다.)
다음 주목할 필드는 user_dim에서 app_info.app_instance_id 라는 필드인데, 이 필드는 각 앱의 고유 ID를 나타낸다. 파이어베이스가 자동으로 부여하는 id로 설치된 앱의 id이다.
예를 들어 내가 갤럭시S7과 노트7를 가지고 같은 앱을 설치했다고 하더라도 각각 다른 디바이스에 설치되었기 때문에 각각의 앱 id는 다르다.
다음은 event_dim인데, event_dim은 이벤트들로 레코드들의 배열(리스트)로 구성이 되고 각각의 이벤트는 이벤트 이름과 그 이벤트에 값을 나타내는 name 과 params라는 필드로 구성이 되어 있다. params는 레코드 타입으로 여러개의 인자를 가질 수 있고, params내의 인자는 또 각각 key와 value식으로 하여 인자의 이름과 값을 저장한다. values는 string_value,int_value,double_value 3가지 서브 필드를 가지고 있는데, 인자의 타입에 따라서 알맞은 필드에만 값이 채워진다. 예를 들어 인자의 타입이 문자열 “Cho” 이고, 인자의 이름이 “lastname”이면, params.key “lastname”이 되고, params.value.string_value=”Cho”가 되고 나머지 필드인 params.value.int_value와 params.value.float.value는 null이 된다.
"event_dim": [
{
"name": "Screen",
"params": [
{
"key": "firebase_event_origin",
"value": {
"string_value": "app",
"int_value": null,
"float_value": null,
"double_value": null
}
},
{
"key": "Category",
"value": {
"string_value": "Main",
"int_value": null,
"float_value": null,
"double_value": null
}
},
]
},
{
"name": "Purchase",
"params": [
{
"key": "amount",
"value": {
"string_value": null,
"int_value": “5000”,
"float_value": null,
"double_value": null
}
}
},
]
},
위의 예제는 빅쿼리에 저장된 하나의 행을 쿼리하여 JSON형태로 리턴 받은 후, 그 중에서 event_dim 필드 내용 일부를 발췌한 것이다.
Screen과 Purchase라는 두개의 이벤트를 받았고,
Screen은 firebase_event_origin=”app”, Category=”main” 이라는 두개의 인자를 받았다.
분석 지표에 대한 이해를 하기 위해서는 먼저 기준 시간에 대한 이해를 할 필요가 있다. 파이어베이스 애널러틱스 콘솔의 우측 상단의 보면 분석 기간을 선택할 수 있다. 분석 기간은 오늘, 어제, 이번주, 지난 7일, 지난 30일 등 미리 정해진 기간이나 Custom을 이용하여, 기간을 정의할 수 있다.
1. Active User (활성 사용자수)
가장 처음에 나오는 지표는 활성 사용자 수 이다. 가장 많이 보는 지표중의 하나인데, 일,월,주별 방문자 수 이다.
Monthly Active User (MAU:월별 활성 사용자 수) 그래프의 X축의 날짜에서 부터 부터 전 30일까지의 앱을 사용한 총 일일 사용자 수.
Weekly Active User (WAU:주별 활성 사용자 수) 그래프의 X축의 날짜에서 부터 전 7일 까지 앱을 사용한 총 일일 사용자의 수
Daily Active User (DAU : 주별 활성 사용자 수) 그래프의 X축 날짜의 앱을 사용한 일일 사용자의 수
위의 그래프를 보면 WAU와 DAU는 수평을 그리고 있는데, 반하여 MAU가 올라가고 있음을 볼 수 있다. 이 그래프는 파이어베이스 애널러틱스를 설치한지 얼마 되지 않는 기간에 뽑은 리포트인데, DAU는 일정하기 때문에, MAU는 누적되서 그래프가 상승 곡선을 띄게 되는 것이다.
예를 들어 8월1일에 설치했다고 했을때, 8월2일의 MAU는 7월3일~8월2일 DAU의 합이 되는데, 8월 1일에 설치를 했기 때문에 7월3일~7월30일까지의 데이타는 없다. 8월 30일의 MAU는 8월1일~8월30일까지 합이고, 8월1~30일까지는 데이타가 있기 때문에 누적되서 상승 곡선을 그리게 된다.
2. Average Revenue (평균 수익)
다음 지표는 수익 지표이다. 크게 ARPU와 ARPPU로 표현되는데 그 내용은 다음과 같다.
ARPU (Average revenue per User) 사용자별 수익률로, 전체 수익을 전체 사용자 수로 나눠서 계산한다.
ARPPU (Average revenue per purchased user) 유료 사용자별 수익률로, 전체수익을 비용을 지불한 사용자로 나눠서 계산한다.
전체 서비스가 유료가 아닌 이상, 커머스의 경우 일부 사용자만 물건을 구매하거나, 게임이나 서비스 앱인 경우에는 일부 사용자만 인앱구매등을 통해서 비용을 지불하기 때문에 다른 두개의 지표가 나온다.
ARPU는 서비스에서 사용자가 증가하는 당 수익률이 어떻게 올라가는지를 알 수 있고, ARPPU는 유료 사용자당 얼마의 금액을 사용하는지를 이해할 수 있다.
이 지표는 파이어베이스 애널러틱스에서 ecommerce_purchase (쇼핑몰 이벤트 중, 구매 이벤트)와 in_app_purchase (일반 이벤트중 인앱 구매) 이벤트에 의해서 추적되기 때문에, ARPU와 ARPPU를 구하고 싶으면, 상품구매나 인앱 구매가 발생하였을때, 위의 이벤트를 통해서 파이어베이스 애널러틱스에 이벤트를 로깅해줘야 한다.
3. first_open attribution (앱실행 빈도)
다음 지표는 첫 앱 실행을 추적하는 지표이다.
기준 시간 기간 동안 인스톨 또는 재 인스톨이 된후, 처음으로 앱이 실행된 횟수를 추적하는 지표이다.
이 지표는 다양한 의미를 가지고 있는데, 앱 다운로드가 캠페인등을 통해서 많이 일어났다고 하더라도, 앱을 한번도 실행을 해보지 않고 삭제하는 경우도 많기 때문에, 앱 다운로드 대비, 얼마나 많은 사용자가 실제로 앱을 실행했는 가를 추적할 수 있다.
앱 다운로드 횟수는 구글 플레이 스토어나 애플 앱스토어의 사용자 콘솔에서 그 값을 추적할 수 있다.
또한 “NETWORK SETTING”에서 광고 서비스 네트워크를 연동할 수 있는데, 광고 네트워크를 연동하게 되면 앱의 설치가 사용자가 앱스토어에서 그냥 자발적으로 설치를 한것인지 아니면 광고 네트워크의 특정 광고 캠페인을 통해서 인입된 사용자인지를 판단할 수 있다.
<그림 광고 네트워크를 연동하는 화면 >
이를 통해서, 광고 마케팅의 효율과, 성과를 측정하여 효율적인 광고 집행이 가능하다.
앱 첫실행을 기록하는 first_open 이벤트는 개발자가 별도로 코드 상에 정의하지 않더라도 자동으로 로깅 된다.
아래 예제를 보자, 광고 네트워크를 통하지 않고, 앱을 처음 사용한 것이 150K 정도 되고, 다음은 구글을 통해서 들어온 비중이 38K 정도가 된다.
맨뒤에, LTV 라는 수치가 있는데, LTV는 Life Time Value의 약자로 사용자가 앱을 설치 한 후, 초기 120일 동안에 일으킨 매출의 수의 총합이다. 매출은 ARPU와 같이 ecommerce_purchase (쇼핑몰 이벤트 중, 구매 이벤트)와 in_app_purchase (일반 이벤트중 인앱 구매) 이벤트에 의해서 추적된다.
이를 통해서 광고 네트워크별로 얼마만큼의 사용자가 들어오고, 유입된 사용자가 발생 시킨 매출을 추적하여 광고의 효율을 측정할 수 있다.
여기서 포스트백 (PostBack)이라는 기능을 잠깐 짚고 넘어갈 필요가 있는데, 쇼핑몰에서 광고 네트워크를 통해서 광고를 집행하고 있다고 하자, 사용자가 호텔 예약을 하고 싶어하는 니즈를 파악하고 사용자에게 호텔 예약 광고를 계속 내보냈다. 광고를 통해서 사용자는 호텔을 예약했다고 하자. 그렇다면 이제 더이상 해당 사용자에게 호텔 광고가 계속 나가면 안된다. (이미 팔았기 때문에) 이를 막기 위해서 광고 네트워크에 해당 물건을 사용자가 구매했으니, 더 이상 같은 광고를 내보내지 말라고 알려줘야 한다. 이를 포스트 백(Postback)이라고 한다. 파이어베이스 애널러틱스에서 포스트백을 설정하는 방법은 https://support.google.com/firebase/answer/6317518?hl=en&utm_id=ad#postbacks 를 참고하기 바란다.
4. Retention cohort (사용자 잔존율 코호트 분석)
다음 지표는 사용자 잔존율을 코호트 분석을 통해서 분석해낸 결과로, 사용자가 처음 앱을 사용한 후 얼마나 많은 사용자가 지속적으로 남아 있느냐를 나타내는 중요한 지표이다. 주 단위 잔존율을 기준으로 통계를 잡아주는데, 잔존 사용자가 많을 수록, 그래프가 더 진하게 표시 되는데, 다음 예제를 보면, 7월17일~7월23일에 가입한 사용자는 총 19481명으로 첫주에는 100% 사용자가 잔존하였으나, 1주 후에는 23.5%만 남았고, 2 주후에는 12.2%만 남았다가 5주후에는 6.4%만 남았다.
7월31~8월6일에 가입한 사용자의 경우 1주차에 23.7%가 남아 있어서 다른 주 대비 잔존율이 높아서 조금 더 진한 색깔이 그래프로 표현되었다.
5. User engagement (사용자 활동 지표)
사용자 활동 지표란, 사용자들이 기간동안 얼마나 앱을 사용했느냐에 대한 기간과 횟수등을 표현하는 지표들이다. 아래 그래프 예제로 설명하면
Daily engagement (총 사용시간) 통계 기간 (기준 시간 기간) 동안 모든 사용자들이 앱을 사용한 총 시간의 합이다. 위의 예에서는 1년 34일 14시간을 사용한것으로 집게 되었다.
Daily engagement per user (사용자당 평균 사용 시간) 통계 기간중, 사용자 1인당 평균 사용시간이다. Daily engagement를 그 기간 동안 총 활성 사용자 수로 나눈 값이다.
Session per user (사용자당 평균 세션 수 ) 사용자당 평균 세션 수 인데, 세션은 사용자가 기간동안 앱을 사용한 횟수로 보면 되다. 위의 예제에서는 사용자당 평균 3.7 회 정도 사용하였다.
Avg. session duration (사용자당 평균 세션 길이) 사용자당 세션의 길이로, 한번 사용할때 평균 얼마 정도의 시간을 사용하느냐인데, 여기서는 사용자당 한번 사용에 7분 8초 정도를 사용한것으로 집게 되었다.
이런 통계 분석에서 주의할점은 이는 어디까지나 평균 값일 뿐이다. 특정 사용자는 기간동안 평균값이 3.7회가 넘는 10회 20회를 사용할 수 도 있고, 어떤 사용자 층은 한번 밖에 사용하지 않을 수 도 있다. 일반적으로 모바일 서비스 앱은 그 사용횟수나 사용 시간에 대한 분포가 특정 사용자군 (헤비유저)에게 몰리는 경향이 있기 때문에, 이러한 평균 지표보다는 정규 분포형의 지표를 따라서 분석하는 것이 조금 더 정확한데, 이를 위해서는 파이어베이스 애널러틱스의 지표만으로는 불가능하고, 원본 데이타를 기반으로 분석을 할 필요가 있다. 이를 위해서 원본 데이타를 빅쿼리에 저장한 후 분석하는 것이 좋은데, 이 방법은 나중에 다시 설명하도록 하겠다.
6. In-App purchase (인앱 구매)
이 지표는 인앱 구매에 대한 지표로, in_app_purchase 이벤트에 의해서 수집된 정보를 기반으로 통계를 계산한다. 총 얼마 만큼의 사용자가, 인앱 구매를 했는지를 출력하고, 이를 통해서 발생된 매출을 출력한다.
아울러 아래 그림과 같이 최고 매출을 일으킨 인앱 구매 상품들을 구매 횟수와 총 매출액을 통계로 표시해준다.
아래의 “VIEW IN-APP PURCHASE DETAILS” 탭을 클릭하면, 모든 인앱 상품의 매출 정보와 판매 추이, 사용자 연령대별 매출 발생 비중등 자세한 정보를 볼 수 있다.
<그림. 인앱 구매 이벤트 집게 화면에서 상세 화면중 성별 및 연령 별 구매 비율 >
7. App version (앱 버전)
통계 기간 동안 모든 사용자가 사용한 앱 버전에 대한 통계를 보여준다. 상위 3개의 버전을 보여주고, 나머지는 Others로 묶어서 통계로 보여준다.
앱 버전 역시 모바일 서비스에서 매우 중요한 지표중의 하나인데, 신기능이나 신규 컨텐츠가 올라가더라도 버전이 옛날 버전이 많이 깔려 있을 경우 신규 기능이나 컨텐츠가 동작하지 않을 수 도 있기 때문에, 얼마나 사용자들이 새 버전으로 업데이트했는지 추적하는 것이 중요한 지표가 되며, 아울러 경우에 따라서 예전 버전이 많을 경우에는 강제 업데이트를 해야 하는 경우도 있기 때문에, 앱 버전에 대한 추적 역시 매우 중요한 지표로 작용하낟.
8. Devices (디바이스)
통계 기간동안에 사용자가 앱을 사용하는데 사용한 주요 디바이스명과, OS 버전에 대한 통계이다.
디바이스명은 테스트 환경을 만들때 사용자들이 주로 어떤 디바이스를 사용하는지를 알면 테스트 디바이스를 준비하기가 편리하기 때문이고, OS version의 경우, 낮은 버전의 OS에서는 특정 SDK나 기능이 작동하지 않을 수 있기 때문에 앱 개발시 어느 OS 버전 부터 지원을 해야 할지, 그리고 사용 빈도가 낮은 OS는 언제 지원을 중단할 수 있을지등을 결정할 수 있는 지표로 활용이 가능하다.
9. Location(위치)
이해는 쉽지만 가장 중요한 지표중의 하나이다. 해당 기간동안 주로 어느 국가에서 앱이 많이 사용되었는 가를 리포팅 해주는 지표이다.
국내나 특정 국가 한정 서비스인 경우가 아닌 글로벌 서비스인 경우 서비스가 어느 나라에서 인기가 있는 가에 따라서, 그 나라에 맞도록 앱을 현지화 하거나, 앱에 대한 마케팅 자원등을 선택과 집중할 수 있다.
10. Demographics (데모그래픽 정보)
데모 그래픽 정보는 사용자의 연령과 성별등을 나타내는 정보이다.
이를 통하여 앱 사용자가 누구인지를 파악할 수 있고, 이를 기반으로 앱 서비스를 타케팅할 수 있는 대상을 식별하여, 제공할 컨텐츠, 마케팅 캠페인 대상등을 정할 수 있다.
11. Interest (사용자 흥미)
마지막으로 이 앱 서비스를 사용하는 사용자가 어떤 흥미를 가지고 있는지를 분석 해주는 기능인데,
이러한 모바일 분석 플랫폼을 무료로 제공하는 서비스 제공자는 구글뿐아니라 야후, 트위터와 같이 광고를 통해서 수익을 창출하는 경우가 많다. 이러한 사업자등은 자사의 서비스에서 사용자들이 어떤 서비스나 어떤 컨텐츠를 선호 하는지를 분석한 후에, 이를 기반으로 모바일 데이타 분석 플랫폼을 사용하는 앱 개발사들의 사용자들이 어떤 컨텐츠나 서비스를 선호하는지를 추적 분석해주는데, 이것이 Interest 분석이다.
위의 그림과 같이 이 앱을 사용하는 사용자들은 TV나 온라인 비디오에 관심이 많은 사용자들이 7.6%, 그리고 음악에 관심이 있는 사용자들이 6.7%, 카메라나 전자 제품에 관심 있는 사용자들이 3.6% 정도이다.
이를 통해서 앱 사용자들을 대상으로 한 타겟 광고나 서비스 개선등에 활용할 수 있다.
지금까지 간략하게나마 파이어베이스 애널러틱스 대쉬보드의 주요 지표에 대해서 설명하였다.
여기에 나오는 지표들은 파이어베이스뿐 아니라 일반적인 모바일 앱 서비스 분석 지표로도 사용되는 만큼, 잘 이해해놓으면 모바일 서비스 빅데이타 분석에 유용하게 활용할 수 있다.
https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder
구글에는 위와 같이 광고를 트래킹 할 수 있는 url 빌더가 있습니다.
더불어, ad network를 custom으로 선택하여 자유롭게 광고 url을 빌드 할 수 있습니다.
그런데, firebase는 ad network가 지정되어 있고 custom으로 url을 빌드 할 수 없는 것으로 보여지네요.
(Firebase>Analytics>기여> 네트워크)
다른 어떤 탭이 따로 구현이 되어서, 네트워크에서 설정이 불가능 한 것인지 궁금합니다. ㅠㅠ
아울러, Firebase>Analytics>기여> 네트워크 에서 생성하는 url과
다이나믹 링크의 url의 쓰임은 어떻게 다른 건가요?
파이어 베이스는 모바일 백앤드의 종합 솔루션으로, 크래쉬 리포팅, 리모트 컨피그를 이용한 A/B 테스팅 플랫폼, 클라우드와 자동 동기화가 가능한 리얼타임 데이타 베이스, 사용자 인증 기능, 강력한 푸쉬 플랫폼 다양한 모바일 기기에 대해서 테스트를 해볼 수 있는 테스트랩 등, 모바일 앱 개발에 필요한 모든 서비스를 제공해주는 종합 패키지와 같은 플랫폼이라고 보면 된다. 안드로이드 뿐만 아니라 iOS까지 지원하여 모든 모바일 앱 개발에 공통적으로 사용할 수 있다.
그중에서 파이어베이스 애널러틱스 (Firebase analytics)는 모바일 부분은 모바일 앱에 대한 모든 이벤트를 수집 및 분석하여 자동으로 대쉬 보드를 통하여 분석을 가능하게 해준다.
이 글에서는 파이어베이스 전체 제품군중에서 파이어베이스 애널러틱스에 대해서 수회에 걸쳐서 설명을 하고자 한다.
파이어베이스 애널러틱스
이미 시장에는 모바일 앱에 대한 데이타 분석이 가능한 유료 또는 무료 제품이 많다.
대표적으로 야후의 flurry, 트위터 fabric, 구글 애널러틱스등이 대표적인 제품군인데, 그렇다면 파이어베이스가 애널러틱스가 가지고 있는 장단점은 무엇인가?
퍼널 분석 및 코호트 분석 지원
파이어베이스 애널러틱스는 데이타 분석 방법중에 퍼넬 분석과 코호트 분석을 지원한다.
퍼널 분석은 한글로 깔데기 분석이라고 하는데, 예를 들어 사용자가 가입한 후에, 쇼핑몰의 상품 정보를 보고 주문 및 결재를 하는 단계 까지 각 단계별로 사용자가 이탈하게 된다. 이 구조를 그려보면 깔데기 모양이 되는데,사용자 가입에서 부터 최종 목표인 주문 결재까지 이루도록 단계별로 이탈율을 분석하여 서비스를 개선하고, 이탈율을 줄이는데 사용할 수 있다.
코호트 분석은 데이타를 집단으로 나누어서 분석하는 방법으로 일일 사용자 데이타 (DAU:Daily Active User)그래프가 있을때, 일일 사용자가 연령별로 어떻게 분포가 되는지등을 나눠서 분석하여 데이타를 조금 더 세밀하게 분석할 수 있는 방법이다.
이러한 코호트 분석과 퍼넬 분석은 모바일 데이타 분석 플랫폼 중에서 일부만 지원하는데, 파이어베이스 애널러틱스는 퍼넬과 코호트 분석을 기본적으로 제공하고 있으며, 특히 코호트 분석으로 많이 사용되는 사용자 잔존율 (Retention 분석)의 경우 별다른 설정 없이도 기본으로 제공하고 있다.
구글의 빅쿼리는 아마존 S3나, 구글의 스토리지 서비스인 GCS 보다 저렴한 비용으로 데이타를 저장하면서도, 수천억 레코드에 대한 연산을 수십초만에 8~9000개의 CPU와 3~4000개의 디스크를 사용해서 끝낼만큼 어마어마한 성능을 제공하면서도, 사용료 매우 저렴하며 기존 SQL 문법을 사용하기 때문에, 매우 쉽게 접근이 가능하다.
모바일 데이타 분석을 쉽게 구현이 가능
보통 모바일 서비스에 대한 데이타 분석을 할때는 무료 서비스를 통해서 DAU나 세션과 같은 기본적인 정보 수집은 가능하지만, 추가적인 이벤트를 수집하여 저장 및 분석을 하거나 서버나 다른 시스템의 지표를 통합 분석 하는 것은 별도의 로그 수집 시스템을 모바일 앱과 서버에 만들어야 하였고, 이를 분석 및 저장하고 리포팅 하기 위해서 하둡이나 스파크와 같은 복잡한 빅데이타 기술을 사용하고 리포팅에도 많은 시간이 소요 되었다.
파이어베이스 애널러틱스를 이용하면, 손 쉽게, 추가 이벤트나 로그 정보를 기존의 로깅 프레임웍을 통하여 빅쿼리에 저장할 수 있고, 복잡한 하둡이나 스파크의 설치나 프로그래밍 없이 빅쿼리에서 간략하게 SQL만을 사용하여 분석을 하고 오픈소스 시각화 도구인 Jupyter 노트북이나 구글의 데이타스튜디오 (http://datastudio.google.com)을 통하여 시작화가 간단하기 때문에, 이제는 누구나 쉽게 빅데이타 로그를 수집하고 분석할 수 있게 된다.
실시간 데이타 분석은 지원하지 않음
파이어베이스 애널러틱스가 그러면 만능 도구이고 좋은 기능만 있는가? 그건 아니다. 파이어베이스 애널러틱스는 아직까지는 실시간 데이타 분석을 지원하고 있지 않다. 수집된 데이타는 보통 수시간이 지나야 대쉬 보드에 반영이 되기 때문에 현재 접속자나, 실시간 모니터링에는 적절하지 않다.
그래서 보완을 위해서 다른 모니터링 도구와 혼용해서 사용하는 게 좋다. 실시간 분석이 강한 서비스로는 트위터 fabric이나 Google analytics 등이 있다.
이러한 도구를 이용하여 데이타에 대한 실시간 분석을 하고, 정밀 지표에 대한 분석을 파이어베이스 애널러틱스를 사용 하는 것이 좋다.
다음으로 파이어베이스 프로젝트를 생성한다. 상단 메뉴에서 “CREATE NEW PROJECT”를 선택하면 새로운 파이어 베이스 프로젝트를 생성할 수 있다. 만약에 기존에 사용하던 구글 클라우드 프로젝트등이 있으면 별도의 프로젝트를 생성하지 않고 “IMPORT GOOGLE PROJECT”를 이용하여 기존의 프로젝트를 불러와서 연결할 수 있다.
프로젝트가 생성되었으면 파이어베이스를 사용하고자 하는 앱을 등록해야 한다.
파이어베이스 화면에서 “ADD APP” 이라는 버튼을 누르면 앱을 추가할 수 있다.
아래는 앱을 추가하는 화면중 첫번째 화면으로 앱에 대한 기본 정보를 넣는 화면이다.
“Package name” 에, 파이어베이스와 연동하고자 하는 안드로이드 앱의 패키지 명을 넣는다.
ADD APP 버튼을 누르고 다음 단계로 넘어가면 google-services.json 이라는 파일이 자동으로 다운된다. 이 파일은 나중에 안드로이드 앱의 소스에 추가해야 하기 때문에 잘 보관한다.
Continue 버튼을 누르면 아래와 같이 다음 단계로 넘어간다. 다음 단계에서는 안드로이드 앱을 개발할때 파이어베이스를 연동하려면 어떻게 해야 하는지에 대한 가이드가 나오는데, 이 부분은 나중에 코딩 부분에서 설명할 예정이니 넘어가도록 하자.
자 이제 파이어베이스 콘솔에서, 프로젝트를 생성하고 앱을 추가하였다.
이제 연동을 할 안드로이드 애플리케이션을 만들어보자.
안드로이드 빌드 환경 설정
콘솔에서 앱이 추가되었으니, 이제 코드를 작성해보자, 아래 예제는 안드로이드 스튜디오 2.1.2 버전 (맥 OS 기준) 으로 작성되었다.
먼저 안드로이드 프로젝트를 생성하였다. 이때 반드시 안드로이드 프로젝트에서 앱 패키지 명은 앞에 파이어베이스 콘솔에서 지정한 com.terry.hellofirebase가 되어야 한다.
안드로이드 프로젝트에는 프로젝트 레벨의 build.gradle 파일과, 앱 레벨의 build.gradle 파일이 있는데
프로젝트 레벨의 build.gradle 파일에 classpath 'com.google.gms:google-services:3.0.0' 를 추가하여 다음과 같이 수정한다.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.google.gms:google-services:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
다음으로, 앱레벨의 build.gradle 파일도 dependencies 부분에 compile 'com.google.firebase:firebase-core:9.4.0' 를 추가하고, 파일 맨 아래 apply plugin: 'com.google.gms.google-services' 를 추가 하여 아래와 같이 수정한다.
MainActivity 클래스에 FirebaseAnalytics 객체를 mFirebaseAnalytics라는 이름으로 정의하고 onCreate메서드에서 FirebaseAnalytics.getInstance(this) 메서드를 이용하여 파이어베이스 애널러틱스 객체를 생성한다.
다음 onSendEvent라는 메서드를 구현한다. 이 메서드는 화면에서 “SEND EVENT”라는 버튼을 누르면 EditText 박스에서 입력된 값으로 SELECT_CONTENT라는 이벤트를 만들어서 파이어베이스 애널러틱스 서버로 보내는 기능을 한다.
컨텐츠 ID,NAME,CATEGORY를 EditText 박스에서 읽어온 후에, Bundle 이라는 객체를 만들어서 넣는다.
파이어베이스 애널러틱스 로그는 이벤트와 번들이라는 개념으로 구성이 된다.
이벤트는 로그인, 컨텐츠 보기, 물품 구매와 같은 이벤트이고, Bundle은 이벤트에 구체적인 인자를 묶어서 저장하는 객체이다. 위의 예제인 경우 SELECT_CONTENTS 라는 이벤트가 발생할때 컨텐츠 ID, 이름(Name), 종류(Category)를 인자로 하여, Bundle에 묶어서 전달하도록 하였다.
Bundle 클래스를 생성한후, bundle.putString(“인자명",”인자값") 형태로 Bundle 객체를 설정한 후에, mFirebaseAnalytics.logEvent(“이벤트명",”Bundle 객체") 메서드를 이용하여 SELECT_CONTENTS 이벤트에 앞서 작성한 Bundle을 통하여 인자를 전달하였다.
앱 개발이 모두 완료되었다. 이제 테스트를 해보자
실행하기
앱을 실행하고 아래와 같이 데이타를 넣어보자
컨텐츠 ID는 200, 컨텐츠 이름은 W, 그리고 컨텐츠 종류는 webtoon으로 입력하였다.
SEND EVENT 눌러서 이벤트를 보내서 파이어베이스 웹콘솔에 들어가서 Analytics 메뉴에 상단 메뉴인 “Events”를 선택하면 처음에는 아무런 값이 나오지 않는다.
앞에서 설명했듯이 파이어베이스 애널러틱스는 아직까지 실시간 분석을 지원하지 않기 때문에 수시간이 지난 후에야 그 값이 반영 된다.
본인의 경우 밤 12시에 테스트를 진행하고 아침 9시경에 확인을 하였더니 아래와 같은 결과를 얻을 수 있었다.
실제로 테스트 시에 select contents 이벤트를 3번을 보냈더니, Count가 3개로 나온다.
그러나 이벤트에 보낸 컨텐츠 ID, 이름 , 분류등은 나타나지 않는다. 기본 설정에서는 이벤트에 대한 디테일 정보를 얻기가 어렵다. 그래서 빅쿼리 연동이 필요한데 이는 후에 다시 다루도록 하겠다.
Dashboard 메뉴를 들어가면 다음과 같이 지역 분포나 단말명등 기본적인 정보를 얻을 수 있다.
이벤트와 이벤트 인자
앞서처럼 이벤트와 인자등을 정해줬음에도 불구하고 대쉬보드나 기타 화면에 수치들이 상세하지 않은 것을 인지할 수 있다. 정확한 데이타를 분석하려면 마찬가지로 정확한 데이타를 보내줘야 하는데, 화면 로그인이나 구매등과 같은 앱에서의 이벤트를 앱 코드내에 삽입해줘야 상세한 분석이 가능하다.
지금까지 간략하게 나마 파이어베이스 애널러틱스의 소개와 예제 코드를 통한 사용 방법을 알아보았다.
모바일 데이타 분석이나 빅데이타 분석에서 가장 중요한 것은 데이타를 모으는 것도 중요하지만, 모아진 데이타에 대한 지표 정의와 그 의미를 파악하는 것이 중요하다. 그래서 다음 글에서는 파이어베이스 애널러틱스에 정의된 이벤트의 종류와 그 의미 그리고, 대쉬 보드를 해석하는 방법에 대해서 설명하고, 그 후에 빅쿼리 연동을 통해서 상세 지표 분석을 하는 방법에 대해서 소개하고자 한다.
앞의 글에서 스트리밍 프로세스의 개념과, 데이타 플로우의 스트리밍 처리 개념에 대해서 알아보았다. 그렇다면 실제로 이를 데이타 플로우를 이용해서 구현을 하기 위해서는 어떤 컴포넌트와 프로그래밍 모델을 사용하는지에 대해서 알아보자.
구글 데이타 플로우 프로그래밍 모델은 앞에서 설명한 바와 같이, 전체 데이타 파이프라인을 정의하는 Pipeline, 데이타를 저장하는 PCollections, 데이타를 외부 저장소에서 부터 읽거나 쓰는 Pipeline I/O, 그리고, 입력 데이타를 가공해서 출력해주는 Transforms , 총 4가지 컴포넌트로 구성이 되어 있다.
이번 글에서는 그 중에서 데이타를 가공하는 Transforms 컴포넌트들에 대해서 알아본다.
Transforms
Transforms는 데이타를 어떻게 가공하느냐에 따라서 다음 그림과 같이 세가지 형태로 분류된다.
Element-Wise
개별 데이타 엘리먼트를 단위로 연산을 수행하는 것을 Element-Wise Transform이라고 한다.
ParDo 함수가 이에 해당하며, 하나의 데이타를 입력 받아서, 연산을 한 후, 하나의 출력을 내보내는 연산이다.
ParDo 함수는 DoFn으로 정의된 연산 로직을 병렬로 여러개의 프로세스와 쓰레드에서 나눠서 처리를 해준다.
DoFn 클래스 는 다음과 같은 포맷으로 정의한다.
static class MyFunction extends DoFn<{입력 데이타 타입},{출력 데이타 타입}>{
@Override
public void processElement(ProcessContext c) {
// do Something
}
}
DoFn 클래스를 상속 받아서 클래스를 정의하고, 클래스 정의시 제네릭 타입 (Generic type)으로, 첫번째는 입력 데이타 타입을 두번째는 출력 데이타 타입을 정의한다.
그리고 processElement 함수를 오버라이드(Override)해서, 이 함수안에 연산 로직을 구현한다.
processElement는 ProcessContext를 인자로 받는데, 이 Context에는 입력 데이타를 포함하고 있다.
입력 데이타를 꺼내려면 c.element()라는 메서드를 이용하면, 입력 데이타 타입으로 정의된 입력 데이타를 꺼낼 수 있다.
데이타를 처리한 다음에 파이프라인상의 다음 컴포넌트로 데이타를 보내려면 c.output ({출력 데이타} ) 형태로 정의를 해주면 된다.
이렇게 정의된 DoFn함수는 ParDo를 이용하여 파이프라인 상에서 병렬로 실행될 수 있다. ParDo는, 파이프라인상에서 .apply 메서드를 이용하여 적용한다.
StringTokenizer st = new StringTokenizer(c.element(),",");
String key = st.nextToken();
String value = st.nextToken();
KV<String,String> outputValue = KV.of(key,value);
c.output(outputValue);
}
}))
Create.of를 이용하여 “Key.Value” 문자열 형태로 데이타를 생성한 후, 이 문자열을 읽어서, DoFn<String,KV<String,String>> 클래스에서 이를 파싱하여, 문자열을 키밸류 데이타형인 KV 데이타 형으로 변환하여 리턴하는 예제이다. 아래 개념도를 보자
입력 값은 String 데이타 타입으로 “Key.Value”라는 형태의 문자열을 받는다.
DoFn에서 처리한 출력 값은 KV 형으로 KV 데이타 타입은 키와 값을 가지고 있는데, 키와 값의 타입도 제네릭 타입으로 키는 String, 값은 String 타입으로 정의하였다. 입력된 “Key.Value” 문자열은 “.” 전후로 분리가 되서, “.” 좌측은 키로, 우측은 값으로 해서, KV에 각각 들어간다.
processElement를 보면, c.element를 이용하여 String 문자열을 꺼낸 후, StringTokenizer를 이용하여 “.”을 분류 문자로 정의해서 파싱한다. 첫번째를 키로 저장하고, 두번째를 값으로 저장한다.
KV<String,String> outputValue = KV.of(key,value)
를 이용하여, KV 객체를 생성한 후, c.output(outputValue); 을 이용하여 다음 파이프라인 컴포넌트로 값을 전달한다.
시스템내에서 수행되는 방법은 다음과 같이 된다. ParDo에 의해서 DoFn 클래스가 여러개의 워커에 의해서 분산 처리가된다.
어그리게이션(Aggregation)
어그리게이션 값을 특정 키 값을 이용하여 데이타를 그룹핑을 하는 개념이다.
이러한 어그리게이션 작업은 내부적으로 셔플링(Shuffling)이라는 개념을 이용해서 이루어지는데, 키별로 데이타를 모으거나 키별로 합산등의 계산을 하기 위해서는, 키별로 데이타를 모아서 특정 워커 프로세스로 보내야 한다.
ParDo를 이용하여 병렬 처리를 할 경우, 데이타가 키값에 상관 없이 여러 워커에 걸쳐서 분산되서 처리되기 때문에, 이를 재 정렬해야 하는데, 이 재 정렬 작업을 셔플링이라고 한다.
아래 그림을 보자, 파이프라인 상에서 첫번째 프로세스를 Worker 1과 Worker 2가 처리를 하였고, 결과는 Key1과 Key2를 키로 가지는 데이타라고 하자, 이를 어그리게이션 하면 아래 그림과 같이 Key1 데이타는 Worker 3로 모이고, Key 2 데이타는 Worker 4로 모인다. 이런 방식으로 셔플링이 이루어진다.
데이타 플로우의 어그리게이션 에는 특정 키별로 데이타를 묶어주는 Grouping과, 특정 키별로 데이타를 연산(합이나 평균을 내는)하는 Combine 두 가지가 있다.
댓글을 달아 주세요