22. 너무 느리다
Heap은 랭킹을 구할 때 마다 Heapsort를 수행하는것
- O(Nlog(N))의 시간 복잡도 소요
- 2000개의 랭킹을 갱신하는데 3분 이상 소요
23.
24.
25. Redis는 뭘 쓰지?
Indexed Skip List
- 1989년에 나온 최신(!) 자료 구조
- 검색/추가/삭제/랭킹 O(log(N))
어떻게??
* http://www.slideshare.net/jongwookkim/skip-list
26. Skip List
- Linked list에 추가 포인터가 있는 자료 구조
- 모든 요소는 정렬 되어 있다
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 소요
- 가변 크기를 사용한다면 많이 줄일 수 있는 부분
44. Reference
• Skip Lists: A Probabilistic Alternative to Balanced Trees
• http://epaperpress.com/sortsearch/download/skiplist.pdf
• 스킵 리스트 소개 자료(김종욱님)
• http://www.slideshare.net/jongwookkim/skip-list