15. Action
• 서버에 저장해야 하는
사용자의 모든 동작을
Action이라고 명명함
• Ex. 로그인, 생산, 수확, 건설, 판매, 뽑기, 거래, 선물 등등
16. Action 기본 통신 구조
사용자 입력
빵 생산
서버 데이터 처리
[생산]
밀가루 -1
빵 생산 시작
게임 연출
밀가루 소모 연출
+
빵 생산 연출
17. 게임 내 사용자 경험
• 기존 처리 완료를 기다려야
다음 요청을 처리할 수 있음
• 응답이 오기전 까지, 사용자의 입력을 막고 대기
• 네트워크 지연 시, 사용자 경험이 매우 나빠짐
18. 동기 / 비동기 Action 구분
• 서버 응답을 기다려야 하는지를 기준으로
동기 / 비동기 Action 두 종류로 구분함
• 동기 Action: 서버 응답 대기
Ex. 친구정보, 거래, 선물, 뽑기 등
• 비동기 Action: 클라 우선 예측 처리
Ex. 생산, 수확, 아이템 판매 등
19. 동기 Action 동작 예시
사용자 입력
밀가루 수확
빵 생산
서버 데이터 처리
[생산]
밀가루 -1
빵 생산 시작
[수확]
밀가루 +1
게임 연출
밀가루 획득 연출
밀가루 소모 연출
+
빵 생산 연출
20. 서버 데이터 처리
[생산]
밀가루 -1
빵 생산 시작
[수확]
밀가루 +1
비동기 Action 동작 예시
사용자 입력
밀가루 수확
빵 생산
게임 연출
밀가루 획득 연출
밀가루 소모 연출
+
빵 생산 연출
21. 비동기 Action 요약
• 그림으로 그리니까 너무 어려운데
• 서버 응답을 예측(Action 미리 실행)해서
• 게임 클라이언트에서 우선 연출
• 서버 응답은 오든가 말든가 게임은 계속 진행
• 통신 중에는 화면 구석에 동기화 아이콘 표기
• 서버 응답이 에러 발생이면, 게임 정지 / 동기화
22. 비동기 Action 장점
• 게임 특성상, 상당히 많은 Action 비동기 처리
• 사용자 터치 막을 필요 없어짐
• 사용자 유저 경험 매우 좋아짐
• Case. 12층에서 1층 가는 차폐 엘리베이터에서도 게임이 끊어지지 않고 플레이 가능함
23. +비동기 Action 주의점
• 모든 Action의 서버 처리 순서 보장필요
• Action Queue에 쌓아서 순서대로 처리
• UI 동기화 처리 복잡도 증가
• 현재 표기 값과 현재 확정 값이 다름.
• 재화는 항상 대입보다 증감으로 처리 해야 함.
• 예측 불가 Client rand() != Server rand()
• 서버에서 Random값 참조하는 경우를 비동기 action 처리했다가
random 결과가 달라서 버그가 발생함.
• Random seed를 맞추려다가 그냥 동기 action으로 처리함
35. 서버 응답속도는 정상
• ELB 평균 응답 100ms ~ 250ms
• 서버는 문제 없음. 클라 버그네, 클라 버그여
36. Client Network 통계
• 클라이언트에서 측정 해 보자!
• 요청 시, 아래 내용 전송
• Action Queue Length
• Action 응답 속도 통계
37. Client Network data 참조1
• 모든 요청마다 0.1% 수준으로 기록 (Sampling)
• 평균 1300ms (=1.3초)
• 정규분포 가정 시 84%의 요청이 2500ms, 97% 요청은 3670ms
Queue 길이 1 2 3
표본 수 788574
(97.80%)
11158
(1.38%)
3418
(0.42%)
최소 605 602 565
최대 5353 5454 5647
평균 1320 1358 1329
표준편차 1175 1246 1301
38. Client Network 통계 평균
• 클라이언트가 받는 응답속도는 평균 1300ms
• 서버는 200ms 만에 보냈는데,
• 네트워크가 잘못했네
• 멍청하게도 3G, LTE, WIFI 구분 안 했음
40. Client Network 발견한 문제
• 동기 Action을 수행하려면
• 기존에 쌓여있던 Action 들이
• 순서대로 전부 수행되고 나서야 수행 가능
• 비동기 Action이 발생하자마자 서버 요청을 시작 하는데도
30개 정도는 어렵지 않게 쌓임
• 요청 100개가 쌓여있으면, 평균 1.3초 가정 시
130초 동안 빙글빙글 돌면서 멈춤
41. User Case
• 게임에 로그인해서
• 생산/수확 한참 하고 나서
• 거래소나 친구 집에 가면
• 게임이 멈춰서 껐다 켰더니
• 생산/수확 요청이 처리 안 되어 있어요
•> 롤백 돼요
42. 기술 용어로 해석
• 게임에 로그인해서 생산/수확 한참 하고 나서
• 비동기 Action을 한 번에 100개쯤 하고
• 거래소나 친구 집에 가면
• 동기 Action을 수행하면 네트워크 응답이 오래 걸리고
• 네트워크 응답이 없어서 껐다 켰더니
• 유저가 네트워크 대기화면에서 게임이 멈춘 거로 인식하고
• 생산/수확 요청이 처리 안 되어 있어요
• 해당 요청이 서버에 안 와서 처리가 안 돼요
46. Batching Requests
• 사실 이 정리 자료의 핵심
• 한번 여러 요청이 묶이도록
통신 구조를 거의 다 뜯어야 했음
• 다른 게임에서는 이걸 뭐라고 부르나 몰라서
내부에서는 Bulk processing, network batching 등 여러 가지 이름으로 부름.
적절한 표현이 있다면 알려주세요
47. 기존 평균 응답속도 (REAL)
Client Server
요청600ms
응답 600ms
수행
250ms
48. 기존 통신 3번 일어난다면
Client Server
요청600ms
응답 600ms
수행
250ms
요청600ms
응답 600ms
수행
250ms
요청600ms
응답 600ms
수행
250ms
49. 모아서 보내서, 이렇게 줄여보자
Client Server
요청600ms 수행
250ms
수행
250ms
응답 600ms
수행
250ms
50. 개선 목표
• 서버 내 처리보다 (100ms ~ 250ms)
• 네트워크 전송이 오래 걸리므로 (1300ms)
• 요청을 n 개를 모아서 한 번에 처리하자
• 문제는 밖에 있었다. 서버 최적화 괜히 했어
51. #5’ DB 처리 개선
Batching 작업 하다가 발견한 다른 장점
이 부분은 패스 하셔도 됩니다.
52. 해당 작업 중 발견한 다른 이점
• 사용자 데이터를
Json format으로
NoSQL 에서 한 번에 관리하고 있었음.
• 통신 구조 상 DB 처리에도 이득
53. + 유저 Main DB NoSQL을 쓴 다는 것…
• 주의. 장점 만큼 단점도 많은 방식입니다.
• 장점은 AWS summit 발표자료...
`게임 고객 사례를 통해 살펴보는 AWS 활용 전략` 참조
• 단점은 개인 문의 바람… 여백이 부족하군요. 하하하
58. DB 처리 감소 이득
• 별생각 없었는데, 구현하면서 보니 꿀 이득
• 로직과 관련 없는 DB 처리도 (Fetch/Deserialize/Serialize/Write 등등)
한 번만 하면 되더라
Server DB
Request Parse
Execute
Serialize
Write User
Deserialize
Response
Fetch User
Execute
Execute
59. 함정 카드 발동
• 여러 요청 중간에 에러가 발생하면,
마지막 정상 요청까지의 상태를 저장해야 함.
• DB 처리를 무조건 건너 뛸 수는 없음
60. 새로운 이슈
• 작업하면서, 내부 소요 시간도 측정 하다 보니
• Serialize가 공통 병목 구간으로 확인됨
Server DB
Request Parse
Execute
Serialize
Write User
Deserialize
Response
Fetch User
Execute
Execute
61. Serialized 대책
• 대안
1. Fetch는 한번, Write는 매번 하기
2. Serialized 된 string만 cache 해 두기
3. Memory transaction 으로 변경 추적하기
4. User 객체 deep copy로 보존
• 다른 대안이 조금씩 애매해서, 일단 포기하고 2번
• 난 포기가 빠른 남자니까
• 테스트 상 ExpressionTree로 DeepCopy 하는 게 가장 빠르긴 했음
• http://stackoverflow.com/questions/852064/faster-deep-cloning
62. DB 처리 개선 정리
• 작업 하다 보니까, DB 처리도 개선되더라
• 처리 속도가 엄청 빨라졌음
• 그런데, 해당 적용으로는 에러 발생시 버그 유발
• 그래서 엄청 빠르게는 못하고, 조금 개선 함
63. 원래 하던 얘기로 돌아가서
• 요청이 100개씩 밀리는 경우가 발생
• 여러 Action을 한 번에 보내면 좋을 것 같아서
• 묶어서 보냄 (= Batching Requests)
• 통신 횟수도 감소, 내부 처리 로직도 개선
64. 모아서 보내는 기준은?
• 100개가 쌓여있다고 100개를 한 번에?!
• 일단 최대 8개씩 보내도록 해봄
• 이후 해당 부분을 수정할 의지가 없어져서 평생 8개씩 보내게 됨
65. 개선 시도 후 테스트
• 기존 150ms 정도 걸리던 요청 (dev서버 기준)
• 첫 Action 만 150ms 정도가 소요되고
• 묶어서 보낸 다른 Action은 10ms 안에 끝남
66. 서비스 적용 후 상황
• 0.1% 샘플링
• 대부분의 요청이 2개씩 묶어서 처리됨.
67. Batching 적용 효과
• 일단 체감 효과가 좋아짐
• 네트워크 지연 상황을 재현하기도 어려워짐
• 해당 적용 효과 통계 자료가 분실됨…