Design Real-time Game Leaderboard

μš”κ΅¬μ‚¬ν•­

  • μƒμœ„ ν”Œλ ˆμ΄μ–΄μ˜ μˆœμœ„ μ‹€μ‹œκ°„ 제곡

  • νŠΉμ • μ‚¬μš©μžμ˜ 일정 λ²”μœ„μ˜ μˆœμœ„ 제곡

  • DAU 500만 λͺ…, MAU 2,500만 λͺ…

  • ν•˜λ£¨ 평균 10 κ²Œμž„ ν”Œλ ˆμ΄

  • μˆœμœ„ λ°˜μ˜μ€ κ°€λŠ₯ν•œ μ‹€μ‹œκ°„μ— κ°€κΉκ²Œ 처리

μœ„ μš”κ΅¬ 사항을 λ§Œμ‘±ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같은 개랡적인 규λͺ¨λ₯Ό μΆ”μ •ν•  수 μžˆλ‹€.

  • μ΄ˆλ‹Ή 평균 μœ μ €: 500만 λͺ… / 24 / 3600 = 57.87 (24μ‹œκ°„ κ³ λ₯΄κ²Œ λΆ„ν¬λ˜μ–΄ μžˆλ‹€κ³  κ°€μ •)

  • μ§„ν–‰ κ²Œμž„: 57.87 * 10 = 578.7 (ν•˜λ£¨ 평균 10κ²Œμž„ ν”Œλ ˆμ΄ν•œλ‹€κ³  κ°€μ •)

  • μ‚¬μš©μž 점수 νšλ“ QPS: 578.7 * 5 = 2,893.5 (피크 μ‹œκ°„μ— 5배의 νŠΈλž˜ν”½μ΄ λ°œμƒν•œλ‹€κ³  κ°€μ •)

  • μˆœμœ„ 쑰회 QPS: 57.87 (졜초 접속 μ‹œ μ‘°νšŒν•œλ‹€κ³  κ°€μ •)

API λ‹¨μœ„ κΈ°λŠ₯ μ •μ˜

  • POST /scores: κ²Œμž„ ν”Œλ ˆμ΄ ν›„ 점수λ₯Ό κΈ°λ‘ν•˜λŠ” API

  • GET /scores: μƒμœ„ ν”Œλ ˆμ΄μ–΄μ˜ μˆœμœ„λ₯Ό μ‘°νšŒν•˜λŠ” API

  • GET /scores/{user_id}: νŠΉμ • μ‚¬μš©μžμ˜ μˆœμœ„λ₯Ό μ‘°νšŒν•˜λŠ” API

개랡적 μ„€κ³„μ•ˆ

κ²Œμž„ μ„œλΉ„μŠ€μ™€ μˆœμœ„ν‘œ μ„œλΉ„μŠ€λ‘œ λ‚˜λˆ„μ–΄ μ•„λž˜μ™€ 같은 νλ¦„μœΌλ‘œ 섀계할 수 μžˆλ‹€.

  1. μ‚¬μš©μžκ°€ κ²Œμž„μ„ ν”Œλ ˆμ΄ν•˜κ³  점수λ₯Ό νšλ“ ν›„ κ²Œμž„ μ„œλΉ„μŠ€μ— μš”μ²­

  2. κ²Œμž„ μ„œλΉ„μŠ€λŠ” μ μˆ˜κ°€ μœ νš¨ν•œμ§€ 확인 ν›„ μˆœμœ„ν‘œ μ„œλΉ„μŠ€μ— 점수 기둝 μš”μ²­

  3. μˆœμœ„ν‘œ μ„œλΉ„μŠ€λŠ” 점수λ₯Ό κΈ°λ‘ν•˜κ³ , ν•΄λ‹Ή μ‚¬μš©μžμ˜ μˆœμœ„λ₯Ό κ°±μ‹ 

    • μˆœμœ„ κ°±μ‹  μ‹œ Redis의 Sorted Set을 μ‚¬μš©ν•˜μ—¬ 점수λ₯Ό λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬

  4. μ‚¬μš©μžλŠ” μ§€μ†μ μœΌλ‘œ μˆœμœ„ν‘œ μ„œλΉ„μŠ€μ— ν”Œλ ˆμ΄μ–΄μ˜ μˆœμœ„λ₯Ό 쑰회

κ²Œμž„ μ„œλΉ„μŠ€μ™€ μˆœμœ„ν‘œ μ„œλΉ„μŠ€ κ°„ ν†΅μ‹ μ—λŠ” 상황에 따라 REST API λ˜λŠ” λ©”μ‹œμ§€ 큐λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

μ €μž₯μ†Œ μš”κ΅¬μ‚¬ν•­ - Redis Sorted Set μ‚¬μš©

μˆœμœ„ 정보λ₯Ό Redis의 Sorted Set을 μ‚¬μš©ν•˜μ—¬ μ €μž₯ν•œλ‹€κ³  κ°€μ •ν•˜κ³ , λ‹€μŒκ³Ό 같은 μš”κ΅¬ 사항이 μžˆλ‹€κ³  κ°€μ •ν•˜μž.

  • μ‚¬μš©μž ID - 점수 ν˜•νƒœλ‘œ μ €μž₯

  • μ›”κ°„ ν™œμ„± μ‚¬μš©μž 2,500만 λͺ… λͺ¨λ‘ μˆœμœ„μ— 포함

  • ID 24 character λ¬Έμžμ—΄ / 점수 16λΉ„νŠΈ μ •μˆ˜ = 26λ°”μ΄νŠΈ

  • 26λ°”μ΄νŠΈ * 2,500만 λͺ… = μ•½ 650MB

650MBλŠ” μ˜€λ²„ν—€λ“œμ™€ μ •λ ¬ μ§‘ν•© ν•΄μ‹œλ₯Ό κ³ λ €ν•΄ 두 λ°°λ₯Ό μ‚¬μš©ν•œλ‹€κ³  κ°€μ •ν•˜λ”λΌλ„, ν•œ λŒ€μ˜ Redis μΈμŠ€ν„΄μŠ€μ— μΆ©λΆ„νžˆ μ €μž₯ν•  수 있으며, 2,900 QPS도 ν•œ λŒ€μ˜ Redisμ—μ„œ μ²˜λ¦¬ν•  수 μžˆλŠ” λ²”μœ„μ΄λ‹€.

Redis Sorted Set λ™μž‘ 방식

Redis의 Sorted Set은 ν•΄μ‹œ ν…Œμ΄λΈ”κ³Ό μŠ€ν‚΅ 리슀트 두 κ°€μ§€ 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„λœλ‹€.

  • ν•΄μ‹œ ν…Œμ΄λΈ”: μ‚¬μš©μžμ˜ 점수 μ €μž₯

  • μŠ€ν‚΅ 리슀트: νŠΉμ • 점수λ₯Ό λ”΄ μ‚¬μš©μžλ“€μ˜ λͺ©λ‘μ„ μ €μž₯

이 쀑 μŠ€ν‚΅λ¦¬μŠ€νŠΈλŠ” λΉ λ₯Έ 검색을 κ°€λŠ₯ν•˜κ²Œ ν•˜λŠ” 자료 ꡬ쑰둜, μ •λ ¬λœ μ—°κ²° λ¦¬μŠ€νŠΈμ— 닀단계 색인을 두어 검색 속도λ₯Ό 높인닀.

1 -------------- 15 ---------------- 60
|                |                   |
1 ----- 8 ------ 15 ------ 36 ------ 60
|       |        |         |         |
1 - 4 - 8 - 10 - 15 - 26 - 36 - 45 - 60 - 68

이진 검색 트리처럼 쀑간 지점에 더 빨리 도달할 수 μžˆλ„λ‘ n차의 색인을 μΆ”κ°€ν•˜μ—¬, 검색 속도λ₯Ό O(log n)으둜 쀄일 수 μžˆλ‹€.

Redis Sorted Set λͺ…λ Ήμ–΄

Redis Sorted Setμ—μ„œ μ‚¬μš©ν•˜κ²Œ λ˜λŠ” λͺ…λ Ήμ–΄λŠ”, λ‹€μŒκ³Ό 같이 ν™œμš©ν•  수 μžˆλ‹€.

  • ZADD: 기쑴에 μ—†λ˜ μ‚¬μš©μžλ₯Ό 집합에 μΆ”κ°€ν•˜κ±°λ‚˜, κΈ°μ‘΄ μ‚¬μš©μž 점수λ₯Ό κ°±μ‹ 

  • ZINCRBY: κΈ°μ‘΄ μ‚¬μš©μž 점수 증감

  • ZRANGE / ZREVRANGE: νŠΉμ • λ²”μœ„μ— μžˆλŠ” μ‚¬μš©μž 쑰회

  • ZRANK / ZREVRANK: νŠΉμ • μ‚¬μš©μžμ˜ μˆœμœ„ 쑰회

상세 섀계

ν΄λΌμš°λ“œ μ„œλΉ„μŠ€ μ‚¬μš©

자체 μ„œλΉ„μŠ€λ₯Ό κ΅¬μΆ•ν•˜λŠ” 경우, Redis와 MySQLλ₯Ό 직접 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•  수 μžˆμ§€λ§Œ, ν΄λΌμš°λ“œ μ„œλΉ„μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€κ³  κ°€μ •ν•˜λ©΄ API Gateway와 AWS λžŒλ‹€ κΈ°μˆ μ„ μ‚¬μš©ν•΄λ³Ό 수 μžˆλ‹€.

  1. API Gatewayλ₯Ό ν˜ΈμΆœν•˜κ³ , ν•΄λ‹Ή κ²Œμ΄νŠΈμ›¨μ΄λŠ” μ μ ˆν•œ AWS λžŒλ‹€ ν•¨μˆ˜λ₯Ό 호좜

  2. λžŒλ‹€ ν•¨μˆ˜λŠ” μŠ€ν† λ¦¬μ§€ κ³„μΈ΅μ˜ λͺ…령을 ν˜ΈμΆœν•˜μ—¬ 얻은 κ²°κ³Όλ₯Ό API Gateway에 λ°˜ν™˜

  3. API GatewayλŠ” λžŒλ‹€ ν•¨μˆ˜μ˜ 응닡을 ν΄λΌμ΄μ–ΈνŠΈμ— λ°˜ν™˜

μ΄λ ‡κ²Œ ν•˜λ©΄, μ„œλ²„ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ§€ μ•Šμ•„λ„ APIλ₯Ό μ œκ³΅ν•  수 있으며, μ„œλ²„ κ΄€λ¦¬μ˜ 뢀담을 쀄일 수 μžˆλ‹€.

λ ˆλ””μŠ€ 규λͺ¨ ν™•μž₯

κΈ°μ‘΄ 규λͺ¨λ³΄λ‹€ 더 큰 규λͺ¨λ‘œ ν™•μž₯ν•˜κΈ° μœ„ν•΄μ„  샀딩이 ν•„μš”ν•œλ°, κ³ μ • νŒŒν‹°μ…˜κ³Ό ν•΄μ‹œ νŒŒν‹°μ…˜ 두 κ°€μ§€ 방법이 μžˆλ‹€.

  • κ³ μ • νŒŒν‹°μ…˜: 점수 λ²”μœ„μ— 따라 νŒŒν‹°μ…˜μ„ λ‚˜λˆ„λŠ” 방법

    • 0100점은 νŒŒν‹°μ…˜ A, 101200점은 νŒŒν‹°μ…˜ B λ“±

    • ν•΄λ‹Ή μ‚¬μš©μžκ°€ μ–΄λŠ νŒŒν‹°μ…˜μ— μ†ν•˜λŠ”μ§€ μ•Œμ•„μ•Ό 함(μ‚¬μš©μžID-점수λ₯Ό μ €μž₯ν•˜λŠ” 2μ°¨ μΊμ‹œλ₯Ό 톡해 μ„±λŠ₯을 높일 수 있음)

    • μ μˆ˜κ°€ κ³ λ₯΄κ²Œ λΆ„ν¬λ˜μ–΄ μžˆμ–΄μ•Ό κΈ°λŒ€ν•˜λŠ” μ„±λŠ₯을 λ‚Ό 수 있음

  • ν•΄μ‹œ νŒŒν‹°μ…˜: λ ˆλ””μŠ€ ν΄λŸ¬μŠ€ν„°κ°€ μžλ™μœΌλ‘œ 샀딩

    • 각각의 ν‚€κ°€ νŠΉμ •ν•œ ν•΄μ‹œ μŠ¬λ‘―μ— μ†ν•˜λ„λ‘ ν•˜λŠ” 샀딩 기법 μ‚¬μš©

      • 16,384개의 ν•΄μ‹œ 슬둯이 있으며, CRC16(key) % 16384둜 ν•΄μ‹œ μŠ¬λ‘―μ„ 계산

      • λ…Έλ“œ λ³„λ‘œ ν•΄μ‹œ 슬둯 λ²”μœ„λ₯Ό ν• λ‹Ή(0 - 5500은 λ…Έλ“œ A, 5501 - 11000은 λ…Έλ“œ B λ“±)

      • ν•΄λ‹Ή μŠ¬λ‘―μ— μ†ν•˜λŠ” λ ˆλ””μŠ€ λ…Έλ“œλ‘œ μš”μ²­μ„ 전달

    • 점수 뢄포가 κ³ λ₯΄μ§€ μ•Šμ•„λ„ μ„±λŠ₯을 μœ μ§€ν•  수 있음

    • μƒμœ„ Nλͺ…μ˜ μ‚¬μš©μž 쑰회 μ‹œ, λͺ¨λ“  λ…Έλ“œμ— μš”μ²­μ„ 보내고 응닡을 합쳐야 ν•˜λ―€λ‘œ μ„±λŠ₯이 μ €ν•˜λ  수 있음

μ„œλΉ„μŠ€ νŠΉμ„±μƒ μƒμœ„ Nλͺ…μ˜ μ‚¬μš©μž μ‘°νšŒκ°€ λΉˆλ²ˆν•˜κ²Œ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ—, κ³ μ • νŒŒν‹°μ…˜μ„ μ‚¬μš©ν•˜λŠ” 것이 더 적합할 수 μžˆλ‹€.

μΆ”κ°€ 고렀사항

더 λΉ λ₯Έ 쑰회 및 λ™μ μž μˆœμœ„ νŒμ •

λ ˆλ””μŠ€ ν•΄μ‹œλ₯Ό μ‚¬μš©ν•˜λ©΄ λ¬Έμžμ—΄ ν•„λ“œμ™€ κ°’ μƒμ˜ λŒ€μ‘κ΄€κ³„λ₯Ό μ €μž₯ν•˜μ—¬ ν™œμš©ν•  수 μžˆλ‹€.

  1. μˆœμœ„ν‘œμ— ν‘œμ‹œν•  μ‚¬μš©μž ID와 μ‚¬μš©μž 객체 μ‚¬μ΄μ˜ λŒ€μ‘ 관계λ₯Ό μ €μž₯

    • λ°μ΄ν„°λ² μ΄μŠ€μ— 질의 ν•˜μ§€ μ•Šκ³ , λΉ λ₯΄κ²Œ μ‚¬μš©μž 정보λ₯Ό μ‘°νšŒν•  수 있음

  2. 두 μ‚¬μš©μž μ μˆ˜κ°€ 같은 경우 λˆ„κ°€ λ¨Όμ € 점수λ₯Ό νšλ“ν–ˆλŠ”μ§€ νŒλ³„ν•˜κΈ° μœ„ν•΄, μ‚¬μš©μž ID와 점수 νšλ“ μ‹œκ°„μ„ ν•¨κ»˜ μ €μž₯

    • λ™μ μž μˆœμœ„ νŒλ³„μ„ μœ„ν•΄ μ‹œκ°„ 정보λ₯Ό μΆ”κ°€ν•˜μ—¬, 동일 점수의 μ‚¬μš©μž 쀑 λ¨Όμ € 점수λ₯Ό νšλ“ν•œ μ‚¬μš©μžκ°€ μƒμœ„ μˆœμœ„λ₯Ό μ°¨μ§€ν•˜λ„λ‘ 함

μ‹œμŠ€ν…œ μž₯μ•  볡ꡬ

μ‹œμŠ€ν…œ μž₯μ• κ°€ λ°œμƒν–ˆμ„ λ•Œ, λ‹€μŒκ³Ό 같은 볡ꡬ 방법을 κ³ λ €ν•  수 μžˆλ‹€.

  • RDB μŠ€λƒ…μƒ· / AOF(Append Only File) 둜그λ₯Ό μ‚¬μš©ν•˜μ—¬ Redis 데이터λ₯Ό 볡ꡬ

  • MySQL에 점수 증감 이λ ₯을 μ €μž₯ν•˜μ—¬, ZADD / ZINCRBY λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•΄ 점수λ₯Ό 볡ꡬ

참고자료

Last updated

Was this helpful?