ݺߣ

ݺߣShare a Scribd company logo
로그 기깔나게 잘 디자인하는 법
흔히 만나는 실제 사례를 중심으로
라인게임즈
백정상
로그를 통해
• 비즈니스 의사결정에 필요한
• 객관적이고
• 명확한
• 지표를 얻을 수 있음
하지만 로그 기록은
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법
로그 대충 쌓으면
• 지표가 부정확하거나 생성 불가능
• 잘못된 결정
• 운영 실수
• 유저 이탈
• 매출 하락
• 인센티브 못 받음
• 집 대출금은 어쩌지??
로그 기깔나게 잘 디자인하는 법
흔히 일어나는 사례 : #1
뭘 봐야할 지 애매해서 일단 뭐
든 쌓아봤어요
로그 기깔나게 잘 디자인하는 법
보고싶은 지표를 먼저 명확하게 설정하자
예) 보고싶은 지표
• DAU (Daily Active Users)
• 일자/레벨 별 스테이지 클리어 정보
• 일자 별 골드 획득 소비량 / 획득 사유
DAU
• 이벤트 : 유저 로그인
• 유저 식별자
• 기기 : 광고 아이디 (ADID, IDFA)
• 유저 : 유저 아이디 (Nickname, etc.)
• 기기 정보
• 모델명, OS, 언어, 스토어 타입 등
• 기타
• 연령, 성별
• 유저 레벨
• 타임스탬프
일자 / 레벨 별 스테이지 클리어
• 이벤트 : 스테이지 클리어
• 유저 식별자
• 스테이지 인덱스
• 스테이지 클리어 여부
• 플레이 한 캐릭터 정보
• 유저 레벨
• 타임스탬프
일자 / 레벨 별 골드 획득 및 사유
• 이벤트 : 골드 획득
• 유저 식별자
• 유료 / 무료 재화 변동수치
• 유료 / 무료 재화 변동 결과
• 유저 레벨
• 재화 획득 사유
• 타임스탬프
로그 기깔나게 잘 디자인하는 법
어라 이런 것도 볼 수 있네?
• 시간대별 로그인 횟수
• 유저들이 가장 많이 플레이하는 캐릭터
• 로그인 횟수와 스테이지 클리어 간의 상관관계
• 스테이지별 골드 획득량
• 유저 레벨 별 로그인 횟수
로그를 제대로 디자인하면
보고 싶은 지표에 대한 아이디어가 새록새록
로그를 디자인하는 시점
• 앱 릴리즈 전
• 릴리즈 전 최종 기능 확정
• 확정된 기능에 대한 지표 확정
• 지표에 필요한 로그 수집
• 앱 릴리즈 후
• 업데이트 기능 기획 시점 지표 확정
• 지표에 필요한 로그 수집
잘 디자인 된 로그는 기록하기 편합니다
흔히 일어나는 사례 : #2
로그인 해야 로비에 들어가니까,
로비에 들어갈 때 로그인 로그를
찍었어요
근데 튜토리얼 지나야 로비에
들어가긴 해요
로그인
튜토리얼
진행
광고 시청 로비 입장
오 이 게임 재미있네?
내 스타일이야 좋았으~
한번 달려본다!
로그인 기록 시점
기록
로그인
튜토리얼
진행
광고 시청 로비 입장
아이고 애미야!
돈 준다길래 시키는 대로 했더니
이상한 게 켜진다~
로그인 기록 시점
이탈
정확한 로그의 기준을 설정
• 앱 실행 - 로그인
• 액티브 유저로 볼 수 있음
• 앱 실행 – 로그인 – 튜토리얼 – 로비
• 좀 더 깊이 플레이 한 유저
• 인게이지드 유저로 볼 수 있음
• 다시 로그를 심어봐야…
• 전체 기간 액티브 유저는 확인 불가
로그가 정확히 쌓이는지 매번 검증
• 앱 릴리즈 전 / 기능 업데이트 시
• QA 시점에 수집된 로그 검증
• 검증 안 해서 이상한 데이터 쌓이면
• 무엇이 오염된 것인지 정확하게 구분하기 진짜 어려움
• 한번 오염된 로그는 전체 로그의 효용가치를 파괴
정확하게 기록된 로그는 귀한 자원이 됩니다
흔히 일어나는 사례 : #3
리스펀스 저장하면 로그 아니
에요?
용량 줄이려고 JSON 이차원 배
열에 값 밀어 넣었어요
예) 스테이지 클리어 시 아이템 획득
{
user_id:”hackest”,
stage_id:1
is_clear:1
play_char_id:3920,
user_level:11,
ts:”2017-10-13 07:00:00.392Z”,
rewards:[[0,15,300], [1,20802,1500]]
}
예) 스테이지 클리어 시 아이템 획득
{
user_id:”hackest”,
stage_id:2
is_clear:1
play_char_id:3920,
user_level:11,
ts:”2017-10-13 07:11:30.392Z”,
rewards:[[3,15,3], [12,2082,1], [0,15,400]]
}
쿼리를 작성해보려고 하니
SELECT user_id, rewards…
보상 아이템 위치가 계속 바뀌네???
WITH temp_stage_reward_item AS (SELECT …)
보상 아이템 갯수가 가변이네???
… json_extract_array_element_text(’rewards', pos)…
엄청나게 느리네???
파서 작성해야 함
def process(record):
parsed = {‘user_id’:record.user_id, ‘stage_id’:record.stage_id …}
parsed[‘rewards’] = []
for reward in rewards:
parsed.rewards.push(
{‘type’:reward[0], ‘id’:reward[1], ‘value’:reward[2]}
)
log_writer.write(parsed)
이렇게 파서 짜면 되지 않나요?
• 되긴 함
• 하지만 로그 종류가 200여 가지라면
• 파서 짜고 검증하는데 시간 너무 오래 걸림
• 하루에 10억 행이 쌓인다면
• 대부분 파서는 복잡한 일을 하고
• 로그 스트림에 사용되는 워커 스케일 업 요구
예제 개선
{
user_id:”hackest”,
stage_id:1
is_clear:1
…
rewards:[
{type:0, id:15, value:300},
{type:1, id:20802, value:1500}
]
}
데이터는 테이블 형태로 기록하자
• 대부분의 빅데이터 솔루션은 스키마 정의만 해주면
• SQL 질의가 가능
• 행/열 형태로 저장되는 게 제일 좋음
• CSV
• Key-value paired JSON Object
용량 및 저장비용 이슈
• 좋은 압축 알고리즘 적용하자
• Gz, lzo, zstd, parquet
• 클라우드 스토리지는 비싸지 않음
• S3 1TB 저장비용 = 약 월 $25
• 스탠다드, 스탠다드-IA
흔히 일어나는 사례 : #4
로우 데이터를 레드시프트에
다 넣어요
1TB 노드 2개 쓰는데 하루에
100기가씩 쌓여요. 어떡하죠?
그래도 되긴 하는데…
• 레드시프트는 2PB까지 저장 가능
• 하지만 꺼둘 수가 없음
• 그 로그를 과연 상시 쿼리할까?
• 의도 이상으로 컴퓨팅 비용이 너무 높음
방안
• 핫 / 콜드 데이터를 구분
• 핫 : 데이터 분석가가 주로 쿼리 날리는 데이터
• 콜드 : 1년에 한번 쿼리 할까 말까 한 데이터
• 핫 데이터는 데이터 웨어하우스에
• 콜드 데이터는 저렴한 스토리지에
• 콜드 데이터 검색은 빅쿼리 / 아테나 /프레스토로
핫 데이터를 더 정제하자
• Star / Snowflake Schema
• Fact, Dimension으로 디자인
• 데이터 최적화
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법
데이터 워크플로우를 관리하자
• 정제 작업은 데이터 워크플로우 툴을 사용
• 정제한 데이터만 데이터 웨어하우스에 저장
• 노드 / 비용 절감
• 쿼리 퍼포먼스 향상
로그 기깔나게 잘 디자인하는 법
로그 기깔나게 잘 디자인하는 법
정리
• 보고싶은 지표를 명확히 설정하고
• 기록할 데이터의 형식과 시점을 매번 검증하고
• 테이블 형태로 기록해주시고
• 핫 / 콜드 데이터 잘 분리해주시고
• 데이터 워크플로우 잘 관리해주시면
• 어느 플랫폼에서나
• 데이터 분석 쉽고 빠르게 시작하실 수 있습니다
끝
jsbaek @ line.games

More Related Content

로그 기깔나게 잘 디자인하는 법

  • 1. 로그 기깔나게 잘 디자인하는 법 흔히 만나는 실제 사례를 중심으로 라인게임즈 백정상
  • 2. 로그를 통해 • 비즈니스 의사결정에 필요한 • 객관적이고 • 명확한 • 지표를 얻을 수 있음
  • 7. 로그 대충 쌓으면 • 지표가 부정확하거나 생성 불가능 • 잘못된 결정 • 운영 실수 • 유저 이탈 • 매출 하락 • 인센티브 못 받음 • 집 대출금은 어쩌지??
  • 10. 뭘 봐야할 지 애매해서 일단 뭐 든 쌓아봤어요
  • 12. 보고싶은 지표를 먼저 명확하게 설정하자
  • 13. 예) 보고싶은 지표 • DAU (Daily Active Users) • 일자/레벨 별 스테이지 클리어 정보 • 일자 별 골드 획득 소비량 / 획득 사유
  • 14. DAU • 이벤트 : 유저 로그인 • 유저 식별자 • 기기 : 광고 아이디 (ADID, IDFA) • 유저 : 유저 아이디 (Nickname, etc.) • 기기 정보 • 모델명, OS, 언어, 스토어 타입 등 • 기타 • 연령, 성별 • 유저 레벨 • 타임스탬프
  • 15. 일자 / 레벨 별 스테이지 클리어 • 이벤트 : 스테이지 클리어 • 유저 식별자 • 스테이지 인덱스 • 스테이지 클리어 여부 • 플레이 한 캐릭터 정보 • 유저 레벨 • 타임스탬프
  • 16. 일자 / 레벨 별 골드 획득 및 사유 • 이벤트 : 골드 획득 • 유저 식별자 • 유료 / 무료 재화 변동수치 • 유료 / 무료 재화 변동 결과 • 유저 레벨 • 재화 획득 사유 • 타임스탬프
  • 18. 어라 이런 것도 볼 수 있네? • 시간대별 로그인 횟수 • 유저들이 가장 많이 플레이하는 캐릭터 • 로그인 횟수와 스테이지 클리어 간의 상관관계 • 스테이지별 골드 획득량 • 유저 레벨 별 로그인 횟수 로그를 제대로 디자인하면 보고 싶은 지표에 대한 아이디어가 새록새록
  • 19. 로그를 디자인하는 시점 • 앱 릴리즈 전 • 릴리즈 전 최종 기능 확정 • 확정된 기능에 대한 지표 확정 • 지표에 필요한 로그 수집 • 앱 릴리즈 후 • 업데이트 기능 기획 시점 지표 확정 • 지표에 필요한 로그 수집
  • 20. 잘 디자인 된 로그는 기록하기 편합니다
  • 22. 로그인 해야 로비에 들어가니까, 로비에 들어갈 때 로그인 로그를 찍었어요
  • 23. 근데 튜토리얼 지나야 로비에 들어가긴 해요
  • 24. 로그인 튜토리얼 진행 광고 시청 로비 입장 오 이 게임 재미있네? 내 스타일이야 좋았으~ 한번 달려본다! 로그인 기록 시점 기록
  • 25. 로그인 튜토리얼 진행 광고 시청 로비 입장 아이고 애미야! 돈 준다길래 시키는 대로 했더니 이상한 게 켜진다~ 로그인 기록 시점 이탈
  • 26. 정확한 로그의 기준을 설정 • 앱 실행 - 로그인 • 액티브 유저로 볼 수 있음 • 앱 실행 – 로그인 – 튜토리얼 – 로비 • 좀 더 깊이 플레이 한 유저 • 인게이지드 유저로 볼 수 있음 • 다시 로그를 심어봐야… • 전체 기간 액티브 유저는 확인 불가
  • 27. 로그가 정확히 쌓이는지 매번 검증 • 앱 릴리즈 전 / 기능 업데이트 시 • QA 시점에 수집된 로그 검증 • 검증 안 해서 이상한 데이터 쌓이면 • 무엇이 오염된 것인지 정확하게 구분하기 진짜 어려움 • 한번 오염된 로그는 전체 로그의 효용가치를 파괴
  • 28. 정확하게 기록된 로그는 귀한 자원이 됩니다
  • 31. 용량 줄이려고 JSON 이차원 배 열에 값 밀어 넣었어요
  • 32. 예) 스테이지 클리어 시 아이템 획득 { user_id:”hackest”, stage_id:1 is_clear:1 play_char_id:3920, user_level:11, ts:”2017-10-13 07:00:00.392Z”, rewards:[[0,15,300], [1,20802,1500]] }
  • 33. 예) 스테이지 클리어 시 아이템 획득 { user_id:”hackest”, stage_id:2 is_clear:1 play_char_id:3920, user_level:11, ts:”2017-10-13 07:11:30.392Z”, rewards:[[3,15,3], [12,2082,1], [0,15,400]] }
  • 34. 쿼리를 작성해보려고 하니 SELECT user_id, rewards… 보상 아이템 위치가 계속 바뀌네??? WITH temp_stage_reward_item AS (SELECT …) 보상 아이템 갯수가 가변이네??? … json_extract_array_element_text(’rewards', pos)… 엄청나게 느리네???
  • 35. 파서 작성해야 함 def process(record): parsed = {‘user_id’:record.user_id, ‘stage_id’:record.stage_id …} parsed[‘rewards’] = [] for reward in rewards: parsed.rewards.push( {‘type’:reward[0], ‘id’:reward[1], ‘value’:reward[2]} ) log_writer.write(parsed)
  • 36. 이렇게 파서 짜면 되지 않나요? • 되긴 함 • 하지만 로그 종류가 200여 가지라면 • 파서 짜고 검증하는데 시간 너무 오래 걸림 • 하루에 10억 행이 쌓인다면 • 대부분 파서는 복잡한 일을 하고 • 로그 스트림에 사용되는 워커 스케일 업 요구
  • 38. 데이터는 테이블 형태로 기록하자 • 대부분의 빅데이터 솔루션은 스키마 정의만 해주면 • SQL 질의가 가능 • 행/열 형태로 저장되는 게 제일 좋음 • CSV • Key-value paired JSON Object
  • 39. 용량 및 저장비용 이슈 • 좋은 압축 알고리즘 적용하자 • Gz, lzo, zstd, parquet • 클라우드 스토리지는 비싸지 않음 • S3 1TB 저장비용 = 약 월 $25 • 스탠다드, 스탠다드-IA
  • 42. 1TB 노드 2개 쓰는데 하루에 100기가씩 쌓여요. 어떡하죠?
  • 43. 그래도 되긴 하는데… • 레드시프트는 2PB까지 저장 가능 • 하지만 꺼둘 수가 없음 • 그 로그를 과연 상시 쿼리할까? • 의도 이상으로 컴퓨팅 비용이 너무 높음
  • 44. 방안 • 핫 / 콜드 데이터를 구분 • 핫 : 데이터 분석가가 주로 쿼리 날리는 데이터 • 콜드 : 1년에 한번 쿼리 할까 말까 한 데이터 • 핫 데이터는 데이터 웨어하우스에 • 콜드 데이터는 저렴한 스토리지에 • 콜드 데이터 검색은 빅쿼리 / 아테나 /프레스토로
  • 45. 핫 데이터를 더 정제하자 • Star / Snowflake Schema • Fact, Dimension으로 디자인 • 데이터 최적화
  • 48. 데이터 워크플로우를 관리하자 • 정제 작업은 데이터 워크플로우 툴을 사용 • 정제한 데이터만 데이터 웨어하우스에 저장 • 노드 / 비용 절감 • 쿼리 퍼포먼스 향상
  • 51. 정리 • 보고싶은 지표를 명확히 설정하고 • 기록할 데이터의 형식과 시점을 매번 검증하고 • 테이블 형태로 기록해주시고 • 핫 / 콜드 데이터 잘 분리해주시고 • 데이터 워크플로우 잘 관리해주시면 • 어느 플랫폼에서나 • 데이터 분석 쉽고 빠르게 시작하실 수 있습니다

Editor's Notes

  1. 하지만 로그 기록은 귀찮은 작업 컨텐츠 제작 막바지에 하는 작업 그래서 대충하고, 실수를 많이 하게 됨 그리고 그래도 된다고 생각하는 경우 많음 뭐 어떻게 쌓든 나중에 분석해주겠지
  2. 하지만 로그 기록은 귀찮은 작업 컨텐츠 제작 막바지에 하는 작업 그래서 대충하고, 실수를 많이 하게 됨 그리고 그래도 된다고 생각하는 경우 많음 뭐 어떻게 쌓든 나중에 분석해주겠지
  3. 하지만 로그 기록은 귀찮은 작업 컨텐츠 제작 막바지에 하는 작업 그래서 대충하고, 실수를 많이 하게 됨 그리고 그래도 된다고 생각하는 경우 많음 뭐 어떻게 쌓든 나중에 분석해주겠지
  4. 그럼 이제 어떻게 해야하느냐.. 하면
  5. 이미 망한거죠 ㅋㅋ 답 없습니다. 이번 생애는 망했다고 생각하고 대충 살면 되죠 뭐.. ㅋ 계속 망할 수는 없잖아요? 이렇게 망하는 흔한 사례와 이런 상황을 해결하기 위한 솔루션들을 지금부터 소개해 드리려고 합니다.
  6. 이유가 없이 쌓인 로그는 쓰레기에 불과한 데이터 그런 로그 더미에서 인사이트를 찾아내는 과정은 쓰레기 더미에서 보물을 캐듯 어려운 작업 쌓인 로그에 따라 못 찾을 수도 있다
  7. 어떤 로그를 기록해야 하는지를 판단하는 중요한 기준
  8. 그럼 실제 디자인하는 걸 예로 들어볼게요
  9. 큐브를 이리 돌리고 저리 돌리듯
  10. 기왕 로그를 쌓아야 한다면 이유가 있는 로그만 쌓자는 겁니다
  11. 기왕 로그를 쌓아야 한다면 이유가 있는 로그만 쌓자는 겁니다
  12. 아.. 복잡하고 성능 나빠지네 ㅜㅜ