디스크 기반 Skip list를 사용한 대용량 실시간 랭킹
WoW 랭킹 서비스 wowz.kr를 사례로
윤석주(nori)
모빌팩토리
윤석주 ( @noricube )
- 2012:서울
- Zoo Invasion
- 퍼즐 주주
- Project VM 개발중
발표자 소개
서비스 컨셉
wowz.kr
- 와우 경매장의 데이터를 수집하여 통계를 보여주는 서비스
- 가격, 가격의 추세
- 와우 인벤에서 좋은 반응 (우측 배너 링크)
WoW의 각종 통계로
랭킹을 알려주는 사이트를 만들자!
MMORPG?
여러가지 요소 중 경쟁이 핵심
와우의 경우?
게임 시스템 내에서 제공
http://kr.battle.net/wow/ko/pvp/leaderboards/rbg
와우의 경우?
유저들이 만든 사이트
http://www.wowprogress.com/
문제는
앞에 두개의 예는 모두 하드코어(레이드, PvP) 유저들이 초점
- 라이트 한 유저들도 경쟁을 즐길 수 있는 방법이 있을까?
- 레이드, PvP외에 다른 요소로 경쟁을 즐길 수 있을까?
와우의 통계 기능
흥미로운 통계들
- 낚은 물고기
- 경매장에서 획득한 골드
- 사용한 생명석
- 익사 횟수
- ….
통계 기능 활용
와우의 통계 기능을 활용해서 경쟁 하도록 하면 어떨까?
- 경매장에서 골드 많이 획득한 순위
- 낚시로 많이 낚은 순위
- 제일 많이 죽은(?) 순위
서비스 구현
API 활용
마침 WoW에서는 캐릭터 정보(통계) API 제공
- 1시간에 36000번까지 호출 가능
- WoW에서 로그아웃 후 즉시 갱신됨
 한 캐릭터 갱신에 100ms 이내로 하면 제일 좋음
연산 예상
서버당 3만~7만 정도의 만렙 캐릭터
연산 예상
- 전 서버를 합산하면 40만개 정도의 캐릭터
- 통계로 얻을 수 있는 수치는 대략 1000개
- 서버 별, 전 서버 랭킹을 각각 따로 보여주고 싶음
 각각 40만의 캐릭터 정보를 가진 2000개의 셋의 랭킹 계산
공간 예상
- 캐릭터당 12byte를 소모 한다고 가정
- Uid 4byte
- Score 8byte
- 12byte * 40만개(캐릭터) * 2000(랭킹셋) = 약 9GB
 메모리에 올리기엔 커서 디스크 자료 구조 사용
알고리즘 선택
- Binary Heap으로 구현
- 디스크 기반에서 추가/삭제/검색이 무난한 속도
- 추상화 하기가 쉬움
왜죠?
너무 느리다
Heap은 랭킹을 구할 때 마다 Heapsort를 수행하는것
- O(Nlog(N))의 시간 복잡도 소요
- 2000개의 랭킹을 갱신하는데 3분 이상 소요
Redis는 뭘 쓰지?
Indexed Skip List
- 1989년에 나온 최신(!) 자료 구조
- 검색/추가/삭제/랭킹 O(log(N))
어떻게??
* http://www.slideshare.net/jongwookkim/skip-list
Skip List
- Linked list에 추가 포인터가 있는 자료 구조
- 모든 요소는 정렬 되어 있다
head 11 22 30 42 51 65 73
NIL
NIL
NIL
* http://www.slideshare.net/jongwookkim/skip-list
Skip List
- 일반적인 linked list
- 검색하려면 모든 노드를 탐색 해야 함
head 11 22 30 42 51 65 71 80
NIL
* http://www.slideshare.net/jongwookkim/skip-list
Skip List
2개 마다 추가 포인터를 둔다면
[N/2]+1(N은 리스트의 크기)만 탐색하면 됨
head 11 22 30 42 51 65 71 80
NIL
NIL
예를들어 71을 찾는다면
* http://www.slideshare.net/jongwookkim/skip-list
Skip List
2개 마다 1개의 추가 포인터, 4번째 요소마다 2개의 추가 포인터
[N/4]+2만 탐색하면 됨
head 11 22 30 42 51 65 71
NIL
NIL
NIL
* http://www.slideshare.net/jongwookkim/skip-list
Skip List
- 2i 번째 노드는 2i 개의 포인터를 가지도록 하면?
- O(log(N))개만 탐색
* http://www.slideshare.net/jongwookkim/skip-list
Skip list
이러한 구조를 계속 유지한다면
- 검색은 매우 빠르다
- 삽입/삭제가 너무 느리다
* http://www.slideshare.net/jongwookkim/skip-list
Skip list
추가 할때 포인터를 확률적으로 결정한다면?
- 노드 중 1/2은 포인터 1개
- 노드 중 ¼은 포인터 2개
- 노드 중 1/2i은 포인터 i개를 가짐
* http://www.slideshare.net/jongwookkim/skip-list
Skip list
- 포인터를 랜덤 하게 가지므로 구조를 유지할 필요 없음
- 하지만 높은 확률로 O(log(N)) 시간에 동작
* http://www.slideshare.net/jongwookkim/skip-list
Skip List insert
- 연관되는 포인터를 저장하면서 탐색
- 추가할때 구조 변경 없이 포인터만 바꿔주면 해결
head 12 22 34 40 55 60 70
NIL
NIL
NIL
55를 추가한다면
Skip List delete
- 연관되는 포인터를 저장하면서 탐색
- 추가와 마찬가지로 구조 변경 없이 포인터만 바꿔주면 해결
head 12 22 34 40 55 60 70
NIL
NIL
NIL
55를 삭제한다면
Skip List rank
- 포인터마다 skip하는 길이를 기록
- 검색 후 값을 더하면 순위
head 12 22 34 40 55 60 70
NIL
NIL
NIL
4
2
1 1
2 2
1 1 1 1 1
60의 순위는?
Skip List를 디스크에
- 포인터를 파일 offset으로 대체
- 추가 시에 파일 끝에 요소 추가
- 삭제 시에 삭제한 offset 보관, 추가시 재사용
head 1 2 3
head [4] [6] [NIL] 1 [6]
2 [9] [NIL] 3 [NIL] [NIL]
Skip List를 디스크에
- Memory Mapped file 사용
- 포인터로 접근 가능해서 편리함
- 우선 고정 크기로
- 만들기 쉽고 SSD용량은 상대적으로 저렴함
Heap과 비교하면
- 오버헤드 제외 하고 디스크 기반에서 매우 유리
- 디스크는 메모리대비 가격도 저렴
Heap Skip List
추가/삭제
상황에 따라
부모 노드와 swap
포인터만 교체
랭킹 구하는 시간 O(Nlog(N)) O(log(N))
오버헤드 X 요소 만큼 추가 포인터
실제로 구현 해보니
- 한 캐릭터 업데이트에 50ms 정도 소요
- Xeon E3-1231v3, SSD 기준
- 원하던 100ms안에 랭킹 갱신이 가능
- SSD 용량 80GB 소요
- 가변 크기를 사용한다면 많이 줄일 수 있는 부분
결과
- 구현은 완료!
- 현재 사이트 제작 + 다듬는 중 6월말 오픈 예정
- 기대해주세요!
감사합니다
sjyun@mobilfactory.co.kr
Reference
• Skip Lists: A Probabilistic Alternative to Balanced Trees
• http://epaperpress.com/sortsearch/download/skiplist.pdf
• 스킵 리스트 소개 자료(김종욱님)
• http://www.slideshare.net/jongwookkim/skip-list

디스크 기반 Skip list를 사용한 대용량 실시간 랭킹 : WoW 랭킹 서비스 wowz.kr를 사례로

  • 1.
    디스크 기반 Skiplist를 사용한 대용량 실시간 랭킹 WoW 랭킹 서비스 wowz.kr를 사례로 윤석주(nori) 모빌팩토리
  • 2.
    윤석주 ( @noricube) - 2012:서울 - Zoo Invasion - 퍼즐 주주 - Project VM 개발중 발표자 소개
  • 3.
  • 4.
    wowz.kr - 와우 경매장의데이터를 수집하여 통계를 보여주는 서비스 - 가격, 가격의 추세 - 와우 인벤에서 좋은 반응 (우측 배너 링크)
  • 5.
    WoW의 각종 통계로 랭킹을알려주는 사이트를 만들자!
  • 6.
  • 7.
    와우의 경우? 게임 시스템내에서 제공 http://kr.battle.net/wow/ko/pvp/leaderboards/rbg
  • 8.
    와우의 경우? 유저들이 만든사이트 http://www.wowprogress.com/
  • 9.
    문제는 앞에 두개의 예는모두 하드코어(레이드, PvP) 유저들이 초점 - 라이트 한 유저들도 경쟁을 즐길 수 있는 방법이 있을까? - 레이드, PvP외에 다른 요소로 경쟁을 즐길 수 있을까?
  • 10.
  • 11.
    흥미로운 통계들 - 낚은물고기 - 경매장에서 획득한 골드 - 사용한 생명석 - 익사 횟수 - ….
  • 12.
    통계 기능 활용 와우의통계 기능을 활용해서 경쟁 하도록 하면 어떨까? - 경매장에서 골드 많이 획득한 순위 - 낚시로 많이 낚은 순위 - 제일 많이 죽은(?) 순위
  • 13.
  • 14.
    API 활용 마침 WoW에서는캐릭터 정보(통계) API 제공 - 1시간에 36000번까지 호출 가능 - WoW에서 로그아웃 후 즉시 갱신됨  한 캐릭터 갱신에 100ms 이내로 하면 제일 좋음
  • 15.
    연산 예상 서버당 3만~7만정도의 만렙 캐릭터
  • 16.
    연산 예상 - 전서버를 합산하면 40만개 정도의 캐릭터 - 통계로 얻을 수 있는 수치는 대략 1000개 - 서버 별, 전 서버 랭킹을 각각 따로 보여주고 싶음  각각 40만의 캐릭터 정보를 가진 2000개의 셋의 랭킹 계산
  • 17.
    공간 예상 - 캐릭터당12byte를 소모 한다고 가정 - Uid 4byte - Score 8byte - 12byte * 40만개(캐릭터) * 2000(랭킹셋) = 약 9GB  메모리에 올리기엔 커서 디스크 자료 구조 사용
  • 18.
    알고리즘 선택 - BinaryHeap으로 구현 - 디스크 기반에서 추가/삭제/검색이 무난한 속도 - 추상화 하기가 쉬움
  • 21.
  • 22.
    너무 느리다 Heap은 랭킹을구할 때 마다 Heapsort를 수행하는것 - O(Nlog(N))의 시간 복잡도 소요 - 2000개의 랭킹을 갱신하는데 3분 이상 소요
  • 25.
    Redis는 뭘 쓰지? IndexedSkip List - 1989년에 나온 최신(!) 자료 구조 - 검색/추가/삭제/랭킹 O(log(N)) 어떻게?? * http://www.slideshare.net/jongwookkim/skip-list
  • 26.
    Skip List - Linkedlist에 추가 포인터가 있는 자료 구조 - 모든 요소는 정렬 되어 있다 head 11 22 30 42 51 65 73 NIL NIL NIL * http://www.slideshare.net/jongwookkim/skip-list
  • 27.
    Skip List - 일반적인linked list - 검색하려면 모든 노드를 탐색 해야 함 head 11 22 30 42 51 65 71 80 NIL * http://www.slideshare.net/jongwookkim/skip-list
  • 28.
    Skip List 2개 마다추가 포인터를 둔다면 [N/2]+1(N은 리스트의 크기)만 탐색하면 됨 head 11 22 30 42 51 65 71 80 NIL NIL 예를들어 71을 찾는다면 * http://www.slideshare.net/jongwookkim/skip-list
  • 29.
    Skip List 2개 마다1개의 추가 포인터, 4번째 요소마다 2개의 추가 포인터 [N/4]+2만 탐색하면 됨 head 11 22 30 42 51 65 71 NIL NIL NIL * http://www.slideshare.net/jongwookkim/skip-list
  • 30.
    Skip List - 2i번째 노드는 2i 개의 포인터를 가지도록 하면? - O(log(N))개만 탐색 * http://www.slideshare.net/jongwookkim/skip-list
  • 31.
    Skip list 이러한 구조를계속 유지한다면 - 검색은 매우 빠르다 - 삽입/삭제가 너무 느리다 * http://www.slideshare.net/jongwookkim/skip-list
  • 32.
    Skip list 추가 할때포인터를 확률적으로 결정한다면? - 노드 중 1/2은 포인터 1개 - 노드 중 ¼은 포인터 2개 - 노드 중 1/2i은 포인터 i개를 가짐 * http://www.slideshare.net/jongwookkim/skip-list
  • 33.
    Skip list - 포인터를랜덤 하게 가지므로 구조를 유지할 필요 없음 - 하지만 높은 확률로 O(log(N)) 시간에 동작 * http://www.slideshare.net/jongwookkim/skip-list
  • 34.
    Skip List insert -연관되는 포인터를 저장하면서 탐색 - 추가할때 구조 변경 없이 포인터만 바꿔주면 해결 head 12 22 34 40 55 60 70 NIL NIL NIL 55를 추가한다면
  • 35.
    Skip List delete -연관되는 포인터를 저장하면서 탐색 - 추가와 마찬가지로 구조 변경 없이 포인터만 바꿔주면 해결 head 12 22 34 40 55 60 70 NIL NIL NIL 55를 삭제한다면
  • 36.
    Skip List rank -포인터마다 skip하는 길이를 기록 - 검색 후 값을 더하면 순위 head 12 22 34 40 55 60 70 NIL NIL NIL 4 2 1 1 2 2 1 1 1 1 1 60의 순위는?
  • 37.
    Skip List를 디스크에 -포인터를 파일 offset으로 대체 - 추가 시에 파일 끝에 요소 추가 - 삭제 시에 삭제한 offset 보관, 추가시 재사용 head 1 2 3 head [4] [6] [NIL] 1 [6] 2 [9] [NIL] 3 [NIL] [NIL]
  • 38.
    Skip List를 디스크에 -Memory Mapped file 사용 - 포인터로 접근 가능해서 편리함 - 우선 고정 크기로 - 만들기 쉽고 SSD용량은 상대적으로 저렴함
  • 39.
    Heap과 비교하면 - 오버헤드제외 하고 디스크 기반에서 매우 유리 - 디스크는 메모리대비 가격도 저렴 Heap Skip List 추가/삭제 상황에 따라 부모 노드와 swap 포인터만 교체 랭킹 구하는 시간 O(Nlog(N)) O(log(N)) 오버헤드 X 요소 만큼 추가 포인터
  • 40.
    실제로 구현 해보니 -한 캐릭터 업데이트에 50ms 정도 소요 - Xeon E3-1231v3, SSD 기준 - 원하던 100ms안에 랭킹 갱신이 가능 - SSD 용량 80GB 소요 - 가변 크기를 사용한다면 많이 줄일 수 있는 부분
  • 42.
    결과 - 구현은 완료! -현재 사이트 제작 + 다듬는 중 6월말 오픈 예정 - 기대해주세요!
  • 43.
  • 44.
    Reference • Skip Lists:A Probabilistic Alternative to Balanced Trees • http://epaperpress.com/sortsearch/download/skiplist.pdf • 스킵 리스트 소개 자료(김종욱님) • http://www.slideshare.net/jongwookkim/skip-list

Editor's Notes