블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

파이어베이스 애널러틱스를 이용한 모바일 데이타 분석 #1-Hello Firebase

조대협 (http://bcho.tistory.com)


얼마전에 구글은 모바일 백앤드 플랫폼인 파이어베이스를 인수하고 이를 서비스로 공개하였다.

파이어 베이스는 모바일 백앤드의 종합 솔루션으로, 크래쉬 리포팅, 리모트 컨피그를 이용한 A/B 테스팅 플랫폼, 클라우드와 자동 동기화가 가능한 리얼타임 데이타 베이스, 사용자 인증 기능, 강력한 푸쉬 플랫폼 다양한 모바일 기기에 대해서 테스트를 해볼 수 있는 테스트랩 등, 모바일 앱 개발에 필요한 모든 서비스를 제공해주는 종합 패키지와 같은 플랫폼이라고 보면 된다. 안드로이드 뿐만 아니라 iOS까지 지원하여 모든 모바일 앱 개발에 공통적으로 사용할 수 있다.



그중에서 파이어베이스 애널러틱스 (Firebase analytics)는 모바일 부분은 모바일 앱에 대한 모든 이벤트를 수집 및 분석하여 자동으로 대쉬 보드를 통하여 분석을 가능하게 해준다.


이 글에서는 파이어베이스 전체 제품군중에서 파이어베이스 애널러틱스에 대해서 수회에 걸쳐서 설명을 하고자 한다.


파이어베이스 애널러틱스

이미 시장에는 모바일 앱에 대한 데이타 분석이 가능한 유료 또는 무료 제품이 많다.

대표적으로 야후의 flurry, 트위터 fabric, 구글 애널러틱스등이 대표적인 제품군인데, 그렇다면 파이어베이스가 애널러틱스가 가지고 있는 장단점은 무엇인가?


퍼널 분석 및 코호트 분석 지원

파이어베이스 애널러틱스는 데이타 분석 방법중에 퍼넬 분석과 코호트 분석을 지원한다.

퍼널 분석은 한글로 깔데기 분석이라고 하는데, 예를 들어 사용자가 가입한 후에, 쇼핑몰의 상품 정보를 보고  주문 및 결재를 하는 단계 까지 각 단계별로 사용자가 이탈하게 된다. 이 구조를 그려보면 깔데기 모양이 되는데,사용자 가입에서 부터 최종 목표인 주문 결재까지 이루도록 단계별로 이탈율을 분석하여 서비스를 개선하고, 이탈율을 줄이는데 사용할 수 있다.

코호트 분석은 데이타를 집단으로 나누어서 분석하는 방법으로 일일 사용자 데이타 (DAU:Daily Active User)그래프가 있을때, 일일 사용자가 연령별로 어떻게 분포가 되는지등을 나눠서 분석하여 데이타를 조금 더 세밀하게 분석할 수 있는 방법이다.


이러한 코호트 분석과 퍼넬 분석은 모바일 데이타 분석 플랫폼 중에서 일부만 지원하는데, 파이어베이스 애널러틱스는 퍼넬과 코호트 분석을 기본적으로 제공하고 있으며, 특히 코호트 분석으로 많이 사용되는 사용자 잔존율 (Retention 분석)의 경우 별다른 설정 없이도 기본으로 제공하고 있다.


<그림. 구글 파이어베이스의 사용자 잔존율 코호트 분석 차트>

출처 : https://support.google.com/firebase/answer/6317510?hl=en

무제한 앱 및 무제한 사용자 무료 지원

이러한 모바일 서비스 분석 서비스의 경우 사용자 수나 수집할 수 있는 이벤트 수나 사용할 수 있는 앱수에 제약이 있는데, 파이어베이스 애널러틱스의 경우에는 제약이 없다.

빅쿼리 연계 지원

가장 강력한 기능중의 하나이자, 이 글에서 주로 다루고자 하는 내용이 빅쿼리 연동 지원이다.

모바일 데이타 분석 서비스 플랫폼의 경우 대 부분 플랫폼 서비스의 형태를 띄기 때문에, 분석 플랫폼에서 제공해주는 일부 데이타만 볼 수 가 있고, 원본 데이타에 접근하는 것이 대부분 불가능 하다.

그래서 모바일 애플리케이션 서버에서 생성된 데이타나, 또는 광고 플랫폼등 외부 연동 플랫폼에서 온 데이타에 대한 연관 분석이 불가능하고, 원본 데이타를 통하여 여러가지 지표를 분석하는 것이 불가능하다.


파이어베이스 애널러틱스의 경우에는 구글의 데이타 분석 플랫폼이 빅쿼리 연동을 통하여 모든 데이타를 빅쿼리에 저장하여 간단하게 분석이 가능하다.

구글 빅쿼리에 대한 소개는 http://bcho.tistory.com/1116 를 참고하기 바란다.

구글의 빅쿼리는 아마존 S3나, 구글의 스토리지 서비스인 GCS 보다 저렴한 비용으로 데이타를 저장하면서도, 수천억 레코드에 대한 연산을 수십초만에 8~9000개의 CPU와 3~4000개의 디스크를 사용해서 끝낼만큼 어마어마한 성능을 제공하면서도, 사용료 매우 저렴하며 기존 SQL 문법을 사용하기 때문에, 매우 쉽게 접근이 가능하다.

모바일 데이타 분석을 쉽게 구현이 가능

보통 모바일 서비스에 대한 데이타 분석을 할때는 무료 서비스를 통해서 DAU나 세션과 같은 기본적인 정보 수집은 가능하지만, 추가적인 이벤트를 수집하여 저장 및 분석을 하거나 서버나 다른 시스템의 지표를 통합 분석 하는 것은 별도의 로그 수집 시스템을 모바일 앱과 서버에 만들어야 하였고, 이를 분석 및 저장하고 리포팅 하기 위해서 하둡이나 스파크와 같은 복잡한 빅데이타 기술을 사용하고 리포팅에도 많은 시간이 소요 되었다.


파이어베이스 애널러틱스를 이용하면, 손 쉽게, 추가 이벤트나 로그 정보를 기존의 로깅 프레임웍을 통하여 빅쿼리에 저장할 수 있고, 복잡한 하둡이나 스파크의 설치나 프로그래밍 없이 빅쿼리에서 간략하게 SQL만을 사용하여 분석을 하고 오픈소스 시각화 도구인 Jupyter 노트북이나 구글의 데이타스튜디오 (http://datastudio.google.com)을 통하여 시작화가 간단하기 때문에, 이제는 누구나 쉽게 빅데이타 로그를 수집하고 분석할 수 있게 된다.

실시간 데이타 분석은 지원하지 않음

파이어베이스 애널러틱스가 그러면 만능 도구이고 좋은 기능만 있는가? 그건 아니다. 파이어베이스 애널러틱스는 아직까지는 실시간 데이타 분석을 지원하고 있지 않다. 수집된 데이타는 보통 수시간이 지나야 대쉬 보드에 반영이 되기 때문에 현재 접속자나, 실시간 모니터링에는 적절하지 않다.

그래서 보완을 위해서 다른 모니터링 도구와 혼용해서 사용하는 게 좋다. 실시간 분석이 강한 서비스로는 트위터 fabric이나 Google analytics 등이 있다.

이러한 도구를 이용하여 데이타에 대한 실시간 분석을 하고, 정밀 지표에 대한 분석을 파이어베이스 애널러틱스를 사용 하는 것이 좋다.


파이어베이스 애널러틱스 적용해보기

백문이 불여일견이라고, 파이어베이스 애널러틱스를 직접 적용해보자.

https://firebase.google.com/ 사이트로 가서, 가입을 한 후에, “콘솔로 이동하기"를 통해서 파이어 베이스 콘솔로 들어가자.

프로젝트 생성하기

다음으로 파이어베이스 프로젝트를 생성한다. 상단 메뉴에서 “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' 를 추가 하여 아래와 같이 수정한다.

apply plugin: 'com.android.application'


android {

  compileSdkVersion 24

  buildToolsVersion "24.0.2"


  defaultConfig {

      applicationId "com.terry.hellofirebase"

      minSdkVersion 16

      targetSdkVersion 24

      versionCode 1

      versionName "1.0"

  }

  buildTypes {

      release {

          minifyEnabled false

          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

      }

  }

}


dependencies {

  compile fileTree(dir: 'libs', include: ['*.jar'])

  testCompile 'junit:junit:4.12'

  compile 'com.android.support:appcompat-v7:24.2.0'

  compile 'com.google.firebase:firebase-core:9.4.0'

}

apply plugin: 'com.google.gms.google-services'



그리고 파이어베이스 콘솔에서 앱을 추가할때 다운된 google-services.json 파일을 app디렉토리에 복사한다.




이 예제의 경우에는 /Users/terrycho/AndroidStudioProjects/HelloFireBase에 프로젝트를 만들었기 때문에,  /Users/terrycho/AndroidStudioProjects/HelloFireBase/app 디렉토리에 복사하였다.


Gradle 파일 수정이 끝나고, google-services.json 파일을 복사하였으면 안드로이드 스튜디오는 gradle 파일이 변경이 되었음을 인지하고 sync를 하도록 아래 그림과 같이 “Sync now”라는 버튼이 상단에 표시된다.


“Sync now”를 눌러서 프로젝트를 동기화 한다.

예제 코드 만들기

이제 안드로이드 스튜디오의 프로젝트 환경 설정이 완료되었다. 이제, 예제 코드를 만들어 보자.

이 예제 코드는 단순하게, 텍스트 박스를 통해서 아이템 ID,이름, 그리고 종류를 입력 받아서, 파이어베이스 애널러틱스에 이벤트를 로깅하는 예제이다.

파이어베이스 애널러틱스 서버로 로그를 보낼 것이기 때문에, AndroidManifest 파일에 아래와 같이  수정하여 INTERNET과 ACCESS_NETWORK_STATE 권한을 추가한다.

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

  package="com.terry.hellofirebase">

  <uses-permission android:name="android.permission.INTERNET" />

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

  <application

      android:allowBackup="true"

      android:icon="@mipmap/ic_launcher"

      android:label="@string/app_name"

      android:supportsRtl="true"

      android:theme="@style/AppTheme">

      <activity android:name=".MainActivity">

          <intent-filter>

              <action android:name="android.intent.action.MAIN" />


              <category android:name="android.intent.category.LAUNCHER" />

          </intent-filter>

      </activity>

  </application>


</manifest>


다음으로 화면을 구성해야 하는데, 우리가 구성하려는 화면 레이아웃은 대략 다음과 같다.



각각의 EditText 컴포넌트는 tv_contentsId, tv_contentsName,tv_contentsCategory로 지정하였다.

위의 레이아웃을 정의한 activity_main.xml은 다음과 같다.


<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  xmlns:tools="http://schemas.android.com/tools"

  android:layout_width="match_parent"

  android:layout_height="match_parent"

  android:paddingBottom="@dimen/activity_vertical_margin"

  android:paddingLeft="@dimen/activity_horizontal_margin"

  android:paddingRight="@dimen/activity_horizontal_margin"

  android:paddingTop="@dimen/activity_vertical_margin"

  tools:context="com.terry.hellofirebase.MainActivity">


  <LinearLayout

      android:orientation="vertical"

      android:layout_width="match_parent"

      android:layout_height="match_parent"

      android:layout_alignParentLeft="true"

      android:layout_alignParentStart="true">


      <TextView

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:textAppearance="?android:attr/textAppearanceMedium"

          android:text="Contents ID"

          android:id="@+id/tv_contetnsId" />


      <EditText

          android:layout_width="match_parent"

          android:layout_height="wrap_content"

          android:id="@+id/txt_contentsId"

          android:layout_gravity="center_horizontal" />


      <TextView

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:textAppearance="?android:attr/textAppearanceMedium"

          android:text="Contents Name"

          android:id="@+id/tv_contentsName" />


      <EditText

          android:layout_width="match_parent"

          android:layout_height="wrap_content"

          android:id="@+id/txt_contentsName" />


      <TextView

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:textAppearance="?android:attr/textAppearanceMedium"

          android:text="Contents Category"

          android:id="@+id/tv_contentsCategory" />


      <EditText

          android:layout_width="match_parent"

          android:layout_height="wrap_content"

          android:id="@+id/txt_contentsCategory" />


      <Button

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:text="Send Event"

          android:id="@+id/btn_sendEvent"

          android:layout_gravity="center_horizontal"

          android:onClick="onSendEvent" />

  </LinearLayout>

</RelativeLayout>


레이아웃 설계가 끝났으면, SEND EVENT 버튼을 눌렀을때, 이벤트를 파이어베이스 애널러틱스 서버로 보내는 코드를 만들어 보자.

MainActivity인 com.terry.hellofirebase.MainActivity 클래스의 코드는 다음과 같다.


package com.terry.hellofirebase;


import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.EditText;

import android.widget.Toast;


import com.google.firebase.analytics.FirebaseAnalytics;


public class MainActivity extends AppCompatActivity {


  // add firebase analytics object

  private FirebaseAnalytics mFirebaseAnalytics;


  @Override

  protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);

      setContentView(R.layout.activity_main);

  }


  public void onSendEvent(View view){

      String contentsId;

      String contentsName;

      String contentsCategory;


      EditText txtContentsId = (EditText)findViewById(R.id.txt_contentsId);

      EditText txtContentsName = (EditText)findViewById(R.id.txt_contentsName);

      EditText txtContentsCategory = (EditText)findViewById(R.id.txt_contentsCategory);


      contentsId = txtContentsId.getText().toString();

      contentsName = txtContentsName.getText().toString();

      contentsCategory = txtContentsCategory.getText().toString();


      Bundle bundle = new Bundle();

      bundle.putString(FirebaseAnalytics.Param.ITEM_ID, contentsId);

      bundle.putString(FirebaseAnalytics.Param.ITEM_NAME, contentsName);

      bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, contentsCategory);

      mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle);


      Toast.makeText(getApplicationContext(), "Sent event", Toast.LENGTH_LONG).show();

  }

}


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 메뉴를 들어가면 다음과 같이 지역 분포나 단말명등 기본적인 정보를 얻을 수 있다.



이벤트와 이벤트 인자

앞서처럼 이벤트와 인자등을 정해줬음에도 불구하고 대쉬보드나 기타 화면에 수치들이 상세하지 않은 것을 인지할 수 있다. 정확한 데이타를 분석하려면 마찬가지로 정확한 데이타를 보내줘야 하는데, 화면 로그인이나 구매등과 같은 앱에서의 이벤트를 앱 코드내에 삽입해줘야 상세한 분석이 가능하다.

이벤트는 https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event 에 정의가 되어 있고, 각 이벤트별 인자에 대한 설명은 https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Param 에 있는데, 이미 파이어베이스에서는 게임이나 미디어 컨텐츠, 쇼핑과 같은 주요 모바일 앱 시나리오에 대해서 이벤트와 인자들은 미리 정의해놓았다.

https://support.google.com/firebase/topic/6317484?hl=en&ref_topic=6386699

를 보면 모바일 앱의 종류에 따라서 어떠한 이벤트를 사용해야 하는지가 정의되어 있다.


또한 미리 정의되어 있는 이벤트 이외에도 사용자가 직접 이벤트를 정의해서 사용할 수 있다.  이러한 이벤트를 커스텀 이벤트라고 하는데 https://firebase.google.com/docs/analytics/android/events 를 참고하면 된다.


지금까지 간략하게 나마 파이어베이스 애널러틱스의 소개와 예제 코드를 통한 사용 방법을 알아보았다.

모바일 데이타 분석이나 빅데이타 분석에서 가장 중요한 것은 데이타를 모으는 것도 중요하지만, 모아진 데이타에 대한 지표 정의와 그 의미를 파악하는 것이 중요하다. 그래서 다음 글에서는 파이어베이스 애널러틱스에 정의된 이벤트의 종류와 그 의미 그리고, 대쉬 보드를 해석하는 방법에 대해서 설명하고, 그 후에 빅쿼리 연동을 통해서 상세 지표 분석을 하는 방법에 대해서 소개하고자 한다.


 

트위터 모바일 SDK 서비스 패브릭에 대한 소개


조대협 (http://bcho.tistory.com)




트위터에서는 2014년 부터, 모바일 생태계 지원을 위해서 다양한 기능을 제공하는 Fabric 서비스를 제공하고 있다. 데이타 분석 및 리포팅, 트위터 연동등 다양한 기능을 제공하고 있는데, 대략적인 프로덕트들에 대한 기능과 특징을 살펴보고자 한다.



Crashlytics - Crash Reporting (https://fabric.io/kits/android/crashlytics)


모바일앱에 대한 크래쉬 내용에 대한 수집 및 분석 기능을 제공한다.  

특이한 사항으로는 크래쉬 분석 뿐만 아니라, 베타 사용자나 테스터들에게 앱을 배포할 수 있는 기능을 제공하고 베타 테스트 사항을 추적할 수 있는 기능을 제공한다.

근래에는 게임 개발 SDK인 Unity를 지원하는 기능이 추가 되었다.

 


Answers - Mobile Analytics Kit (https://fabric.io/kits/android/answers/summary) 


Google Analytics나 Yahoo의 Flurry와 비슷한 앱 모니터링/리포팅 서비스이다. Google Analytics와는 다르게 완전 무료이다. (데이타 Limit가 없다.)

단 타 서비스와 차이점은 복잡한 형태의 분석이 불가능하다 Cohort, Funnel 분석이나 User Path등 복잡한 분석은 불가하고 DAU,MAU,Session등 단순한 분석만 가능하다.


단순하기 때문에 지표 이해가 쉬운것이 장점으로 볼 수 있고, 또 다른 장점은 타 서비스에 비해서 리얼타임이라는 것이다. 대쉬보드의 수치는 20~30초 정도의 지연이 있는 수치로, 실시간 이벤트를 하거나 PUSH에 대한 반응을 바로바로 봐야할때나 TV CF후에 반응등 실시간 반응 분석이 필요할때 유용하게 사용할 수 있다.


정확한 분석을 위해서는 Fabric 하나로만은 불가능하겠지만 실시간성을 지원하는 점을 보면, Fabric + Flurry와 같이 두개의 솔루션을 조합해서 사용하는 것을 고려하는 것이 좋다.


Answers에서 특이한 기능중에 하나는, 트위터의 사용자 정보를 기반으로, Fabric Answer 를 통해서 모니터링 되는 사용자에 대한 특성 파악이 가능하다는 것이다. 트위터는 컨텐츠 및 여러가지 종류의 계정 (스포츠, 코메디 등등)을 운영하고 있기 때문에, 트위터는 트위터 사용자의 특성이 어떤지를 알 수 있고, 이 정보를 바탕으로 Fabric이 연동된 서비스의 각 사용자들의 특성을 파악해줄 수 있기 때문에, 서비스 운영 입장에서 사용자에 대한 인사이트를 제공할 수 있다. 




Digit Kit


Digit Kit는 SMS를 이용한 인증 서비스 이다. SMS를 통해서 인증 번호를 전송해서 본인 여부를 확인하는 서비스인데, 200여개의 국가를 지원하고 있고, 가장 중요한건 무료다!!. 글로벌 서비스를 제공 하는 경우 글로벌 SMS 서비스를 고려해야 하고, 또 그에 대한 금액도 만만하지 않은데, 하나의 서비스로 글로벌 커버를 비용 부담없이 제공하는 것은 활용을 고려해볼만하다고 보다. 향후  Email Verification 서비스도 함께 제공할 예정이다. 




Twitter Kit


Twitter Kit은 트위터 기능을 사용하기 위한 모바일 SDK이다. 특이한 점은 트위터로의 공유하는 GUI등을 SDK로 제공해서 어렵지 않게 트위터로의 공유 기능을 구현할 수 가 있다. 




Curator - Twitter contents curation service


트위터 컨텐츠를 모아서 큐레이션 (기존의 컨텐츠들을 2차 가공하여 새로운 컨텐츠를 만드는 것) 해주는 서비스로, 주로 미디어 서비스나 컨텐츠 공급자, 큐레이터에게 유리한 서비스로 Curator라는 저작툴을 이용하여, 큐레이션할 컨텐츠를 골라서 특정 주제에 해당하는 피드를 만들 수 있다. 아래는 서울의 첫눈이라는 주제로 트윗을 검색한 후에, 이를 골라서 콜랙션을 만드는 저작도구 화면이다. 



다음은 큐레이트된 컨텐츠를 임베딩하기 위해서 퍼블리슁 화면이다. 



쉽게 이해하는 모바일 데이타 분석



조대협(http://bcho.tistory.com)


모바일 서비스 비지니스를 진행함에 있어서 가장 중요한 것중 하나는 지표에 따른 의사 결정과 서비스 개선이다. 이를 위해서, 어떤 지표들이 필요한지 정의하고 어떻게 측정할지에 대한 정확한 이해가 필요한데, 이 글에서는 모바일 서비스 리포팅에 대해 어떤 지표가 있고 어떻게 활용해야 하는지, 그리고 이런 지표를 수집 분석하기 위한 도구들에 대해서 설명하도록 한다.


모바일 서비스에서 단계별 사용자 흐름


먼저 지표를 이해하기 전에, 사용자가 모바일 서비스 가입부터 사용에서 부터 이익을 내줄때 까지 어떤 흐름을 거치는지에 대해서 살펴볼 필요가 있다. 여러 글들이나 서비스들에서 다소 용어 차이는 있지만 대부분 아래와 같이 단계를 정의한다. 





Acquisitions (사용자 획득 단계)


“사용자 획득 단계”는, 사용자가 앱을 설치 하는 단계로 광고/마케팅등을 통해서 사용자가 앱을 인지하고 설치하는 단계인데, 조금 더 세분화 하면, 설치 후 첫번째 실행을 한 단계로 정의하거나 또는 설치 후 회원 가입까지 한 단계를 “사용자가 획득 되었다” 라고 판단할 수 있다.


사용자의 유입은 검색엔지이나 앱스토어의 검색등을 통하거나, TV,온라인 캠페인(인터넷 광고), 오프라인 캠페인등을 통해서 이끌 수 있다. 유입 경로가 다양하기 때문에 모든 경로에 대한 추적은 불가능하지만, 특히 온라인 캠페인(인터넷 광고) (페이스북이나 카톡 등)는 손쉽게 추적이 가능하고 사용자 획득양에 따라서 광고 플랜을 조절할 수 있기 때문에, 이러한 온라인 캠페인은 시작하기 전에 사용자 유입이 비용대비 어떻게 효과가 있는지를 측정할 수 있는 준비 (분석툴등)를 해놓고 시작해야 한다.


Retention (사용자 유지 단계)


마케팅등을 통해서 사용자를 유입시켰으면 이 유입된 사용자를 서비스에 잡아놓아야 하는데, 이를 Retention, 즉 사용자 유지라고 한다. 이 사용자 유지율을 가입한 사용자가 가입한 이후, 얼마나 꾸준히 재 접속을 하는지를 통해서 측정하는 것이 일반적인데, 1일 후 재접속율, 2일..7일 재접속율을 체크하면 된다. 


이 단계에서 이탈을 방지하고 얼마나 사용자를 Lock in 하여 충성도가 높은 사용자층을 유지하는 것이 중요하다.


Engagement (사용자 활동 단계)


사용자가 서비스를 지속적으로 사용하기 시작하면, 서비스와 사용자간의 인터랙션 즉 활동이 시작되는 단계가 된다. 미디어 서비스일 경우 단방향으로 컨텐츠를 보기만 하는 단방향성의 활동보다는 댓글이나 좋아요 버튼등을 통한 양방향 활동등을 유도하여 서비스의 로열티를 높이고, 서비스에 체류하는 시간을 늘려서 장기적으로 수익화할 수 있는 원천으로 삼아야 한다.


Monetize (수익화 단계)


고정 사용자 층이 형성이 되었으면, 이 사용자 층을 이용하여 수익을 창출해야 하는 데, 광고나 게임의 경우 인앱 구매, 쇼핑의 경우 물품의 실제 구매 단계 까지 연결이 되서 최종적으로 수익을 창출하는 단계이다.


사용자의 인터랙션은 앞에서 설명한바와 같이 위의 그림 처럼 깔때기 형태로 이루어지며 최종 수익을 발생하는 사용자를 얼마나 많이 유도 하느냐가 비지니스의 성패가 된다. 


이러한 흐름을 설명하는 것은 보통 모바일 앱 데이타 분석에 있어서 상당히 많은 지표들이 있고, DAU,MAU,Session Time등 각각의 지표만을 모니터링 하고 분석할뿐 전체 지표가 어떻게 연결되는지 연관성에 대한 인사이트가 적은 것이 대부분의 문제라고 생각하기 때문에 사용자의 단계별 활동에 대한 흐름을 설명하였다.


단계별 지표 정의와 의미


이번에는 위에서 서술한 각 단계별로 모니터링 하는 주요 중요 지표에 대해서 알아보도록 하자



Acquisition 


Download

앱을 다운로드해서 설치한 횟수이다. 이때 중요한 것이 이 Download 수와 실제 사용자 수는 일치 하지 않는다는 것이다. 같은 사용자가 기기를 바꿔서 다시 다운로드할 수 도 있고, 여러기기에 다운로드를 할 수 도 있고 혹은 앱을 지웠다가 재 설치할 수 도 있기 때문에 , 다운로드 수와 사용자 수를 혼돈하지 않도록 한다. 이러한 다운로드 수는 별도의 솔루션을 사용하지 않더라도 구글 플레이 스토어나, 애플 앱스토어 등에서 쉽게 모니터링 할 수 있다.



New User

신규 사용자 수이다.  앱을 설치하고 첫번째로 사용하는 사용자의 수로, 실제로 프로모션등으로 인하여 앱을 설치는 하지만, 사용하지도 않고 삭제하는 경우의 수도 많기 때문에, 별도로 측정이 필요하다.


Demographic Info

그외, 사용자에 대한 기본적인 정보를 수집할 수 있는데, 나이, 성별,  지역적인 위치, 사용 단말의 종류, 통신사등 기본적인 인구 통계나 디바이스에 대한 정보를 수집을 통해서 주로 어떤 사용자 층이 서비스를 사용하는지 인지할 수 있다. 



Install tracking

사용자 획득 단계에서 중요한 지표중의 하나가, 이 사용자가 어디를 통해서 들어왔냐는 것이다. 온라인 마케팅을 통해서 들어온건지. 그렇다면 채널이 페이스북인지? 아니면 웹 사이트 광고인지, 어느 웹사이트 인지? 아니면 공유 기능등을 통한 추천으로 들어온것인지 이메일 마케팅을 통해서 앱 인스톨이 유도 된것인지등이 분석이 되어야 한다.

이러한 분석은 안드로이드 앱의 경우 캠페인 관리 기능을 통해서 UTM 정보라는 것을 획득하면, 어느 경로를 통해서 앱 인스톨이 유도 되었는지 추적이 가능하기 때문에, 결과적으로 어느 마케팅 채널을 통해서 사용자 유입이 활발하게 이루어지는지 판단이 가능하고 이를 통해서 효율적인 채널에 마케팅 리소스를 집중할 수 있도록 해준다.


Retension


Retension rate는 신규 사용자의 재 방문율 분석을 통해서 인지할 수 있다. 이런 수치는 Google Analytics나 Yahoo의 Flurry등읗 이용하여 분석이 가능한데, 아래 그림은 Flurry의 Retension 모니터링 화면이다. 


  


가입자가 가입을 한후에, 날짜가 지남에 따라 얼마나 많은 사람이 남아 있는 가를 볼 수 있다. 당연히 Day 0 에는 100% 일테고, 위의 그림을 보면, 1일 차에는 대략 60%의 사용자가 남게 되고, 그후에 40~50% 사용자가 유지되는 것을 볼 수 있다.


Engagement


Engagement 는 서비스에 대한 사용자의 활동량을 측정하는 수치로 서비스의 종류나 특성에 따라 측정해야 하는 수치가 다르다. 예를 들어 신문이나 방송같은 미디어 서비스의 경우 컨텐츠 뷰수가 중요할것이고, 게임같은 경우에는 플레이 시간이나, 레벨업 등이 중요할 것이고, 쇼핑의 경우에는 상품을 보는 수등이 중요할 수 있다.

이런 추가적인 지표는 각 서비스에 맞게 정의하는 것이 중요하지만, 공통적으로 사용할 수 있는 지표를 보면 다음과 같다


User Path

앱 상에서 사용자의 이동 경로로, 메인 화면으로 갔다가 각각의 메뉴로 사용자가 이동하고 각 메뉴별 체류 시간등을 분석해줌으로써 사용자가 주로 어떤 패턴으로 기능을 사용하는지 또한 어떤 기능이 많이 사용되고 안되는지 등에 대해서 분석이 가능하다.



 

Active User

Active User는 단위 시간동안 그 서비스를 사용한 사용자의 수를 뜻한다.

일반적으로 일단위나 주단위, 월단위를 많이 사용하는데 각각을  DAU(Daily Active User), WAU(Weekly Active User), MAU(Monthly Active User)라고 하고 앱의 서비스 규모를 측정하는 가장 일반적인 지표로 많이 사용된다. 


Session

다음으로 중요한 지표중 하나는 세션(Session)인데, 세션은 한명의 사용자가 한번 앱에 접속해서 사용하고 종료할때까지의 기간을 세션이라고 한다. 한명의 사용자가 하루에 여러번 앱을 사용하면 각각이 하나의 세션으로 취급되며, 일반적으로 안드로이드의 경우 하나의 세션을 사용자의 액션이 없을 경우 30분 후에 종료되는 형태로 정의된다. (cf. 웹에서 HTTP Session이 사용자 액션이 없으면 20분 후에 종료되는 것과 같은 종류로 보면 된다) 

이 세션의 수는 일반적으로 현재 앱을 사용하는 동시 접속자 수와 유사하다고 보면 된다. (사용자가 실제 사용을 종료하고도 30분 정도를 동시 사용자로 측정하기 때문에 다소 오차는 있지만, 전체적으로는 동접자 수와 유사하다고 판단한다.)

https://support.google.com/analytics/answer/2731565 는 Google Analytics에서 사용하는 세션의 개념이다.


Session Lenth

한번 접속했을때 사용자가 앱을 사용하는 시간을  Session Length라고 한다. 이 Session Length가 길다는 것은 그만큼 앱을 사용하는 시간이 길다는 의미로 사용자의 활동이 많다고 볼 수 있으나, 앱의 특성에 따라서 Session Length가 가지는 의미는 다르다. 알람 앱같은 경우에는 설정이나 알람이 울릴때만 앱이 사용되기 때문에, Session Length가 길 수 가 없고 짧다. 그래서 Session Length가 긴것 보다는 총  Session의 수가 얼마나 되느냐가 중요한 척도가 된다. 



Viral

근래에 모바일 서비스에서 중요한 지표중의 하나가 바이럴 지표인데, 페이스북과 같은 SNS 서비스를 통해서 공유가 되고, 이 공유를 통해서 들어오는 사용자 유입은 매우 중요하다. 그래서 추가적으로 SNS 매체별 공유 카운트 등을 별도로 추적할 필요가 있다.


Bounce rate

흔히들 놓치는 수치 중에 하나가 이탈율이다. 사용자 Install이 증가함에도 불구하고, 지속적으로 DAU가 늘어나지 않는 이유는 흔히 앱을 설치했다가 삭제하는 이탈 사용자 때문인데, 이러한 이탈율은 Google play store 등에서 쉽게 추적이 가능하다.


<그림. 구글 플레이스토어에서 일일 Uninstall 사용자 추적 예제> 


Loyalty (하루에 몇번 앱을 사용하는가?)

다음으로는 사용자의 충성도를 측정하는 지표인데, 주로 하루에 또는 일주일에 몇번 앱을 사용하는지를 측정한다. 



추가적으로 고민해야 하는 사항들


앞에서 모바일 앱 데이타 분석에서 일반적으로 살펴봐야 하는 지표들에 대해서 알아보았다. 이런 일반 지표 이외에 추가적으로 고려해야 하는 부분은 무엇이 있을까?


코호트  분석 (Cohort analysis)


코호트 분석이란, 분석 결과를 특정 사용자 그룹으로 (나이 또는 성별 등) 나눠서 더 깊게 분석하는 것으로, 집단의 특성에 따른 인사이트를 얻어서 서비스에 반영할 수 있다.

예를 들어서 DAU가 100만으로 꾸준히 유지 되는 서비스가 있다고 가정할때, 이를 연령 층으로 나누었을때 20대 사용자가 증가하고 30대가 감소한다면, DAU 향상을 위해서 30대를 위한 서비스 개선을 생각하거나 또는 서비스의 방향을 20대로 아예 바꿔 버릴 수 도 있다. 앞의 지표를 하나의 숫자로만 보고 분석하면 집단별 특성을 놓칠 수 있지만, 코호트 분석을 통하면 서비스를 사용하는 집단의 특성에 따라 다양한 해석이 가능하기 때문에 그에 따른 다양한 대응역시 가능하게 된다.


퓨넬 분석 (Funnel analysis)


Funnel / 깔때기 분석이라고 하는데, 특정 목표를 달성할때 까지 사용자의 잔존 비율을 단계별로 분석하는 분석 방법이다. 

앞에서 설명한 Acquisitions > Retain > Engagement > Monetization 의 단계도 뒤로 갈수록 사용자가 점점 낮아지는 깔때기 형태로 일종의 퓨넬 분석에 속한다.





위의 그림은 Flurry에서 제공하는 Funnel 분석 결과 화면으로, 자동차를 판매하는 사이트에서, 각 단계별로 넘어가는 사용자 통계로, Choose Car 단계에서 Check In 단계로 넘어갈때, 43.1 %의 사용자만 넘어간것을 볼 수 있다. 다음 단계는 각각 56.4%, 72.6%로 View State 목표를 달성하는 과정중에 사용자가 Check In 단계에서 가장 많이 이탈함을 알 수 있고 이 부분을 우선 개선해야 하는 것을 알 수 있다. 


이러한 퓨넬 분석을 이용하면, 사용자가 최종 목표에 다다르기 까지 어느단계에서 이탈을 하는지 쉽게 판단이 가능하고, 그 단계를 보강함으로써 최종단까지 사용자를 유도하도록 서비스를 개선할 수 있다.

 

지표의 단순화


지금까지 다양한 지표를 살펴봤는데, 비단 모바일 데이타 분석 뿐 아니라 일반적인 데이타 분석에서도 경험상 보면 필요한 핵심 지표의 수는 그리 많지 않다. 오히려 지표가 많을 수 록 혼란이 생기고, 각 지표의 의미를 이해하기 위해서 많은 노력이 들어간다. 그래서 조직에서 그리고 비지니스에서 꼭 필요한 핵심 지표 위주로 지표를 선정하고 집중해서 관리 하는 것이 훨씬 더 효과적이 아닌가 한다.


추가적인 분석 지표


앞서 살펴본 일반적인 지표 이외에도 모바일 서비스에 있어서 중요한 추가 지표들이 있다.


크래쉬 비율


앱의 사용자 유발하고, 앱 평가를 떨어뜨리는 요인중의 하나가  ANR(Application Not responding : 애플리케이션이 멈춰서 응답이 없는 현상) 또는 앱이 비정상 종료 되는 경우인데, 모든 케이스는 아니지만 상당 케이스는 모니터링 도구를 통해서 추적이 가능하다. 구글의 플레이 스토어의 경우에도 개발자 콘솔을 통해서 이 ANR과 DOWN리포팅 및 로그를 받을 수 있고, 아니면 야후 Flurry나 트위터의 Fabric을 통해서도 이 문제에 대한 로그를 수집 및 분석이 가능하다. 




<그림. Fabric 크래쉬 분석 화면>


앱스토어 평가


서비스의 노출을 위한 검색엔진 최적화 만큼이나 중요한것이 모바일 앱에서는 앱스토어 최적화이다. 앱스토어에 올라가는 이미지, 문구, 분류 체계 그리고 검색 노출이 쉽게 하는 기능뿐 아니라, 앱스토어에서 앱에 대한 평점 관리는 대단히 중요한 지표이기 때문에 이 부분 역시 같이 신경써야 한다.



실제 측정을 위한 절차


그러면 이런 지표들을 측정하고 사용하기 위해서는 어떠한 절차를 거쳐야 할까?


정보 모델의 설계


가장 중요한 것은 정보 모델의 설계이다. 서비스 특성을 감안하여 가장 중요한 성장 동력이 되는 지표가 무엇인지, 앞의 퓨넬 모델에서 설명한 사용자의 획득에서 수익 창출 단계까지 이르기 까지 서비스의 특성에 따라서 어떤 지표가 필요한지를 선정하고, 서비스에 맞춰서 각 지표를 정의하는 것이다.


미디어 서비스의 경우 앱 인스톨, 액티브 사용자 비율, 탈퇴 비율등과 같은 정적 지표와

사용자가 메인에서 리스트로 진입해서 컨텐츠를 보고 댓글을 쓰는 동적 이동에 따른 메인 뷰 수, 컨텐츠 뷰수, 체류 시간과 같은 동선에 따른 지표를 정보 모델로 정의할 필요가 있다.


구현 방식 선정


이러한 정보 모델이 정의 되고, 각 대표 지표가 선정이 되었으면, 이를 실제 구현할 수 있는 구현 방법을 결정해야 하는데, 모바일 데이타 분석은 빅데이타 영역에 속하기 때문에 자체 구축을 하려면 하둡이나 스파크같은 복잡한 인프라가 필요하고 대용량 데이타를 저장 및 분석하기 위한 많은 하드웨어와 인력이 필요하다.


근래에는 클라우드 서비스 형태로 제공되는 모바일 앱 분석 서비스들이 많고 광고 플랫폼을 중심으로 앞에서 언급한 구글,야후,트위터들이 무료 분석 플랫폼을 제공하기 때문에 이러한 무료 플랫폼을 이용하는 것도 하나의 방법이 된다. 

개인적으로는 Flurry를 가장 선호하는데, 사용자 수에 대한 제약이 없고 User Path, Funnel 분석등 다양한 기능을 제공한다. Google Analytics의 경우 기능이 막강하고 다양한 커스터마이제이션이 가능은 하지만 사용법 학습등에 많은 노력이 필요하고, 일정 볼륨이 넘어가면 1억원 이상의 비용을 지급하고 유료로 사용해야 하기 때문에 과연 좋은 선택인가에 대해서는 의문이 있다. 




단 이러한 플랫폼의 경우에는 커스터마이징이 어렵고 이로 인하여 대쉬 보드에 원하는 지표를 다 넣을 수 없는 경우가 많기 때문에 만들어놓더라도 각각의 지표가 연결된 의미를 찾지 못해서 무용지물화 되기 쉬운 단점이 있고, 앱스토어나 기타 흩어져있는 시스템들의 정보를 취합하여 보여줄 수 없다.


중간 대안으로는 정보분석 플랫폼을 사용하되, 이러한 분석 플랫폼들은 오픈 API를 제공하고 있고, 앱스토어도 오픈 API를 제공하기 때문에,  이러한 API를 이용하여 여러 소스로 부터 데이타를 모으고, 조직의 데이타 분석 수준이나 뷰에 적절한 대쉬 보드를 직접 구축하면 훨씬 높은 효과를 얻을 수 있다.


이벤트 태그 삽입


구현 방식이 선정되면 앱에서 발생하는 이벤트 (시작, 종료, 메인 페이지 이동, 댓글 등록)를 플랫폼으로 보낼 코드를 삽입하면 된다.


야후 플러리의 경우 간단하게 이벤트 명을 입력하는 것만으로 이벤트를 로깅 할 수 있다.


[Flurry logEvent:@“EVENT_NAME"];


<코드. 야후 플러리 이벤트 로깅 iOS Object C 예제>


이때 솔루션에 따라 이벤트의 개수와 이벤트의 길이에 제약이 있기 때문에, 정보 모델을 설계할때 적절한 이벤트 수를 정하는 것이 중요하다. (플러리의 경우 300개의 이벤트, 이벤트 명은 255자 이하)

이벤트 명을 정의할때는 정보 모델에 따라서 트리 구조로 계층 구조를 갖는게 좋은데 예를 들어


/main

/main/contents/

/main/contents/comment


식의 REST 형식의 리소스 형태를 사용하게 되면, 훨씬 더 직관적으로 이해 쉽다.



맺으며


모바일건 웹이건 근래의 서비스는 경쟁이 심해지고 빠르게 사용자의 니즈를 이해하고 맞춰나가지 않으면 생존하기 힘든만큼 데이타 분석은 선택이 아니라 거의 필수적이다. 


이러한 데이타 분석은 갑자기 튀어난게 아니라 Dataware house, Business Intelligence, OLAP 등으로 예전 부터 전통적으로 존재하고 있는 시스템이고 다만 구현 방식이나 강조되는 포인트들이 다소 변경된것인데, 경험상으로 보면 이런 시스템을 구현하는 데 많은 비용과 노력을 들이지만 100% 잘 사용되는 경우가 드물다. 

 원인을 보면, 시스템을 구축하지만 이 구축된 정보를 얼마나 쉽게 전달할것인가에 대한 고려가 적고 지표에 대한 이해와 시스템 사용 방법에 대한 교육이 없이 한정된 배경 지식만으로 전체 지표를 이해가 불가능 하기 때문이다.

 시스템을 보는 입장에서 최대한 단순하게 만들어야 되는데, 경험상 BI 프로젝트등을 해보면 멋진 대쉬보드를 만들어놓고도 결국 끝에 가서 나오는 말은 액셀로 보내주세요... 이다.

 시스템의 구축이 전체의 30% 이하 정도의 작업이라면 나머지는 필요한 지표의 정의, 정보 모델의 정의, 사용자가 원하는 대쉬보드의 구축, 구성원들에 대한 데이타 분석 및 시스템에 대한 활용 교육이 지속적으로 제공되어야 한다. 큰그림을 이해하지 못한 상태에서 파편만 보다가는 전체 흐름이나 방향을 놓칠 수 있기 때문에 이 부분에 대해서는 몇번을 강조해도 부족함이 없을것이라 본다.  

Continuous Deployment 
(Auto Deployment)


빌드와 테스트까지 자동화 했으면 그 다음 문제는 배포이다.

수동으로 배포하는 경우 한 두개의 서버라면 별 걱정이 없겠지만, 개발,테스트,운영 환경과 같이 여러 환경에 또한 각 환경에 수십대의 서버에 배포를 해야 한다면, 문제는 달라진다. 그래서 요즘에서 CI에 배포의 개념을 더한 CD (Continuous Delivery 또는 Continuous Deployment)라는 개념이 유행하는데, 이는 빌드가 완료된 후, 배포까지 자동화 하는 방법이다.



이런 배포를 지원하는 도구는 여러가지 타입이 있다.

   특정 솔루션에 종속적인 도구

Tomcat이나 WebLogic 같은 WAS의 경우 각 제품에 특화된 배포 도구를 가지고 있다. Tomcat의 경우 Tomcat Client Deployer (http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#Deploying using the Client Deployer Package ) 와 같은 도구가 있는데, Remote에서 war 파일을 배포해줄 수 있는 도구 이다.

이러한 도구들의 특징은 해당 솔루션에 최적화가 되어 있기 때문에, RunTime Deploy나 기타 해당 솔루션에 특화된 기능을 활용할 수 있기 때문에, 안정적인 배포가 가능하다는 장점을 가지고 있다.

그러나 반대로 솔루션에 관련된 애플리케이션 파일만 배포할 수 있다는 단점을 가지고 있다. 무슨 이야기인가 하면, war 파일 이외에, 다른 디렉토리에 configuration 파일을 배포하고 싶을 경우, 이런 파일들은 배포가 불가능하다는 것이다. 또한 여러개의 인스턴스에 동시 배포를 하고 싶을 때, 인스턴스들이 제품에서 제공하는 클러스터링 기능등을 사용하고 있지 않을 경우, 각 인스턴스들을 일일이 각각 배포해야 하는 단점이 있다. 쉽게 말해서 매우 제품에 종속적이라는 것이다.

   Configuration Management

다음으로는 Puppet이나 Chef와 같은 Configuration Management 도구 기반의 배포 방식이 있다. 이러한 도구들은 원래 태생이 Deployment보다는 초기 솔루션을 설치하거나, 다수의 서버나 솔루션에 대한 Configuration 정보를 중앙 관리하기 위해서이다. 이에 비해서 Deploy 과정은 대부분 파일을 복사하고 서버를 restart 시키는 과정 정도의 단순 작업이기 때문에, 만약에 이러한 Configuration Management 인프라를 갖추고 있거나, 또는 배포 과정이 솔루션의 설정을 포함하여 매우 복잡한 경우 일때는 매우 효율적으로 사용될 수 있으나, 반대로 이러한 인프라가 없는 상태에서 단순한 배포만하고자 할 경우에는 오히려 배보다 배꼽이 커질 수 도 있다.

   Remote Shell 기반의 도구

마지막으로, Remote Shell 기반의 배포 도구가 있다. SSH RSH과 같은 명령을 툴로 실행시켜 주는 도구 인데, 파일 복사에서 부터 커맨드 라인에서 입력하는 명령들을 원격으로 실행시켜 준다.

솔루션에 종속적이지 않으며 또한 자유도가 높으며 사용이 매우 편리하다.

Python 으로 된 도구로는 Python Fabric이라는 도구가 있고, Ruby쪽에서는 Capistrano라는 도구가 있다.

Case Study

필자의 경우 클라우드 프로젝트 이전에만 해도, 환경 자체가 그리 크지 않았기 때문에, 웹로직이나 Tomcat의배포 툴을 사용해서 배포를 진행했었다. 클라우드 환경 기반에서 프로젝트를 진행하고 또한 진행하는 프로젝트의 규모가 커짐에 따라서 이러한 배포 자동화가 꼭 필요하게 되었는데, 이 배포는 Configuration Deployment 두 가지로 나눠서 생각해볼 수 있다.

애플리케이션을 배포하기 전에 먼저 OS Tomcat과 같은 솔루션을 설치 하는 Configuration, 그 다음이 이 환경 위에 애플리케이션을 배포하는 Deployment이다.

Configuration의 경우에는 Puppet이나 Chef를 도입하고 싶었으나, 팀의 규모와 시간 관계상 도입이 어려웠고, 환경의 복잡도가 낮아서 별도의 Configuration management 도구는 도입하지 않기로 결정하였다.

대신 OS Tomcat Pre-install된 표준 VM 이미지를 만들어 놓고, 배포가 필요할때 마다 이 이미지를 Loading한 후에, 애플리케이션을 Deployment 하는 형태를 사용하였다.

이 방식은 표준 이미지를 만들어 놓고 계속 재 사용하기 때문에, 관리가 쉽지만 반대로 Configuration을 변경하고자 할 때, 이미 배포된 이미지들에 대한 Configuration을 일일이 다시 변경해야 하는 단점이 있다. (어느 정도 규모가 되면 Configuration Management 도구로 넘어가는 것이 좋은듯 하다.)

Fabric을 이용한 배포

그러면 Fabric을 이용한 Tomcat 애플리케이션에 대한 간단한 배포 시나리오를 살펴보도록 하자.

구성은 아래와 같다. Load Balancer 아래에 N개의 Tomcat 인스턴스들이 연결되어 있는 구조 이고, 배포는 다음과 같은 순서를 따르도록 한다.

   먼저 배포하고자 하는 Tomcat 인스턴스를 Load Balancer에서 제외한다.

   다음으로 배포하고자 하는 인스턴스를 Stop한다.

   배포하고자 하는 war 파일을 해당 Tomcat 인스턴스에 복사한다.

   그리고 해당 Tomcat 인스턴스를 리스타트한다.

   위의 1)~4) 과정을 다른 인스턴스에도 반복한다.



이 배포 방식은 간단하기는 하지만, 하나의 서비스내에서 배포 과정중에, 배포가 완료된 인스턴스와 배포 예정인 인스턴스에 애플리케이션이 다르기 때문에, 애플리케이션 변경이 많은 경우에는 적용하기가 어렵다 . 대규모 변경이 있는 경우에는 전체 클러스터를 내렸다가 전체 배포 후 서비스를 다시 시작하는 방식을 사용해야 하는데 이 경우에는 배포 중에 서비스에 대한 순간적인 정지가 발생할 수 있다.

무정지 배포 아키텍쳐

이런 문제를 해결 하기 위해서 일부 자바 기반의 application server의 경우 runtime redeployment (시스템을 운영중에, 정지없이 프로그램을 변경하는 행위로, 일부 자바 기반의 application server에서는 WAR와 같은 웹모듈이나, EJB 같은 모듈을 시스템을 무정지 상태로 재 배포 할 수 있는 기능을 제공한다.) 를 제공하는 제품들이 많다. redeployment 의 원리는 새로운 application load하고, classloader reload하는 형식인데, classloader reload이 위험도가 높은 작업이기도 하고, application을 작성할때, redeploy를 고려하지 않은 경우 정상적으로 runtime redeploy가 되지 않는 경우가 많다. 가장 확실한 redeploy 기법은 application server를 정지시킨후, 재배포한후에 restart하는 것이 가장 안정적이다. 이렇게 restart기반으로 redeploy를 할때, 시스템을 정지 상태를 최소화는 구조를 무정지 배포 아키텍쳐라고 하는데, 구조는 다음과 같다.




application server를 두개의 클러스터 그룹으로 나눈후, 각 클러스터 앞에 reverse proxy를 각각 배치 시킨다. 그리고 reverse proxy 앞에는 L4 스위치를 둬서 각 클러스터로 load balancing을 할 수 있도록 한다.

배포를 할 때는 Cluster A 앞에 있는 reverse proxy를 정지 시킨다. 이렇게 하면, 앞단의 L4 로드 밸런서에서 Cluster A request를 보내지는 않으나, Cluster A 자체는 살아 있다. 그 후에 Cluster A의 각 인스턴스에 애플리케이션을 재 배포 한후,Cluster A reverse proxy를 재기동 시킨다. 마찬 가지 방법으로 Cluster B에도 같은 방법으로 redeploy를 수행한다.

이 구조를 택하면 전체 서비스 중지 없이 그리고 애플리케이션 변화에 대해서 일관성 있게 한꺼번에 재 배포가 가능하다.

Fabric을 이용하여 AWS Tomcat war 파일 배포 하기

그러면 실제로 Fabric을 이용해서 어떻게 배포를 할 수 있을까?

다음은 아주 간단한 Fabric을 이용한 배포 스크립트 이다.

순서는 tomcat stop > copy war > start 와 같다. EC2상에서 pem (SSH)를 이용하여, 두대의 Host deploy하는 스크립트이다.

#fabfile.py

from fabric.api import run,env,execute,task

from fabric.operations import local,put

 

def tomcat_cluster():

        env.user ='root'

        env.hosts=['host1.server.com','host2.server.com'] # list of server setting

        env.key_filename='~/pem/pemfile.pem' # pem file

 

def hostname():

        run('uname -a')

 

def start():

        run('/etc/init.d/tomcat6 start')  # tomcat instance stop

 

def stop():

        run('/etc/init.d/tomcat6 stop') # tomcat instance stop

 

def copy():

        put('./dummy.war','/root/war') # file copy

 

def deploy():

        execute(stop)

        execute(copy)

        execute(start)

 

해당 파일을 fabfile.py에 저장후에

%fab tomcat_cluster deploy

명령어로 실행을 하면 아래와 같은 순서로 배포가 진행된다.

host1.stop()

host1.copy()

host1.start()

host2.stop()

host2.copy()

host2.start()

 

위의 예제는 Fabric의 설명을 하기 위한 아주 간단한 예제로, 필요에 따라서 수정해서 사용하기 바란다.

앞의 예제에서는 간단하게 war 파일만을 복사하는 형태로 배포 스크립트를 작성하였지만, maven 설명할때 언급했던 것 처럼, 기타 Configuration 파일을 함께 배포하고, roll back이나 버전 관리가 용이하게하기 위해서 rpm 형태로 배포하는 것을 권장한다. 또한 rpm 파일을 관리하기 위해서 내부적으로 자체 yum repository를 만들어서 관리하는 것이 좋다.

배포에서 고민해야 할것 들

배포주기

근 몇 년전만 해도, 배포는 몇 달간의 개발이 끝나면 테스트를 거쳐서 특정한 날짜를 잡아서 대규모 배포를 형태가 일반적이었다.

그러나 근래에는 전체적인 IT 트렌드가 SNS와 같은 B2C 서비스가 중심이 되면서, 경쟁 서비스에 비해서 좋은 서비스를 빠르게 제공하기 위해서 업데이트 주기가 매우 짧아지고 있다. 이런 이유에서 배포도 자동화가 필요하게 되었고 Continuous Delivery와 같은 개념이 근래에 유행하게 된것일 수도 있는데, SNS 서비스의 경우 빠르면 하루 단위로 배포하는 경우 까지 있다.

배포 주기가 짧은 경우에는 몇 가지 더 고려할 사항이 있는데, 배포는 코드 개발보다는 인프라 관리나 빌드에 관련된 부분이 많다. 그래서 배포의 주체는 이런 운영 주체가 되는 경우가 일반적인데, 배포시 문제가 생기는 경우가 있을 시에는 개발팀의 도움이 필요하고, 배포가 정상적으로 되었을 경우에는 개발팀으로 부터의 확인등이 필요하기 때문에 조직 구조상 운영팀과 개발팀이 분리된 조직에서는 잦은 배포가 여러가지로 어려운점이 많다. 그래서 근래에는 이런 개발과 운영 조직을 합쳐서 개발팀을 운영하는 DevOps (Deveopment + Operation)형태의 조직구조로 전환하여 개발,배포,운영을 통합하여 관리 하는 쪽으로 이동하고 있다.

이 경우 단순히 조직을 합치는 것뿐만 아니라 개발자에게는 인프라나 운영에 대한 이해 능력을 그리고 운영팀에는 개발에 대한 어느정도 선까지의 능력을 요구하게 되고 업무 프로세스등의 변화가 필요하기 때문에 조직을 융합시키는 차원이 아니라 조금 더 높은 수준의 접근이 필요하다.  

수동 배포

운영 환경 배포는 반드시 수동으로 하는 것을 권고한다.

지금까지 자동으로 배포하는 방법을 설명해놓고, 왠 갑자기 수동 배포를 언급하는가 싶을 수도 있을텐데, 이유는 다음과 같다.

배포는 앞서 본 것과 같이 쉘 명령등을 수행해서 여러가지 명령 (Shutdown, Copy, Restart)을 동시에 여러 서버에 수행한다. 즉 중간에 에러가 날 가능성이 매우 높다.

그래서 배포 작업을 수행할때는 반드시 사람이 지켜보면서 배포 스크립트를 수행하는 것이 좋다. 개발환경이나 QA 환경 같은 경우에는 거의 업무 시간에 빌드를 하면서 배포가 수행이 되기 때문에, 배포 오류가 났을 경우에는 사람이 인지하기가 쉽고, 에러가 났을때 서비스에 직접적인 영향을 주지는 않는다. 그래서 개발이나 QA 환경 같은 경우에는 사람이 지켜보지 않고, CI 프로세스의 일부로 빌드 테스트가 끝나면 자동으로 배포를 하도록 해도 된다.

그렇지만 운영 환경의 경우에는 서비스에 직접적인 영향을 주기 때문에, 반드시 사람이 지켜보면서 수동으로 배포를 시작 및 모니터링 하도록 하는 것이 좋다.

배포 roll back

서비스에 대한 배포시, 테스트를 아무리 잘했다하더라도, 에러가 발생할 수 있다.

에러가 발생하였을 때는 이전의 버전으로 신속하게 roll back할 수 가 있어야 하는데, 이렇게 하기 위해서는 애플리케이션의 이전 버전을 반드시 저장하고 있어야 하고, 배포 스크립트 역시 예전 버전을 다시 배포할 수 있는 기능을 구현해야 한다.

릴리즈 노트

마지막으로 배포가 끝나면 반드시 릴리즈 노트를 작성 및 함께 배포하는 것이 좋다.

배포란 개발이나 운영이 주로 주도하는 작업이기 때문에, 비지니스 쪽에서 필요한 기능 변화에 대한 릴리즈 노트의 중요성을 잃어 버리는 경우가 많은데,  서비스가 변경이 되었을때, 어떠한 기능이 추가 되었는지, 그리고 어떠한 버그가 FIX가 되었는지를 사용자에게 알려줄 필요가 있으며, 특히 서비스를 판매나 영업하는 입장에서는 어떤 변화가 있었는지를 확인하는 것이 중요하기 때문에, 이 부분을 반드시 챙기도록 한다.

릴리즈 노트는 배포 되는 대상 (독자)에 따라서 다르게 작성되야 하는데,

내부 릴리즈 노트는 다음과 같은 내용이 포함되는 것을 권고한다.

Ÿ   릴리즈 버전, 날짜 및 빌드 넘버

Ÿ   새로운 기능 및 설명

Ÿ   버그 number 및 버그 수정 내용

또는 JIRA와 같은 Tak Management 도구를 사용하는 경우, JIRA에 등록된 기능이나 Bug 수정 내용을 릴리즈 시기에 자동으로 JIRA로 부터 생성해 낼 수 있다. (JIRA에서 릴리즈 노트 생성하기 https://confluence.atlassian.com/display/JIRA/Creating+Release+Notes)

만약 서비스나 제품 사용자를 대상으로 하는 경우, 위의 릴리즈 노트의 내용을 사용할 수 도 있지만, 조금 더 직관적이고 읽기 쉬운 형태로 릴리즈 노트를 작성하는 것이 좋다.

다음은 몇몇 잘 정의된 릴리즈 노트의 샘플이다.

Ÿ   안드로이드 릴리즈 노트 : http://developer.android.com/sdk/RELEASENOTES.html

Ÿ   Fire Fox 릴리즈 노트 http://www.mozilla.org/en-US/firefox/23.0.1/releasenotes/

Ÿ   Maven 릴리즈 노트 http://maven.apache.org/release-notes-all.html

릴리즈 노트는 청중들에게 이번 릴리즈 기능의 변경 사항을 제대로 알리기 위함이다. JIRA와 같은 시스템의 기능을 이용하건, 아니면 일일이 손으로 새로 쓰건간에 반드시 보는 사람이 어떤 변화가 있었는지 쉽게 이해할 수 있는 형태라야 한다.

http://pds3.egloos.com/pds/200611/26/16/capistrano_niceview.pdf 여기 정리가 잘되어 있네요.

Fabric과 비슷하게 SSH 기반으로 작동하는 도구입니다.

위의 PT에 스크립트 작성하는 전체적인 흐름이 잘 정의 되어 있어서, Fabric 사용할때도 비슷하게 참조할 수 있겠습니다.


Fabric을 이용한 간단한 Tomcat deploy

프로그래밍/Python | 2013.01.29 18:46 | Posted by 조대협

Tomcat war deploy시, 가장 이상적인 방법은 

tomcat stop > copy war > start 순서이다.

아래는 간단하게 Python 기반의 Fabric을 이용하여, EC2상에서 pem (SSH)를 이용하여, Host들에 deploy하는 과정을 정의함


#fabfile.py

from fabric.api import run,env,execute,task

from fabric.operations import local,put


def tomcat_cluster():

        env.user ='root'

        env.hosts=['host1.server.com','host2.server.com'] # list of server setting

        env.key_filename='~/pem/pemfile.pem' # pem file


def hostname():

        run('uname -a')


def start():

        run('/etc/init.d/tomcat6 start')  # tomcat instance stop


def stop():

        run('/etc/init.d/tomcat6 stop') # tomcat instance stop


def copy():

        put('./dummy.war','/root/war') # file copy


def deploy(): 

        execute(stop)

        execute(copy)

        execute(start)

해당 파일을 fabfile.py에 저장후에

%fab tomcat_cluster deploy

해주면 아래와 같은 순서로 수행됨

host1.stop()

host1.copy()

host1.start()

host2.stop()

host2.copy()

host2.start()


기타 참고할만한 명령어
- sudo
- get : 파일 copy 해옴 
- local : local machine에서 명령어 수행
- with cd('{dir}') : 특정 디렉토리를 베이스로 명령어등을 수행할때 사용


※ 참고 : 외부에서 Host 명을 dynamic하게 받는 방법

--------------------------------

외부에서 host list 받는 방법

def deploy(lookup_param):

    # This is the magic you don't get with @hosts or @roles.

    # Even lazy-loading roles require you to declare available roles

    # beforehand. Here, the sky is the limit.

    host_list = external_datastore.query(lookup_param)

    # Put this dynamically generated host list together with the work to be

    # done.

    execute(do_work, hosts=host_list)

    

실행할때는

$ fab deploy:app


------ 또는 -----------

# Marked as a publicly visible task, but otherwise unchanged: still just

# "do the work, let somebody else worry about what hosts to run on".

@task

def do_work():

    run("something interesting on a host")


@task

def set_hosts(lookup_param):

    # Update env.hosts instead of calling execute()

    env.hosts = external_datastore.query(lookup_param)

    

$ fab set_hosts:app do_work

One benefit of this approach over the previous one is that you can replace do_work with any other “workhorse” task:


$ fab set_hosts:db snapshot

$ fab set_hosts:cassandra,cluster2 repair_ring

$ fab set_hosts:redis,environ=prod status


Python Fabric Install

프로그래밍/Python | 2013.01.28 18:55 | Posted by 조대협

AWS EC2 (Amazon Linux 기준)


1. Python install (dev package로 설치)

(반드시 dev package가 설치되어 있어야지, pycrypto 설치시 에러가 나지 않음. pycrptyo는 encryption 관련 라이브러리로 C 라이브러리를 사용하는데, 컴파일중, python.h를 사용한다. 이 헤더 파일은 dev package안에 포함되어 있음)


- yum install python-devel 


2. pip install

$ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py

$ [sudo] python get-pip.py


3. gcc가 인스톨 (pycrypto 설치를 위해서 필요함) 

yum install gcc


4. fabric install


pip install pycrypto fabric


5. 설치 확인


from fabric.api import run


def host_type():

    run('uname -s')