/async-parallel-scan

🐳 ν…Œμ΄λΈ” ν’€μŠ€μΊ”κ³Ό 비동기/λ©€ν‹° μ“°λ ˆλ“œλ₯Ό ν™œμš©ν•œ 데이터 처리.

Primary LanguageKotlin

Full Table Scan with Async & Parallel

비동기λ₯Ό ν™œμš©ν•œ ν…Œμ΄λΈ” ν’€ μŠ€μΊ” μ„±λŠ₯ ν…ŒμŠ€νŠΈ.

ν…Œμ΄λΈ” ν’€ μŠ€μΊ”μ€ ν…Œμ΄λΈ”μ˜ λͺ¨λ“  rowλ₯Ό μ‘°νšŒν•˜κΈ° λ•Œλ¬Έμ—, 데이터가 λ§Žμ„ 경우 일반적으둜 ꢌμž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 데이터가 λ§Žλ”λΌλ„ λΆ„ν• κ³Ό 비동기λ₯Ό ν™œμš©ν•œ 병렬 처리λ₯Ό ν•˜λ©΄ νŠΉμ • μƒν™©μ—μ„œλŠ” κ½€ 쒋은 μ„±λŠ₯을 λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€.





1. μš”κ΅¬ 사항

이벀트 ν”Œλ‘œμš°λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. μ•Œλ¦Ό 솑신은 λ³„λ„μ˜ μ‹œμŠ€ν…œμ΄ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— κ³ λ €ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  1. μ•Œλ¦Ό λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•œλ‹€.
  2. 전체 μ‚¬μš©μžλŠ” 2,000 만 λͺ…이며, μ•Œλ¦Ό μˆ˜μ‹ μ— λ™μ˜ν•œ μ‚¬μš©μžμ—κ²Œλ§Œ μ•Œλ¦Όμ„ μ „μ†‘ν•œλ‹€.
  3. 단일 μ• ν”Œλ¦¬μΌ€μ΄μ…˜/λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€.





Step1. 비동기λ₯Ό ν™œμš©ν•΄ μ•Œλ¦Όμ„ μ „μ†‘ν•œλ‹€.

데이터가 λ§Žμ„ 경우, ν…Œμ΄λΈ” ν’€ μŠ€μΊ”μ„ μ‚¬μš©ν•˜λ©΄ λͺ¨λ“  rowλ₯Ό 읽기 λ•Œλ¬Έμ— μ‹œκ°„μ΄ 였래 걸릴 수 μžˆμœΌλ―€λ‘œ, 비동기λ₯Ό ν™œμš©ν•΄ 이λ₯Ό κ°œμ„ ν•œλ‹€.

  1. λΉ„λ™κΈ°λ‘œ 데이터λ₯Ό μ²˜λ¦¬ν•œλ‹€.
  2. λͺ¨λ‹ˆν„°λ§μ„ 톡해 μžμ› μ‚¬μš©λ₯ μ„ μ²΄ν¬ν•œλ‹€.




Step2. νƒœμŠ€ν¬ μœ μ‹€μ„ λŒ€λΉ„ν•œλ‹€.

메세지 큐(Message Queue)λ₯Ό μ‚¬μš©ν•˜λŠ” 경우, μ˜λ„μΉ˜ μ•Šκ²Œ νƒœμŠ€ν¬κ°€ μœ μ‹€λ˜λŠ” 경우 κ°€ λ°œμƒν•œλ‹€. λ©”μ‹œμ§€κ°€ μœ μ‹€λ  경우, 이λ₯Ό λŒ€λΉ„ν•  수 μžˆλ„λ‘ ν•œλ‹€.

  1. λ©”μ‹œμ§€ μœ μ‹€μ„ λŒ€λΉ„ν•œλ‹€.
  2. λ©”μ‹œμ§€ νλŠ” μ–΄λ–€ 것을 μ‚¬μš©ν•΄λ„ 상관없닀.
  3. μ™ΈλΆ€ λ©”μ‹œμ§• μ‹œμŠ€ν…œμ„ λ„μž…ν–ˆμ„ μ‹œ, μ„±λŠ₯ λ³€ν™”λ₯Ό μΈ‘μ •ν•œλ‹€.







2. 아이디어

μ•„μ΄λ””μ–΄λŠ” λΆ„ν• κ³Ό 비동기λ₯Ό ν™œμš©ν•œ 병렬 처리 μž…λ‹ˆλ‹€.

  • λΆ„ν• 
  • 비동기λ₯Ό ν™œμš©ν•œ 병렬 처리





λ¨Όμ € ν•˜λ‚˜μ˜ 큰 νƒœμŠ€ν¬λ₯Ό μ μ ˆν•œ λ‹¨μœ„(chunk)둜 λΆ„ν• ν•©λ‹ˆλ‹€.

image







각 νƒœμŠ€ν¬λŠ” μžμ‹ μ΄ μ²˜λ¦¬ν•  μž‘μ—…μ˜ μ‹œμž‘/끝점을 μ•Œκ³  μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 데이터 쀑볡 처리λ₯Ό λ°©μ§€ν•˜λ©°, 인덱슀(Index)λ₯Ό ν™œμš©ν•  수 있게 λ©λ‹ˆλ‹€.

image







이후 각 νƒœμŠ€ν¬λ₯Ό 비동기λ₯Ό ν†΅ν•œ λ³‘λ ¬λ‘œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

image







3. κ²°κ³Ό

2,000만 건 처리 μ‹œ 1λΆ„ ~ 1λΆ„ 45초.

# μ•½, 1λΆ„ 31초(91.16)
127.0.0.1:6379> get time::string::startTime
"1710619193857"
127.0.0.1:6379> get time::string::endTime
"1710619285018"
# μ•½ 1λΆ„ 26초(86.45)
127.0.0.1:6379> get time::string::startTime
"1710619455453"
127.0.0.1:6379> get time::string::endTime
"1710619541899"
# μ•½ 1λΆ„ 38초(98.73)
127.0.0.1:6379> get time::string::startTime
"1710619665364"
127.0.0.1:6379> get time::string::endTime
"1710619764089"







4. ν•œκ³„

νƒœμŠ€ν¬ μ‹€ν–‰ 쀑 μƒˆλ‘œμš΄ 데이터가 μΆ”κ°€ 됐을 λ•Œ, 이λ₯Ό μ²˜λ¦¬ν•  수 μžˆλŠ” λ°©μ•ˆμ΄ μ—†μŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 2,000만 μ‚¬μš©μžμ—κ²Œ μ•Œλ¦Όμ„ λ°œμ†‘ν•˜λŠ” 도쀑 μƒˆλ‘œμš΄ μ‚¬μš©μžκ°€ κ°€μž…μ„ ν•œλ‹€λ©΄ 이λ₯Ό λŒ€μ²˜ν•  방법이 μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λͺ¨λ“  둜직이 λλ‚œ ν›„, μƒˆλ‘œ μΆ”κ°€λœ μ‚¬μš©μžλ“€μ€ λ³„λ„μ˜ 둜직으둜 μ²˜λ¦¬ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.

interface UserRepository : JpaRepository<User, Long> {
    @Query("SELECT u FROM user u WHERE u.id > maxUserId")
    fun findByIdOver(maxUserId: Long): List<User>
}

λ˜ν•œ 이 외에도 μ“°λ ˆλ“œ ν’€ 개수 μ„€μ •, 컀λ„₯μ…˜ 관리, λͺ¨λ‹ˆν„°λ§ λ“±μ˜ μΆ”κ°€ μ΄μŠˆκ°€ μžˆμŠ΅λ‹ˆλ‹€. 상세 λ‚΄μš©μ€ λΈ”λ‘œκ·Έλ₯Ό μ°Έμ‘°ν•΄μ£Όμ„Έμš”.