skip list

skip list

skip listλŠ” ν™•λ₯ μ  자료ꡬ쑰라고 λΆ€λ₯΄λ©°, κ²€μƒ‰μ΄λ‚˜ μ‚½μž… μ‹œ O(logN)의 속도λ₯Ό 보μž₯ν•œλ‹€. λ¦¬μŠ€νŠΈμ™€ μœ μ‚¬ν•˜μ§€λ§Œ, λ¦¬μŠ€νŠΈλŠ” 검색이 O(N)이닀.

skip listλŠ” 보톡 μ•„λž˜μ™€ 같은 ν˜•νƒœλ₯Ό κ°–λŠ”λ‹€.

그림처럼 λ©€ν‹° 헀더λ₯Ό κ°–κ³  있으며, 높이가 μ—¬λŸ¬ κ°œλ‹€.

μ—¬κΈ°μ„œ λ§ν•˜λŠ” λ†’μ΄λž€, ν•˜λ‚˜μ˜ λ…Έλ“œλŠ” κ°’(value)을 κ°€μ§€κ³  μžˆλŠ”λ° λ…Έλ“œμ˜ 레벨(높이)λ§ˆλ‹€ 같은 값을 κ°€μ§„λ‹€.

  • 값은 κ°™μ§€λ§Œ, ν—€λ”μ—μ„œ κ°€λ¦¬ν‚€λŠ” 포인터가 λ‹€λ₯΄λ‹€.

이 λ†’μ΄λŠ” 랜덀 ν™•λ₯ λ‘œ κ²°μ •λ˜λŠ”λ° 보톡은 ν•œ κ°œμ”©μ€ 기본적으둜 생긴닀.

μ™œ ν™•λ₯ μ  자료ꡬ쑰 인가?

λ…Έλ“œμ˜ 높이. 즉, λ…Έλ“œμ˜ λ ˆλ²¨μ€ ν™•λ₯ λ‘œ κ²°μ •λœλ‹€. 레벨이 ν™•λ₯ μ μœΌλ‘œ κ³„μ‚°λ˜λŠ” 것을 μ œμ™Έν•˜λ©΄ λ§ν¬λ“œ λ¦¬μŠ€νŠΈλž‘ μœ μ‚¬ν•˜λ‹€κ³  ν•œλ‹€.

zslRandomLevel ν•¨μˆ˜λŠ” redis의 skip list κ΅¬ν˜„μ—μ„œ μƒˆλ‘œμš΄ λ…Έλ“œμ˜ λ ˆλ²¨μ„ κ²°μ •ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.

깊게 λΆ„μ„ν•˜μ§€ μ•Šμ•˜μ§€λ§Œ, 이 ν•¨μˆ˜λŠ” λžœλ€ν•œ 값을 μƒμ„±ν•˜μ—¬, κ·Έ 값이 νŠΉμ • μž„κ³„κ°’λ³΄λ‹€ μž‘μ„ λ•Œλ§ˆλ‹€ λ ˆλ²¨μ„ μ¦κ°€μ‹œν‚€λŠ” λ°©μ‹μœΌλ‘œ μž‘λ™ν•œλ©° μ΅œλŒ€ λ ˆλ²¨μ€ μ΄ˆκ³Όν•˜μ§€ μ•Šλ„λ‘ 보μž₯λœλ‹€.

결과적으둜, 이 ν•¨μˆ˜λŠ” 1λ ˆλ²¨μ—μ„œ μ‹œμž‘ν•˜μ—¬ λ‹€μŒ 레벨둜 올라갈 ν™•λ₯ μ΄ 1/4둜 μ„€κ³„λ˜μ–΄ 있으며, μ΅œλŒ€ λ ˆλ²¨μ€ 32이닀.

μ €μž₯ μ˜ˆμ‹œ

예λ₯Ό λ“€μ–΄, scoreκ°€ 10, 20, 30인 μ„Έ 개의 memberκ°€ μ‘΄μž¬ν•œλ‹€κ³  ν•˜λ©΄ skip listλŠ” λ‹€μŒκ³Ό 같이 κ΅¬μ„±λœλ‹€.

O(logN)으둜 탐색이 κ°€λŠ₯ν•œ 이유

skip listλŠ” μ—¬λŸ¬ 레벨의 μ—°κ²° 리슀트둜 κ΅¬μ„±λœλ‹€. Level 1μ—μ„œμ˜ νƒμƒ‰μœΌλ‘œ λ³Έλ‹€λ©΄, λ§ν¬λ“œ λ¦¬μŠ€νŠΈμ™€ μœ μ‚¬ν•˜κ²Œ O(N)의 속도가 λ‚˜μ˜¨λ‹€. ν•˜μ§€λ§Œ 탐색 νš¨μœ¨μ„±μ€ Tree와 μœ μ‚¬ν•˜λ‹€.

  • κ°€μž₯ μ•„λž˜ λ ˆλ²¨μ€ λͺ¨λ“  μš”μ†Œ(μ‹€μ œ κ°’)을 ν¬ν•¨ν•˜κ³ , μƒμœ„ 레벨둜 갈수둝 μš”μ†Œ μˆ˜κ°€ 쀄어든닀.

각 λ…Έλ“œκ°€ μƒμœ„ λ ˆλ²¨μ— 포함될 ν™•λ₯ μ€ 50%이닀. 이둜 인해 레벨 Kμ—λŠ” ν‰κ· μ μœΌλ‘œ N / 2^K 개의 λ…Έλ“œκ°€ ν¬ν•¨λœλ‹€.

탐색 κ³Όμ •:

  1. μ΅œμƒμœ„ λ ˆλ²¨μ—μ„œ μ‹œμž‘ν•˜μ—¬, 각 λ ˆλ²¨μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ μ΄λ™ν•˜λ©° νƒμƒ‰ν•œλ‹€.

  2. 더 이상 이동할 수 μ—†μœΌλ©΄ ν•œ 단계 μ•„λž˜ 레벨둜 λ‚΄λ €κ°„λ‹€.

  3. 이 과정을 λ°˜λ³΅ν•˜μ—¬ μ›ν•˜λŠ” μš”μ†Œμ— λ„λ‹¬ν•œλ‹€.

ex) 7을 μ°ΎλŠ” κ³Όμ •

  1. Level 3μ—μ„œ μ‹œμž‘: 1 β†’ 9 (9κ°€ 더 ν¬λ―€λ‘œ 내렀감)

  2. Level 2둜 내렀감: 1 β†’ 5 β†’ 9 (9κ°€ 더 ν¬λ―€λ‘œ 내렀감)

  3. Level 1둜 내렀감: 5 β†’ 7 β†’ 9 (7을 찾음)

이 κ³Όμ •μ—μ„œ λͺ‡ 개의 λ…Έλ“œλ§Œ ν™•μΈν•˜κ³ λ„ λΉ λ₯΄κ²Œ 7을 찾을 수 μžˆλ‹€.

과정을 보면, Level1 μ—μ„œλŠ” 1번, 3번 λ…Έλ“œμ˜ 탐색을 κ±΄λ„ˆ λ›°λŠ” 것을 λ³Ό 수 μžˆλ‹€.

일반 μ—°κ²° λ¦¬μŠ€νŠΈμ˜€λ‹€λ©΄ 1~7κΉŒμ§€ λͺ¨λ“  λ…Έλ“œλ₯Ό 확인해야 ν•œλ‹€.

각 λ ˆλ²¨μ—μ„œ ν™•μΈν•˜λŠ” λ…Έλ“œ μˆ˜κ°€ μ œν•œμ μ΄κ³ , 레벨 μˆ˜κ°€ logN에 λΉ„λ‘€ν•˜κΈ° λ•Œλ¬Έμ— 전체 탐색 μ‹œκ°„μ΄ O(logN)이 λœλ‹€.

skip list ꡬ쑰

skip listλŠ” quad node ν˜•νƒœλ‘œ κ΅¬ν˜„λœλ‹€. λ”°λΌμ„œ ν•œ λ ˆμ΄μ–΄ μ•ˆμ—μ„œ λ§ν¬λ“œ 리슀트의 μ–‘λ°©ν–₯ 탐색 λΏλ§Œμ•„λ‹ˆλΌ μœ„μ•„λž˜λ‘œλ„ 링크λ₯Ό κ°€μ§€κ³  μžˆμ–΄μ„œ μ‚­μ œ, 검색, μ—…λ°μ΄νŠΈμ—λ„ μš©μ΄ν•˜λ‹€.

λ…Έλ“œ ꡬ쑰

  • backward: 이전 λ…Έλ“œλ₯Ό κ°€λ₯΄ν‚€λŠ” 포인터

  • level[]: 각 λ ˆλ²¨λ³„ λ‹€μŒ λ…Έλ“œ 정보 (포인터와 span)

  • score: μ •λ ¬ 기쀀이 λ˜λŠ” 점수 (μ‚½μž…μœΌλ‘œ λ“€μ–΄μ˜€λŠ” 점수)

  • ele: μ‹€μ œ μ €μž₯λ˜λŠ” member 데이터 (μ‚½μž…μœΌλ‘œ λ“€μ–΄μ˜€λŠ” member 값이 λ“€μ–΄μ˜΄)

skip listμ—μ„œλŠ” span을 톡해 각 λ ˆλ²¨μ—μ„œ λ…Έλ“œκ°€ μ–Όλ§ˆλ‚˜ λ§Žμ€ λ…Έλ“œλ₯Ό κ±΄λ„ˆλ›°λŠ”μ§€λ₯Ό κΈ°λ‘ν•˜μ—¬, νŠΉμ • key의 μˆœμœ„λ₯Ό μ‰½κ²Œ 계산할 수 있고 이λ₯Ό 톡해 검색 μ‹œ λͺ‡ 개의 λ…Έλ“œλ₯Ό κ±΄λ„ˆλ›°μ–΄μ•Ό ν•˜λŠ”μ§€λ₯Ό λΉ λ₯΄κ²Œ μ•Œ 수 μžˆμ–΄μ„œ 탐색 속도λ₯Ό ν–₯μƒμ‹œν‚¨λ‹€κ³  ν•œλ‹€.

예λ₯Ό λ“€μ–΄, span=5인 경우, ν˜„μž¬ λ…Έλ“œ λ‹€μŒμ— 5개의 λ…Έλ“œκ°€ μžˆλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

Redisμ—μ„œ skip list 적용

RedisλŠ” Sorted Set을 λ‚΄λΆ€μ μœΌλ‘œ ZSet이라고 ν•œλ‹€. Sorted Set은 λ‚΄λΆ€μ μœΌλ‘œ 두 κ°€μ§€ 데이터 ꡬ쑰둜 μ €μž₯λœλ‹€. Redisκ°€ 데이터 ꡬ쑰λ₯Ό μ„ νƒν•˜λŠ” 데, 두 κ°€μ§€ 쑰건이 μžˆλ‹€.

  1. member μˆ˜κ°€ 128개 κΉŒμ§€λŠ” zip list μžλ£Œκ΅¬μ‘°μ— μ €μž₯λœλ‹€.

    • λ‹€λ₯Έ ν•˜λ‚˜μ˜ κ°’(value)의 길이가 64byteκΉŒμ§€λŠ” zip list에 μ €μž₯λœλ‹€.

  2. 129κ°œλΆ€ν„°λŠ” 자료ꡬ쑰λ₯Ό λ³€ν™˜ν•΄μ„œ skip list에 μ €μž₯λœλ‹€.

    • 65 byte λΆ€ν„°λŠ” skip list에 μ €μž₯λœλ‹€.

    • μ—¬λŸ¬ 멀버 쀑 ν•˜λ‚˜λΌλ„ 값이 65 byte 이상이면 λ³€ν™˜λœλ‹€.

    • 이 λ‘κ°€μ§€λŠ” OR 쑰건이기 λ•Œλ¬Έμ— ν•˜λ‚˜λΌλ„ 쑰건에 μΆ©μ‘±ν•˜λ©΄ λ ˆλ””μŠ€ μ„œλ²„κ°€ μžλ™μœΌλ‘œ 자료ꡬ쑰λ₯Ό λ³€ν™˜ν•΄μ„œ μ €μž₯ν•œλ‹€.

μ΄λ ‡κ²Œ ν•˜λŠ” μ΄μœ λŠ” member μˆ˜κ°€ 적을 λ•ŒλŠ” zip listκ°€ μ—°μ†λœ λ©”λͺ¨λ¦¬ 곡간을 μ‚¬μš©ν•˜μ—¬ λ©”λͺ¨λ¦¬ μ˜€λ²„ν—€λ“œλ₯Ό 쀄이고, λΉ λ₯Έ μ„±λŠ₯을 μ œκ³΅ν•œλ‹€κ³  ν•œλ‹€. λ§Œμ•½ memberκ°€ λ§Žμ•„μ§€λ©΄ O(logN)의 검색, μ‚½μž…, μ‚­μ œλ₯Ό 보μž₯ν•˜λŠ” skip listκ°€ 더 μ ν•©ν•˜λ‹€κ³  ν•œλ‹€.

이 섀정은 redis.conf의 ADVANCDE CONFIG의 κ°’μœΌλ‘œ μ‘°μ •ν•  수 μžˆλ‹€.

  • zset-max-ziplist-entriesλŠ” Sorted Setμ—μ„œ zip list둜 μ €μž₯ν•  수 μžˆλŠ” μ΅œλŒ€ μ—”νŠΈλ¦¬(member) 수λ₯Ό μ„€μ •ν•˜λŠ” νŒŒλΌλ―Έν„°μ΄λ‹€. 0으둜 μ„€μ •ν•˜λ©΄ μ²˜μŒλΆ€ν„° μŠ€ν‚΅ λ¦¬μŠ€νŠΈμ— μ €μž₯λ˜μ–΄ ν…ŒμŠ€νŠΈ μ‹œ μ„±λŠ₯을 μ’€ 더 μ •ν™•ν•˜κ²Œ νŒŒμ•…ν•  수 μžˆλ‹€.

  • zset-max-ziplist-valueλŠ” zip list둜 μ €μž₯ν•  수 μžˆλŠ” κ°’(value)의 μ΅œλŒ€ 길이이닀.

Last updated