Skip to content

final17/project-w

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

444 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

์›จ์ดํ‹ฐ ํ”„๋กœ์ ํŠธ

๐Ÿ“– ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

๋ง›์ง‘ ์˜ˆ์•ฝ ์„œ๋น„์Šค๋Š” ์‚ฌ์šฉ์ž๋“ค์ด ์†์‰ฝ๊ฒŒ ๋ง›์ง‘์„ ์˜ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ์ด ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๊ฒŒ ๋œ ์ด์œ ๋Š”, ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ง›์ง‘ ์˜ˆ์•ฝ ๊ณผ์ •์—์„œ ๊ฒช๋Š” ๋ถˆํŽธํ•จ์„ ํ•ด์†Œํ•˜๊ณ ์ž ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋‹ค์–‘ํ•œ ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•ด ์ง๊ด€์ ์ด๊ณ  ํŽธ๋ฆฌํ•œ ์˜ˆ์•ฝ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

โŒš ํ”„๋กœ์ ํŠธ ํ•ต์‹ฌ ๋ชฉํ‘œ

  1. ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ ๋Œ€์‘

    • Jmeter๋ฅผ ํ™œ์šฉํ•ด์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ๊ธฐ๋Šฅ๋“ค ๋ฐœ๊ฒฌ ํ›„ ๋™์‹œ์„ฑ ํ•ด๊ฒฐ ๋Œ€๊ธฐ์—ด ๋ฐ ํŠธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ Redis ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ•ด ์•ˆ์ •์ ์ธ ์„ฑ๋Šฅ์„ ํ™•๋ณด.
  2. ์„ฑ๋Šฅ ์ตœ์ ํ™”

    • Redis์˜ RAtomicLong, RScoreSortedSet, RQueue, RMap ๋“ฑ์„ ๋น„๊ตํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์ตœ์ ์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์„ ํƒํ•ด ์ฒ˜๋ฆฌ ์†๋„๋ฅผ ๊ฐœ์„ .
    • Redis ๊ธฐ๋ฐ˜ ์บ์‹ฑ์œผ๋กœ ์‹ค์‹œ๊ฐ„ ์ƒํ’ˆ ์กฐํšŒ ์„ฑ๋Šฅ์„ 3๋ฐฐ ํ–ฅ์ƒ.
    • Redisson์„ ์‚ฌ์šฉํ•˜์—ฌ CPU ์ ์œ ์œจ 50% ๊ฐ์†Œ ๋ฐ ์•ˆ์ •์  ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ตฌํ˜„.
    • Redis ์บ์‹ฑ์„ ์ด์šฉํ•ด์„œ 100๋งŒ๊ฑด ๋ฐ์ดํ„ฐ์—์„œ ์Œ์‹์  ์ด๋ฆ„์„ ์กฐํšŒํ•  ๋•Œ 1048.9ms์—์„œ 4.32ms๋กœ ์•ฝ 24278% ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    • ์ดํ›„, ์—˜๋ผ์Šคํ‹ฑ ์„œ์น˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฒ€์ƒ‰ ์†๋„ ๊ฐœ์„  ๋ฐ ๊ฒ€์ƒ‰ ์ •ํ™•๋„ ํ–ฅ์ƒ
  3. ์šด์˜ ๋ฐ ๋ฐฐํฌ ํšจ์œจํ™”

    • Jenkins, Docker, Github Actions, AWS EC2์„ ์ด์šฉํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•์œผ๋กœ ๋ฐฐํฌ ์ž๋™ํ™”.
    • Slack ์•Œ๋ฆผ์„ ์„ค์ •ํ•˜์—ฌ ๋ฐฐํฌ ์ƒํƒœ ๋ฐ ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํŒ€์›๋“ค์—๊ฒŒ ์ „๋‹ฌํ•ด ํ˜‘์—… ํšจ์œจ์„ฑ ๊ฐ•ํ™”.
    • ๋ณด์•ˆ ๊ทธ๋ฃน ์„ค์ •๊ณผ SSL ์ธ์ฆ์„œ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋ณด์•ˆ์„ฑ์„ ๊ฐ•ํ™”ํ•œ ๋ฐฐํฌ ํ™˜๊ฒฝ ๊ตฌ์ถ•.
  4. ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ž๋™ํ™”

    • Spring Batch์™€ Scheduler๋ฅผ ํ†ตํ•ด ์ง‘๊ณ„๋ฅผ ์ž๋™ํ™”ํ•˜๊ณ  QueryDSL๋ฅผ ํ†ตํ•ด ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ ๋ฐ ์ฒ˜๋ฆฌ ์ตœ์ ํ™”
    • ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์–‘ํ•œ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ถ„์‚ฐ ์ €์žฅํ•˜์—ฌ ํ›„์† ๋ถ„์„ ๋ฐ ๋ณด๊ณ ์— ์ตœ์ ํ™”๋œ ๊ตฌ์กฐ ๊ตฌํ˜„
  5. ์›น ํฌ๋กค๋ง

    • ์Œ์‹์  ์ด๋ฆ„๊ณผ ์ง€์—ญ๋ช… ์ถ”์ถœ ํ›„ "๋ง›์ง‘" ํ‚ค์›Œ๋“œ ์ถ”๊ฐ€ ํ•˜์—ฌ ๋„ค์ด๋ฒ„ ๊ธฐ๋ฐ˜ ์›น ํฌ๋กค๋ง
    • Redis ์บ์‹œ ๋ฐ ec2 ํ”„๋ก์‹œ ip๋ฅผ ํ™•์šฉํ•˜์—ฌ ๋„ค์ด๋ฒ„ ip๋ฐด ๊ฐ€๋Šฅ์„ฑ ์ถ•์†Œ

๐Ÿ“š ๊ธฐ์ˆ  ์Šคํƒ

๐Ÿ’ป Developers

Java Spring Spring Spring MySQL ELK Redis AWS EC2 AWS RDS AWS S3 GitHub Actions YAML

๐ŸŽ›๏ธ ํ™˜๊ฒฝ

IntelliJ IDEA Notion Slack GitHub macOS Windows


KEY Summary

๐Ÿ›  ์˜ˆ์•ฝ ๋Œ€๊ธฐ์—ด ๋™์‹œ์„ฑ ์ด์Šˆ
โš ๏ธ ๋ฌธ์ œ ๋ฐœ๊ฒฌ
  • ํ˜„์ƒ: JMeter๋กœ 1,000๋ช…์˜ ์œ ์ €๊ฐ€ ๋™์‹œ์— ๋Œ€๊ธฐ์—ด์— ๋“ฑ๋กํ–ˆ์„ ๋•Œ, ๋ฐœ๊ถŒ ๋ฒˆํ˜ธ๊ฐ€ ์ค‘๋ณต์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋™์‹œ์„ฑ ์ด์Šˆ๊ฐ€ ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ” ์ƒํ™ฉ ๋ถ„์„
  • ๋ถ„์„: ๋Œ€๊ธฐ์—ด ๋“ฑ๋ก ๋กœ์ง์— ๋™์‹œ์— ์ ‘๊ทผ ์‹œ ๋ฐœ๊ถŒ๋ฒˆํ˜ธ๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์ค‘๋ณต๋œ ๋ฒˆํ˜ธ๊ฐ€ ์ €์žฅ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ“ 1์ฐจ ์‹œ๋„: synchronized ์‚ฌ์šฉ
  • ๋ฐฉ๋ฒ•: ๋ฐœ๊ถŒ๋ฒˆํ˜ธ ์ฆ๊ฐ€ ๋ถ€๋ถ„์— synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์ ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ: ์ค‘๋ณต์ด ์ค„์–ด๋“ค์—ˆ์ง€๋งŒ ์™„์ „ํžˆ ํ•ด๊ฒฐ๋˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.
    • @Transactional๋กœ ์ธํ•ด synchronized๊ฐ€ ๋๋‚œ ํ›„ ์ปค๋ฐ‹ ์‹œ์ ์—์„œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋“ค์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์ž„์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ”’ 2์ฐจ ์‹œ๋„: ๋น„๊ด€์  ๋ฝ(Pessimistic Lock) ์ ์šฉ
  • ๋ฐฉ๋ฒ•: ๋™์‹œ์„ฑ ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ํ™˜๊ฒฝ์„ ๊ณ ๋ คํ•ด, ๋น„๊ด€์  ๋ฝ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐœ๊ถŒ๋ฒˆํ˜ธ ํ…Œ์ด๋ธ”์˜ ์ค‘๋ณต ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ: ์ค‘๋ณต ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋˜์—ˆ์œผ๋‚˜, ๋†’์€ ํŠธ๋ž˜ํ”ฝ ์ƒํ™ฉ์—์„œ ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•˜์—ฌ ์ผ๋ถ€ ํŠธ๋žœ์žญ์…˜์ด ๋กค๋ฐฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    • show engine innodb status ๋ช…๋ น์–ด๋กœ ๋ฐ๋“œ๋ฝ ๋กœ๊ทธ๋ฅผ ๋ถ„์„ํ•œ ๊ฒฐ๊ณผ, ๋™์ผํ•œ storeId์™€ waiting_number ๊ฐ’์„ ์‚ฝ์ž…ํ•˜๋ ค๋Š” ํŠธ๋žœ์žญ์…˜ ๊ฐ„์˜ ์ถฉ๋Œ๋กœ ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•œ ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ’ก 3์ฐจ ์‹œ๋„: Redis๋กœ ์ „ํ™˜
  • ๋ฐฉ๋ฒ•: RDB ๋Œ€์‹  Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ์ˆœ์ฐจ์  ์ฒ˜๋ฆฌ๋ฅผ ์œ ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. Redis๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜์ด๋ฏ€๋กœ Lock ์—†์ด๋„ ํšจ์œจ์ ์œผ๋กœ ๋™์‹œ์„ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ: ์ฒ˜๋ฆฌ์œจ์ด ์•ฝ 43.2% ๊ฐœ์„ ๋˜์—ˆ๊ณ , ์‘๋‹ต ์‹œ๊ฐ„๋„ ์•ฝ 30.8% ๋‹จ์ถ•๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    • ๋˜ํ•œ, Redis์˜ ๋ฐ์ดํ„ฐ ํœ˜๋ฐœ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ณ ๋ฏผํ•˜์˜€์Šต๋‹ˆ๋‹ค.
      • ๋ ˆ๋””์Šค ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์„ฑ ๋ฐ AOF ์˜ต์…˜ ์ถ”๊ฐ€
      • ๋ ˆ๋””์Šค ์„œ๋ฒ„ ๋‹ค์šด ์‹œ ์Šฌ๋ž™ ์•Œ๋ฆผ ๊ธฐ๋Šฅ


๐Ÿ” ์Œ์‹์  ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์†๋„ ํ–ฅ์ƒ
  1. ๋ฐฐ๊ฒฝ

    • 100๋งŒ๊ฑด ์ •๋„์˜ ํฐ ๋ฐ์ดํ„ฐ๋ฅผ LIKE๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰
  2. ๋ฌธ์ œ

    • ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ 1์ดˆ ์ •๋„๋กœ ๋А๋ ค ๊ฒ€์ƒ‰ ์†๋„ ํ–ฅ์ƒ์ด ํ•„์š”ํ•จ
  3. ํ•ด๊ฒฐ ๋ฐฉ์•ˆ

    • ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ํ–ฅ์ƒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•
      1. index๋ฅผ ์ ์šฉํ•œ๋‹ค.
      2. Redis ์บ์‹œ๋ฅผ ์ด์šฉํ•œ๋‹ค.
    1์ฐจ ์‹œ๋„: index๋ฅผ ์ ์šฉ
    • Single Index: ํ•˜๋‚˜์˜ ์ปฌ๋Ÿผ์— ์ธ๋ฑ์Šค๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ•ด๋‹น ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰์„ ์ตœ์ ํ™”
      • ์ธ๋ฑ์Šค๋ฅผ ํƒ€๊ณ  ๊ฒ€์ƒ‰๋œ ๋‚ด์šฉ์€ 0.843 sec -> 0.031 sec๋กœ ์†๋„๊ฐ€ ํ–ฅ์ƒ๋จ
      • Single Index๋ฅผ ํƒ€๊ณ  ๊ฒ€์ƒ‰๋œ ๋‚ด์šฉ์€ ์†๋„๊ฐ€ ๋นจ๋ผ์กŒ์ง€๋งŒ ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ์•Š๋Š” ๋‚ด์šฉ์€ ์†๋„ํ–ฅ์ƒ์ด ์•ˆ๋จ
      • Single Index ํŠน์„ฑ์ƒ "๊ฒ€์ƒ‰์–ด%"๋งŒ ์ธ๋ฑ์Šค๋ฅผ ํƒ€๊ณ , "%๊ฒ€์ƒ‰์–ด" ๋˜๋Š” "%๊ฒ€์ƒ‰์–ด%"๋Š” ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ
    • Full text index: ์ „๋ฌธ ๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค๋กœ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ๊ฒ€์ƒ‰์„ ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•œ ์ธ๋ฑ์Šค
      • full text index ๋˜ํ•œ "๊ฒ€์ƒ‰์–ด%"๋งŒ ์ธ๋ฑ์Šค๋ฅผ ํƒ€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ
    • Full text index N-Gram: n-gram ๋ฐฉ์‹์€ full text index์™€ single index์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊ฒƒ ๊ฐ™์•„ ๋„์ž…
      • full text index๋กœ ์ธํ•ด ๊ฒ€์ƒ‰์˜ ์ •ํ™•๋„๋Š” Like๋ณด๋‹ค ๋†’์•„์กŒ์ง€๋งŒ ์†๋„๋Š” ๋” ๋А๋ ค์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒ
      • ์œ„ ํ˜„์ƒ์˜ ์ด์œ ๋ฅผ ์ฐพ์•„๋ณธ ๊ฒฐ๊ณผ full text index์˜ n-gram์˜ ๊ฒฝ์šฐ ์ ‘๋‘์–ด ๊ฒ€์ƒ‰์—์„œ๋Š” like๋ณด๋‹ค ๋น ๋ฅธ ์„ฑ๋Šฅ์„ ๋ณด์—ฌ์ฃผ์—ˆ์ง€๋งŒ ์ ‘๋ฏธ์–ด ๊ฒฝ์šฐ์—๋Š” like๋ณด๋‹ค ๋А๋ฆฐ ์†๋„๋ฅผ ๋ณด์—ฌ์ฃผ์–ด ์ผ๊ด€๋œ ๊ฒ€์ƒ‰์†๋„๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ
      • ๊ฐ€๋” like๋ณด๋‹ค 10๋ฐฐ ์ •๋„ ๋А๋ฆฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ
    2์ฐจ ์‹œ๋„: Redis ์บ์‹ฑ ์ ์šฉ
    • Redis ์บ์‹ฑ ์ „๋žต์— ๋งž๋Š”์ง€? ์Œ์‹์ ์˜ ๋‚ด์šฉ๊ณผ ์ด๋ฆ„์€ ๋ณ€๊ฒฝ์ด ์ ๊ณ , ๊ฒ€์ƒ‰์ด ๋งค์šฐ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— Redis ์บ์‹ฑ์— ์ ํ•ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐ
    • Redis์—๋Š” ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์—†์–ด dto๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์„œ 10๊ฑด์”ฉ ์ €์žฅ
    • ๊ฒฐ๊ณผ: 1048ms -> 4.32ms๋กœ ์†๋„๊ฐ€ ํ–ฅ์ƒ๋จ
  4. ๊ฒฐ๊ณผ

    • ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ 1048.90ms์—์„œ 4.32ms๋กœ ํ–ฅ์ƒ๋˜์—ˆ๋‹ค.

โš™๏ธ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ
  1. ๋ฐฐ๊ฒฝ
  • ๊ฐ€๊ฒŒ, ๋ฉ”๋‰ด, ๋ฆฌ๋ทฐ ์ข‹์•„์š” ๊ธฐ๋Šฅ
  1. ๋ฌธ์ œ
  • ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๋™์ผํ•œ ๊ฐ€๊ฒŒ, ๋ฉ”๋‰ด, ํ˜น์€ ๋ฆฌ๋ทฐ์— ๋Œ€ํ•ด ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ์ทจ์†Œํ•˜๋Š” ์š”์ฒญ์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ
    • ์ข‹์•„์š” ์ค‘๋ณต ์ €์žฅ: ๋‘ ๊ฐœ์˜ "์ข‹์•„์š”"๊ฐ€ ์ค‘๋ณต์œผ๋กœ ์ €์žฅ๋˜์–ด ์‹ค์ œ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํƒœ๊ฐ€ ๋ถˆ์ผ์น˜ํ•˜๊ฒŒ ๋จ.
    • ์ค‘๋ณต ์ทจ์†Œ: ์ด๋ฏธ ์ทจ์†Œ๋œ ์ข‹์•„์š”๋ฅผ ๋‹ค์‹œ ์ทจ์†Œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ํ•ด์นจ.
    • ์ข‹์•„์š” ์ˆ˜์˜ ๋ถˆ์ผ์น˜: ์š”์ฒญ์ด ๊ฒฝํ•ฉํ•˜๋Š” ๋™์•ˆ ์ข‹์•„์š” ์ถ”๊ฐ€์™€ ์ทจ์†Œ๊ฐ€ ํ˜ผ์žฌ๋˜์–ด ์ตœ์ข…์ ์ธ ์ข‹์•„์š” ์ˆ˜๊ฐ€ ๋น„์ •์ƒ์ ์œผ๋กœ ๊ธฐ๋ก๋จ.
  1. ํ•ด๊ฒฐ ๋ฐฉ์•ˆ
  • Redisson์˜ ๋ถ„์‚ฐ ๋ฝย RLock์„ ๋„์ž…
    • ๋ฝ ์ƒ์„ฑ ๋ฐ ๊ด€๋ฆฌ: Redis์˜ RLock์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค๋ณ„๋กœ ๊ณ ์œ ํ•œ ๋ฝ ํ‚ค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: lock:like:<entity_id> ํ˜•ํƒœ์˜ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด ํŠน์ • ๊ฐ€๊ฒŒ, ๋ฉ”๋‰ด, ๋ฆฌ๋ทฐ์— ๋Œ€ํ•œ ๋ฝ์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ด€๋ฆฌ.
    • ๋ฝ ํš๋“: lock.tryLock ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฝ์„ ํš๋“ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๊ธฐ ์‹œ๊ฐ„ ๋™์•ˆ ๋ฝ์„ ์‹œ๋„ํ•˜๋ฉฐ, ๋ฝ์„ ํš๋“ํ•˜๋ฉด ์ง€์ •๋œ ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ณด์žฅ.
    • ๋™์‹œ์„ฑ ์ œ์–ด: ๋ฝ์„ ํ†ตํ•ด ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ toggleLike ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฝ ํ•ด์ œ: ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ๋ฝ์„ ํ•ด์ œํ•˜์—ฌ ๋‹ค๋ฅธ ์š”์ฒญ์ด ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉ.
  1. ๊ฒฐ๊ณผ
  • ์ข‹์•„์š” ์ค‘๋ณต ๋ฐฉ์ง€: ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•ด ๋™์‹œ ์ ‘๊ทผ์ด ์ง๋ ฌํ™”๋˜์–ด, ๋‘ ๊ฐœ์˜ "์ข‹์•„์š”"๊ฐ€ ์ค‘๋ณต์œผ๋กœ ์ €์žฅ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€.
  • ์ข‹์•„์š” ์ทจ์†Œ ์ค‘๋ณต ๋ฐฉ์ง€: ์ด๋ฏธ ์ทจ์†Œ๋œ ์ข‹์•„์š”์— ๋Œ€ํ•ด ์ถ”๊ฐ€์ ์ธ ์ทจ์†Œ ์š”์ฒญ์ด ๋ฌด์‹œ๋จ.
  • ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ: ์ข‹์•„์š” ์ถ”๊ฐ€ ๋ฐ ์ทจ์†Œ๊ฐ€ ๊ต์ฐจ๋˜๋Š” ์ƒํ™ฉ์—์„œ๋„ ์ตœ์ข…์ ์ธ ์ข‹์•„์š” ์ˆ˜๊ฐ€ ์ •ํ™•ํžˆ ๋ฐ˜์˜๋จ.
  • ์„ฑ๋Šฅ ์ €ํ•˜ ์ตœ์†Œํ™”: Redis์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ ์ฒ˜๋ฆฌ๋กœ ์ธํ•ด ๋ฝ์„ ์‚ฌ์šฉํ•˜๋Š” ์ž‘์—…์—์„œ๋„ ์„ฑ๋Šฅ ์†์‹ค์ด ์ตœ์†Œํ™”๋จ.

โฐ ์Šคํ”„๋ง ๋ฐฐ์น˜ ๋„์ž…
  1. ๋ฐฐ๊ฒฝ
    • ์Šคํ”„๋ง ๋ฐฐ์น˜ ๋„์ž…
      • ์ •์‚ฐ ๋˜๋Š” ์›จ์ดํŒ… ๋ฐ์ดํ„ฐ๋Š” ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ๋ณด๋‹ค๋Š” ์‹œ์Šคํ…œ ๋ถ€๋‹ด์ด ์ ์€ ์‹œ๊ฐ„๋Œ€์— ์ผ๊ด„์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ํ•„์š”์„ฑ์— ์˜ํ•ด ๋ฐฐ์น˜ ๋ฐฉ์‹์„ ์„ ํƒ
      • ์•ˆ์ •์ ์ธ ์šด์˜์„ ์œ„ํ•ด ๋ฉ”์ธ DB์™€ ๋ฐฐ์น˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ DB๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ๋…๋ฆฝ์ ์ธ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑ
    • ๋ฐฐ์น˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ…Œ์ด๋ธ” ์ƒ์„ฑ ํ•„์ˆ˜ํ™”
      • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ „์šฉ DB๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ตฌ์กฐ๋กœ ์ „ํ™˜
    • ๋ฉ€ํ‹ฐ DataSource ๊ตฌ์„ฑ
      • ๋ฉ”์ธ๋ฐฐ์น˜ MetaDBConfig๊ณผ DataDBConfig๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋“ˆ ๊ตฌ๋ถ„
  2. ๋ฌธ์ œ
    • DB ๋ถ„๋ฆฌ ์„ค์ • ์—๋Ÿฌ
      • application.yml์— ์„ค์ • ์—๋Ÿฌ๋กœ ์ธํ•œ ๋ฉ”ํƒ€ ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋ถˆ๊ฐ€
    • ์นด๋ฉœ๋ฌธ๋ฒ• -> ์Šค๋„ค์ดํฌ๋ฌธ๋ฒ• ๋ณ€ํ™˜ ์—๋Ÿฌ
      • DB์— ์ ‘๊ทผํ•˜์—ฌ Query๋กœ ๋ณ€ํ™˜์‹œ ๋ฌธ๋ฒ• ๋ณ€ํ™˜์ด ์•ˆ๋˜๋Š” ์—๋Ÿฌ ๋ฐœ์ƒ
  3. ํ•ด๊ฒฐ ๋ฐฉ์•ˆ
    • DB ๋ถ„๋ฆฌ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
      • DB์— ๋งž๋Š” ์Šคํ‚ค๋งˆ๋ฅผ ์ฐพ์•„์„œ ์ถ”๊ฐ€ ์„ค์ •
    • ์นด๋ฉœ๋ฌธ๋ฒ• -> ์Šค๋„ค์ดํฌ๋ฌธ๋ฒ• ๋ณ€ํ™˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
      • CamelCaseToUnderscoresNamingStrategy ์ถ”๊ฐ€ ์„ค์ •
      • SpringImplicitNamingStrategy ์ถ”๊ฐ€ ์„ค์ •
  4. ๊ด€๋ จ ๋งํฌ : https://github.com/final17/batch

์ธํ”„๋ผ ์•„ํ‚คํ…์ฒ˜ & ์ ์šฉ ๊ธฐ์ˆ 

์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ

image

๐Ÿ“ฆ ์ ์šฉ ๊ธฐ์ˆ  ์ƒ์„ธ๋ณด๊ธฐ

๐Ÿ’พ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ์บ์‹ฑ

  1. Redis
  • ์ ์šฉ ์œ„์น˜: ์บ์‹œ ์„œ๋ฒ„, ๋Œ€๊ธฐ์—ด, ์ข‹์•„์š” ๊ธฐ๋Šฅ, ์กฐํšŒ ์ˆ˜
  • ์‚ฌ์šฉ ์ด์œ : ๋™์‹œ์„ฑ ์ œ์–ด์™€ ์บ์‹ฑ์„ ์œ„ํ•ด ๋ ˆ๋””์Šค๋ฅผ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  1. Redis Cluster
  • ์ ์šฉ ์œ„์น˜: ๋ ˆ๋””์Šค, Docker-compose๋กœ ๊ตฌ์„ฑ

    • ์‚ฌ์šฉ ์ด์œ : ๊ณ ๊ฐ€์šฉ์„ฑ์„ ์œ„ํ•ด ๋ ˆ๋””์Šค ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์„ฑ ๋ฐ AOF ์˜ต์…˜์„ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
    docker-compose.yml
    services:
      redis-master-1:
        container_name: redis-master-1
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7001" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7001" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17001" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7001:7001"
          - "17001:17001"
        networks:
          - redis-cluster-network
    
      redis-master-2:
        container_name: redis-master-2
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7002" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7002" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17002" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7002:7002"
          - "17002:17002"
        networks:
          - redis-cluster-network
    
      redis-master-3:
        container_name: redis-master-3
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7003" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7003" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17003" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7003:7003"
          - "17003:17003"
        networks:
          - redis-cluster-network
    
      redis-replica-1:
        container_name: redis-replica-1
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7004" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7004" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17004" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7004:7004"
          - "17004:17004"
        networks:
          - redis-cluster-network
    
      redis-replica-2:
        container_name: redis-replica-2
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7005" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7005" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17005" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7005:7005"
          - "17005:17005"
        networks:
          - redis-cluster-network
    
      redis-replica-3:
        container_name: redis-replica-3
        image: redis:latest
        command: >
          sh -c 'echo "bind 0.0.0.0" > /etc/redis.conf &&
                echo "port 7006" >> /etc/redis.conf &&
                echo "cluster-enabled yes" >> /etc/redis.conf &&
                echo "cluster-config-file node.conf" >> /etc/redis.conf &&
                echo "cluster-node-timeout 5000" >> /etc/redis.conf &&
                echo "cluster-announce-port 7006" >> /etc/redis.conf &&
                echo "cluster-announce-ip ${HOST_IP}" >> /etc/redis.conf &&
                echo "cluster-announce-bus-port 17006" >> /etc/redis.conf &&
                echo "protected-mode no" >> /etc/redis.conf &&
                redis-server /etc/redis.conf'
        ports:
          - "7006:7006"
          - "17006:17006"
        networks:
          - redis-cluster-network
    
      redis-cluster-entry:
        container_name: redis-cluster-entry
        image: redis:latest
        command: redis-cli --cluster create redis-master-1:7001 redis-master-2:7002 redis-master-3:7003 redis-replica-1:7004 redis-replica-2:7005 redis-replica-3:7006 --cluster-replicas 1 --cluster-yes
        depends_on:
          - redis-master-1
          - redis-master-2
          - redis-master-3
          - redis-replica-1
          - redis-replica-2
          - redis-replica-3
        networks:
          - redis-cluster-network
    
    networks:
      redis-cluster-network:
        driver: bridge
    
  1. MYSQL
  • ์ ์šฉ ์œ„์น˜: AWS RDS
  • ์‚ฌ์šฉ ์ด์œ : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ฆฌ ์ž‘์—…(๋ฐฑ์—…, ํŒจ์น˜, ๋ชจ๋‹ˆํ„ฐ๋ง ๋“ฑ) ์ž๋™ํ™”ํ•˜์—ฌ ๋ถ€๋‹ด์„ ์ค„์—ฌ์ฃผ๊ณ  ์žฅ์•  ๋ฐœ์ƒ์‹œ ์ž๋™์œผ๋กœ ๋Œ€์ฒด ์ธ์Šคํ„ด์Šค๋กœ ์ „ํ™˜ํ•˜์—ฌ ๊ณ ๊ฐ€์šฉ์„ฑ์„ ์ œ๊ณต.

๐ŸŒ ์ธํ”„๋ผ ๋ฐ ๋ฐฐํฌ

  1. Jenkins

    • ์ ์šฉ ์œ„์น˜: AWS EC2์— ๋ฐฐํฌ
      • ์‚ฌ์šฉ ์ด์œ : ์ž๋™ํ™”๋œ ๋นŒ๋“œ์™€ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ ๊ด€๋ฆฌ๋กœ ์ผ๊ด€๋œ ๋ฐฐํฌ ํ”„๋กœ์„ธ์Šค ๊ตฌํ˜„.

        Main Project Jenkins ๊ตฌ์„ฑ
          pipeline {
              agent any
              environment {
                  AWS_PUBLIC_IP = 'ubuntu@3.36.56.171'
                  DOCKER_HUB = 'aysel0413'
                  DOCKER_IMAGE = 'project-w'
                  DOCKER_TAG = '0.1'
              }
              stages {
                 stage('start') {
                     steps {
                         slackSend (
                             channel: '#jenkins',
                             color: '#FFFF00',
                             message: "START: Job ${env.JOB_NAME} [${env.BUILD_NUMBER}]"
                         )
                     }
                 }
                 stage('Git Clone') {
                     steps {
                         git branch: 'dev', 
                         credentialsId: 'github-access-token', 
                         url: 'https://github.com/final17/project-w.git'
                     }
                 }
                 stage('Build') {
                     steps {
                         dir('./') {
                             sh 'chmod +x ./gradlew'
                             sh './gradlew clean bootJar'
                         }
                     }
                 }
                 stage('Test') {
                     steps {
                         // ํ…Œ์ŠคํŠธ ๋‹จ๊ณ„ ์‹คํ–‰
                         dir('./') {
                             sh './gradlew test'
                         }
                     }
                 }
                 stage('DockerFile Build') {
                     steps{
                         dir("./") {
                             script {
                                 dockerimage = docker.build("${DOCKER_HUB}/${DOCKER_IMAGE}:${DOCKER_TAG}")
                             }
                         }   
                     }
                 }
                 stage('Docker Image Push') {
                     steps {
                         script {
                             withDockerRegistry(credentialsId:"docker-access-token") {
                                 dockerimage.push()
                             }
                         }
                     }
                 }
                 stage('Deploy') {
                     steps {
                         sshagent(credentials: ['aws_key']) {
                             sh '''
                                 ssh -o StrictHostKeyChecking=no ${AWS_PUBLIC_IP} << EOF
                                 docker container stop app
                                 docker image prune -f
                                 docker pull ${DOCKER_HUB}/${DOCKER_IMAGE}:${DOCKER_TAG}
                                 docker run -d --rm -p 8080:8080 --env-file ./config/.env --name app ${DOCKER_HUB}/${DOCKER_IMAGE}:${DOCKER_TAG}
                                 exit
                                 EOF
                             '''
                            }
                        }
                    }
                }
                post {
                    success {
                         slackSend (
                             channel: '#jenkins',
                             color: '#00FF00',
                             message: """
                                     SUCCESS: Job ${env.JOB_NAME} [${env.BUILD_NUMBER}]
                                     """
                         )
                    }
                    failure {
                         slackSend (
                             channel: '#jenkins',
                             color: '#FF0000',
                             message: "FAIL: Job ${env.JOB_NAME} [${env.BUILD_NUMBER}]"
                         )
                    }
                }
           }
        
  2. Docker

    • ์ ์šฉ ์œ„์น˜: ๋ชจ๋“  ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆํ™”
    • ์‚ฌ์šฉ ์ด์œ : ํ™˜๊ฒฝ ์ด์‹์„ฑ์„ ๋†’์—ฌ ์šด์˜ ํ™˜๊ฒฝ ๊ฐ„์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๊ณ  ๋ฐฐํฌ ์†๋„ ๊ฐœ์„ . ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค ๊ฐ„์˜ ์˜์กด์„ฑ์„ ๊ฒฉ๋ฆฌํ•˜์—ฌ ์•ˆ์ •์ ์ธ ์šด์˜ ํ™˜๊ฒฝ ๊ตฌ์ถ•.
  3. Github Actions

    • ์ ์šฉ ์œ„์น˜: CI/CD ํŒŒ์ดํ”„๋ผ์ธ
    • ์‚ฌ์šฉ ์ด์œ : ์ฝ”๋“œ ํ‘ธ์‹œ์— ๋”ฐ๋ฅธ ์ž๋™ํ™”๋œ ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฒ€์‚ฌ์™€ ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ ๊ณผ์ •์„ ํ†ตํ•ด ๊ฐœ๋ฐœ ์†๋„์™€ ํ’ˆ์งˆ์„ ๋™์‹œ์— ์œ ์ง€.
  4. ELKB

    • ์ ์šฉ ์œ„์น˜: ํ†ตํ•ฉ ๊ฒ€์ƒ‰, AWS EC2์— ๋ชจ๋‹ˆํ„ฐ๋ง ํ™˜๊ฒฝ ๊ตฌ์ถ•
    • ์‚ฌ์šฉ ์ด์œ : ํ†ตํ•ฉ ๋กœ๊น…๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•œ ํ”Œ๋žซํผ์œผ๋กœ ์‹œ์Šคํ…œ ๋กœ๊ทธ ์ˆ˜์ง‘ ๋ฐ ๋ถ„์„์„ ํ†ตํ•ด ๋น ๋ฅธ ๋ฌธ์ œ ํƒ์ง€ ๋ฐ ๋Œ€์‘. Elasticsearch๋ฅผ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ์ธ๋ฑ์‹ฑ ๋ฐ ๊ฒ€์ƒ‰, Logstash๋กœ ๋‹ค์–‘ํ•œ ๋กœ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ ๋ฐ ๋ณ€ํ™˜, Kibana ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ†ตํ•œ ์‹œ๊ฐํ™”, Beats๋กœ ์„œ๋ฒ„์—์„œ์˜ ๋กœ๊ทธ์™€ ๋ฉ”ํŠธ๋ฆญ ๊ฒฝ๋Ÿ‰ ์ˆ˜์ง‘์„ ํ†ตํ•ด ์‹œ์Šคํ…œ์˜ ์‹ค์‹œ๊ฐ„ ์ƒํƒœ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํŒŒ์•….

์ฃผ์š” ๊ธฐ๋Šฅ

๊ฒฐ์ œ API ์—ฐ๋™
  • ์™ธ๋ถ€ PG์‚ฌ์™€ ๊ฒฐ์ œ API๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ๊ฒฐ์ œ ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ DB์— ์ €์žฅํ•จ์œผ๋กœ์จ ๊ฒฐ์ œ ์ •๋ณด๋ฅผ ์ถ”์ 

    ํ”„๋กœ์„ธ์Šค ํ๋ฆ„
  • Spring์˜ REST API์™€ ํŠธ๋žœ์žญ์…˜ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฒฐ์ œ API์™€์˜ ์—ฐ๋™์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ

์ •์‚ฐ Spring Batch
  • ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ ๋Œ€์‹ , ์‹œ์Šคํ…œ ๋ถ€ํ•˜๊ฐ€ ์ ์€ ์‹œ๊ฐ„๋Œ€์— ๋ฐฐ์น˜ ๋ฐฉ์‹์œผ๋กœ ์ •์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ๋ณ„๋„์˜ ์„œ๋ฒ„ ํ™˜๊ฒฝ์„ ํ™œ์šฉํ•˜์—ฌ ๋ถ€ํ•˜๋ฅผ ์ตœ์†Œํ™”.

    • ํ”„๋กœ์„ธ์Šค ํ๋ฆ„: ๊ฒฐ์ œ ์™„๋ฃŒ ๋ฐ์ดํ„ฐ ์กฐํšŒ โ†’ ์ˆ˜์ˆ˜๋ฃŒ ๊ณ„์‚ฐ โ†’ ์ •์‚ฐ ๊ฒฐ๊ณผ ์ €์žฅ.
  • ์Šคํ”„๋ง ๋ฐฐ์น˜์™€ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ •์‚ฐ ์ž‘์—…์„ ์ž๋™ํ™”ํ•˜๊ณ , ๋ฐฐ์น˜๊ฐ€ ์‹œ์Šคํ…œ ๋ถ€ํ•˜๊ฐ€ ์ ์€ ์‹œ๊ฐ„์— ์‹คํ–‰๋˜๋„๋ก ์„ค์ •

  • ๊ด€๋ จ ๋งํฌ : https://github.com/final17/batch

ํ†ตํ•ฉ ๊ฒ€์ƒ‰
  • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฉ”๋‰ด, ์ฃผ์†Œ, ๊ฐ€๊ฒŒ๋ช…์„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ํ†ตํ•ฉ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์ œ๊ณต

  • ์ฃผ์†Œ์™€ ์ง€์—ญ๋ณ„ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•ด ์›ํ•˜๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋” ์„ธ๋ถ€์ ์œผ๋กœ ํƒ์ƒ‰ ๊ฐ€๋Šฅ

  • ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•˜๊ณ  ๋†’์€ ์ •ํ™•๋„๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด Elasticsearch๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ตœ์ ํ™”๋œ ๊ฒ€์ƒ‰ ํ™˜๊ฒฝ ์ œ๊ณต

์›จ์ดํŒ… ๋Œ€๊ธฐ์—ด
  • ํด๋ฆญ ํ•œ ๋ฒˆ์œผ๋กœ ์›จ์ดํŒ… ๋Œ€๊ธฐ์—ด์— ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋Š” ์ง๊ด€์ ์ธ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์ œ๊ณต

  • ์‚ฌ์šฉ์ž์—๊ฒŒ ํ˜„์žฌ ๋Œ€๊ธฐ ์ˆœ๋ฒˆ๊ณผ ์˜ˆ์ƒ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์•Œ๋ฆผ ์ œ๊ณต, ๋Œ€๊ธฐ ์ค‘์ธ ๊ณ ๊ฐ์˜ ํŽธ์˜์„ฑ ๊ทน๋Œ€ํ™”

  • ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•œ ๋Œ€๊ธฐ์—ด ๊ด€๋ฆฌ ๋ฐ ์ˆœ๋ฒˆ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด Redis๋ฅผ ํ™œ์šฉํ•œ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋กœ ์•ˆ์ •์„ฑ๊ณผ ํšจ์œจ์„ฑ ํ™•๋ณด


๊ธฐ์ˆ ์  ๊ณ ๋„ํ™”

๐Ÿ“์˜ˆ์•ฝ๋ถ€ํ„ฐ ๊ฒฐ์ œ, ๊ทธ๋ฆฌ๊ณ  ์ •์‚ฐ๊นŒ์ง€: ํšจ์œจ์ ์ธ ํ”„๋กœ์„ธ์Šค ๊ตฌ์ถ• ์—ฌ์ •
๐Ÿ’ณ ๊ฒฐ์ œ API ์—ฐ๋™
ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

[๋ฌธ์ œ ์ธ์‹]

์˜ˆ์•ฝ CRUD ์ž‘์—… ์ง„ํ–‰ ํ›„ ๊ฒฐ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ† ์ŠคํŽ˜์ด๋จผํŠธ API๋ฅผ ์—ฐ๋™ํ•˜๋ฉด์„œ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜์˜€๊ณ  ๊ฒฐ์ œ ์‹œ์Šคํ…œ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ณผ์ •์—์„œ ํ† ์ŠคํŽ˜์ด๋ฅผ ํ†ตํ•œ ๊ฒฐ์ œ API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ค‘์— ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. API๋กœ ์‘๋‹ต๋ฐ›์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž‘์„ฑํ•œ ํ˜•์‹๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋ฐ˜ํ™˜๋˜์—ˆ๊ณ  ์ด๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ฒฐ์ œ ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์ง€ ์•Š์€ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

[ํ•ด๊ฒฐ ๋ฐฉ์•ˆ]

API์˜ ์‘๋‹ต ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋‹ค์‹œ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด API ๋ฌธ์„œ๋ฅผ ๋ฉด๋ฐ€ํžˆ ์‚ดํŽด๋ณด๊ณ  ๋ฌธ์„œ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฐ์ดํ„ฐ ํ˜•์‹์— ๋งž์ถฐ์„œ ํ•„์š”ํ•œ ํ•„๋“œ๋“ค์„ ์ถ”์ถœํ•˜์—ฌ ๊ฒ€์ฆํ•˜๊ณ  API ์‘๋‹ต์„ ์ •ํ™•ํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

[ํ•ด๊ฒฐ ์™„๋ฃŒ]

ํ…Œ์ด๋ธ” ์—”ํ‹ฐํ‹ฐ์˜ ๊ตฌ์กฐ๋ฅผ ์žฌ๊ฒ€ํ† ํ•˜์—ฌ ๊ฐ ํ•„๋“œ๊ฐ€ ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹ค์ œ ๊ฒฐ์ œ์™€ ๊ฒฐ์ œ ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ํ๋ฆ„์„ ์ ๊ฒ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ œ์ด๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ์ตœ๋Œ€ํ•œ ๋งŽ์ด API๋ฅผ ํ˜ธ์ถœํ•ด๋ณด๋ฉฐ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ณผ์ •์„ ํ†ตํ•ด ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ์ œ ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ์ œ ํ…Œ์ŠคํŠธ

๊ฒฐ์ œ ํ๋ฆ„


Jmeter ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

ํ…Œ์ŠคํŠธ ํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์€ ๊ฒฐ์ œ ์š”์ฒญ ์ „ ๊ฒ€์ฆ๋ถ€๋ถ„์œผ๋กœ ํŒ๋‹จํ–ˆ๊ณ  ํ•ด๋‹น ๋ถ€๋ถ„์— Jmeter๋ฅผ ๊ฑธ์–ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋‚ด์šฉ ์ƒ˜ํ”Œ ์ˆ˜ ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„ (ms) ์ตœ์†Œ ์‘๋‹ต ์‹œ๊ฐ„ (ms) ์ตœ๋Œ€ ์‘๋‹ต ์‹œ๊ฐ„ (ms) ์˜ค๋ฅ˜์œจ (%) ์ฒ˜๋ฆฌ๋Ÿ‰ (req/sec)
๊ธฐ๋ณธ 2140 502 17 1689 4.67 189.9
RedissonLock 1844 1831 18 2318 5.42 53.8
Async 1968 518 8 1046 5.08 183.6
RedissonLock + Async 1852 1669 16 3743 5.40 58.9

์—ฌ๋Ÿฌ ํ…Œ์ŠคํŠธ๋กœ ํ™•์ธํ•ด๋ณธ ๊ฒฐ๊ณผ ๊ธฐ๋ณธ ๋ฐฉ์‹์ด ๋” ๋น ๋ฅด๊ณ  ๋ฐ์ดํ„ฐ๋„ ์•ˆ์ •์ ์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š”๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
โš™๏ธ ์ •์‚ฐ ์ฒ˜๋ฆฌ ์ž๋™ํ™”

๊ด€๋ จ ๋งํฌ : https://github.com/final17/batch


๐Ÿ” ์Œ์‹์  ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์†๋„ ํ–ฅ์ƒ

๋ฐฐ๊ฒฝ

  • 100๋งŒ๊ฑด ์ •๋„์˜ ํฐ ๋ฐ์ดํ„ฐ๋ฅผ LIKE๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ ๋ฌธ์ œ

  • ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ 1์ดˆ ์ •๋„๋กœ ๋А๋ ค ๊ฒ€์ƒ‰ ์†๋„ ํ–ฅ์ƒ์ด ํ•„์š”ํ•จ

    ๐Ÿงพ ์˜์‚ฌ ๊ฒฐ์ •
    ๊ฒ€์ƒ‰์„ ๊ณ ๋„ํ™” ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•
    1. ํŽ˜์ด์ง€๋„ค์ด์…˜: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ ํ•œ ๋ฒˆ์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์•Š๊ณ , ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ์ ์šฉํ•˜์—ฌ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์กฐํšŒํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 2. JPA ์ฟผ๋ฆฌ ์ตœ์ ํ™” ๋ฐ Indexing: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์— ์ธ๋ฑ์Šค๋ฅผ ์„ค์ •ํ•˜์—ฌ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 3. Redis ์บ์‹ฑ ์ ์šฉ: ์ž์ฃผ ์กฐํšŒํ•˜๋Š” ์Œ์‹์  ๋ฐ์ดํ„ฐ๋ฅผ Redis์— ์บ์‹ฑํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ ๋นˆ๋„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ด์ค‘์—์„œ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์ ์šฉ์„ ์™„๋ฃŒํ•˜์˜€๊ณ , Indexing์„ ํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐ์„ ํ•˜์—ฌ Indexing์„ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„์— Redis ์บ์‹ฑ์„ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

    ์ธ๋ฑ์Šค ์ข…๋ฅ˜
    1. ๋‹จ์ผ ์ธ๋ฑ์Šค(Single Index): ํ•˜๋‚˜์˜ ์ปฌ๋Ÿผ์— ์ธ๋ฑ์Šค๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ•ด๋‹น ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰์„ ์ตœ์ ํ™” ํ•ฉ๋‹ˆ๋‹ค. 2. ๋ณตํ•ฉ ์ธ๋ฑ์Šค(Composite Index): ์—ฌ๋Ÿฌ ์ปฌ๋Ÿผ์„ ์กฐํ•ฉํ•˜์—ฌ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์„์œผ๋กœ, ํŠน์ • ์กฐํ•ฉ์— ๋Œ€ํ•œ ์ตœ์ ์˜ ์„ฑ๋Šฅ์„ ์ œ๊ณต 3. ์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค(Unique Index): ์ค‘๋ณต์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ์ธ๋ฑ์Šค 4. ์ „๋ฌธ๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค(Full-Text Index): ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ๊ฒ€์ƒ‰์„ ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•œ ์ธ๋ฑ์Šค

    ์ด์ค‘์—์„œ Full-Text Inex๊ฐ€ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์˜ ๊ฒ€์ƒ‰์œผ๋กœ ์ ํ•ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

    ํ•ด๊ฒฐ ์ˆœ์„œ
    1. Full-Text Index ์ ์šฉ
      • Full-Text Index๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.("๊ฒ€์ƒ‰์–ด"๋งŒ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๊ณ  "%๊ฒ€์ƒ‰์–ด", "๊ฒ€์ƒ‰์–ด%", "%๊ฒ€์ƒ‰์–ด%")
      1. Full-Text Index์—์„œ N-Gram์„ ์‚ฌ์šฉํ•˜๊ธฐ
      • Full-Text๋Š” ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ N-Gram์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. N-Gram์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ„์—์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
      • image
      • ํ•˜์ง€๋งŒ Like๋งŒ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ์™€ Full-Text Index N-Gram์„ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด "์†Œ๋ผ", "๋„๊นจ๋น„"๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ๋น ๋ฅด๊ณ , "์‹๋‹น"์€ ๋‘˜์ด ์†๋„๊ฐ€ ๋น„์Šทํ•˜๊ณ , "์ฐŒ๊ฐœ", "๊ตญ๋ฐฅ"์€ N-Gram๋ฐฉ์‹์ด ๋А๋ฆฐ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
      • N-Gram์ด ๋А๋ฆฐ ์ด์œ ๋Š” N-Gram์€ ํŠน์ • ๊ฒ€์ƒ‰ ์‹œ ์„ธ๋ฐ€ํ•œ ์ผ์น˜ ๊ฒ€์ƒ‰์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์ง€๋งŒ ๋” ๋А๋ ค์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค.
      • ์ •ํ™”๋„๋Š” ํ–ฅ์ƒ๋˜์—ˆ์ง€๋งŒ ์†๋„๊ฐ€ ๋งŽ์ด ๋А๋ ค์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
      1. Single Index ๊ฑธ์–ด๋ณด๊ธฐ
      • ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ index์ธ Single Index๋ฅผ ๊ฑธ์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค
      • ์ธ๋ฑ์‹ฑ ์ ์šฉ ๋ฒ”์œ„
        • EXPLAIN SELECT * FROM store WHERE business_name LIKE '%๋„๊นจ๋น„%';
        • image
        • EXPLAIN SELECT * FROM store WHERE business_name LIKE '๋„๊นจ๋น„%';
        • image
        • EXPLAIN SELECT * FROM store WHERE business_name LIKE '%๋„๊นจ๋น„';
        • image
      • ์ธ๋ฑ์‹ฑ ์—†์ด LIKE๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ํ–ˆ์„ ๋•Œ
      • image
      • ์ธ๋ฑ์‹ฑ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ
      • image
      1. Redis ์บ์‹ฑ ์‚ฌ์šฉํ•˜๊ธฐ
      • ์Œ์‹์  ๋ฐ์ดํ„ฐ๋Š” ์ž์ฃผ ์กฐํšŒ๋˜๊ณ , ๋ณ€๊ฒฝ์ด ์ ๊ณ  ์ฝ๊ธฐ ๋น„์œจ์ด ๋†’์€ ๋ฐ์ดํ„ฐ๋ผ๊ณ  ์ƒ๊ฐํ•˜์—ฌ Redis ์บ์‹ฑ ๋Œ€์ƒ์— ์ ํ•ฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
      • ์ฒ˜์Œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ redis์— ๋„ฃ์œผ๋ ค๊ณ  ํ•˜์ž ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜ค๋ฉด์„œ ๋„ฃ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
      • image
      • ๊ทธ๋ž˜์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ dto๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
      • Redis ๊ฒฐ๊ณผ
        • ์บ์‹ฑ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์ „
        • image
        • ์บ์‹ฑ ์ฒ˜๋ฆฌ ํ›„
        • image
      • ์†๋„๊ฐ€ 1048.90ms โ†’ 4.32ms๋กœ ๋นจ๋ผ์ง„ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โš™๏ธ ์กฐํšŒ์ˆ˜, ์ข‹์•„์š” ๋ถ„์‚ฐ๋ฝ ์ ์šฉ

์™œ ๋™์‹œ์„ฑ ์ œ์–ด ์‹œ ์—ฌ๋Ÿฌ ์„ ํƒ์ง€๊ฐ€ ์žˆ๋Š”๋ฐ, ๋ถ„์‚ฐ๋ฝ์„ ์‚ฌ์šฉํ–ˆ์„๊นŒ?

  • ๋ถ„์‚ฐ ์‹œ์Šคํ…œ ํ™˜๊ฒฝ์—์„œ์˜ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ, ์„ฑ๋Šฅ, ๊ทธ๋ฆฌ๊ณ  ํ™•์žฅ์„ฑ ์ธก๋ฉด์—์„œ ๊ฐ€์žฅ ์ ํ•ฉํ•œ ์†”๋ฃจ์…˜์ด๊ธฐ ๋•Œ๋ฌธ

๋‚™๊ด€์  ๋ฝ๊ณผ ๋น„๊ด€์  ๋ฝ์˜ ์„ ํƒ์ง€

  • ๋น„๊ด€์  ๋ฝ
    ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ํ–‰ ๋‹จ์œ„๋กœ ๋ฝ์„ ๊ฑธ์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณดํ˜ธ. ์žฅ์ : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ ˆ๋ฒจ์—์„œ ๊ฐ•๋ ฅํ•œ ๋™์‹œ์„ฑ ์ œ์–ด ๊ฐ€๋Šฅ. ์ถ”๊ฐ€ ๋„๊ตฌ ์—†์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ธฐ๋Šฅ๋งŒ์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ. ๋‹จ์ : ๋ฝ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ง์ ‘ ๊ฑธ๋ฆฌ๋ฏ€๋กœ, ํŠธ๋žœ์žญ์…˜์ด ์˜ค๋ž˜ ์ง€์†๋˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋จ. ๋ถ„์‚ฐ ํ™˜๊ฒฝ(๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค)์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ. ๋ฝ ๊ฒฝํ•ฉ์ด ์‹ฌํ•˜๋ฉด ๋ฐ๋“œ๋ฝ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

  • ๋‚™๊ด€์  ๋ฝ
    ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์€ ํ›„ ์—…๋ฐ์ดํŠธ ์‹œ์ ์— ๋ฐ์ดํ„ฐ์˜ ๋ฒ„์ „์„ ํ™•์ธํ•˜์—ฌ ๋™์‹œ์„ฑ ์ถฉ๋Œ์„ ๊ฐ์ง€.

  • ์žฅ์ : ๋ฝ์„ ๊ฑธ์ง€ ์•Š์œผ๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ๋›ฐ์–ด๋‚จ. ์ถฉ๋Œ ๋ฐœ์ƒ์ด ์ ์€ ํ™˜๊ฒฝ์—์„œ ์ ํ•ฉ.

  • ๋‹จ์ : ์ถฉ๋Œ์ด ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋จ(์—ฌ๋Ÿฌ ๋ฒˆ ์žฌ์‹œ๋„ ํ•„์š”). ์ถฉ๋Œ ๊ฐ์ง€ ํ›„ ๋กค๋ฐฑ ๋ฐ ์žฌ์‹œ๋„ ๋กœ์ง์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Œ. ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ถ”๊ฐ€์ ์ธ ๊ตฌํ˜„ ํ•„์š”.


Redis๋กœ ๋ถ„์‚ฐ๋ฝ์„ ์ฑ„ํƒํ•œ ์ด์œ 

  • ๋ถ„์‚ฐ ํ™˜๊ฒฝ ์ง€์›: ๋ฉ€ํ‹ฐ ๋…ธ๋“œ/๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค์—์„œ๋„ ๋™์ž‘.
  • ์„ฑ๋Šฅ: ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋น ๋ฆ„.
  • ๋ฐ๋“œ๋ฝ ๋ฐฉ์ง€: ์ž๋™ TTL๋กœ ๋ฐ๋“œ๋ฝ ๊ฐ€๋Šฅ์„ฑ์„ ์ œ๊ฑฐ.
  • ํ™•์žฅ์„ฑ: ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์„ฑ์„ ํ†ตํ•ด ๋†’์€ ํ™•์žฅ์„ฑ๊ณผ ๊ฐ€์šฉ์„ฑ ์ œ๊ณต.
  • ์œ ์—ฐ์„ฑ: ๋‹จ์ผ ๋ฆฌ์†Œ์Šค๋‚˜ ํŠน์ • ์ž‘์—… ๋‹จ์œ„๋กœ ๋ฝ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ.

๐Ÿ” Elastic search ํ†ตํ•ฉ ๊ฒ€์ƒ‰

ํ†ตํ•ฉ ๊ฒ€์ƒ‰ ๊ตฌํ˜„

DB LIKE ๊ฒ€์ƒ‰

๊ตฌํ˜„ ์•„์ด๋””์–ด

DB์—์„œ LIKE ์—ฐ์‚ฐ์„ ํ†ตํ•ด ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์กฐ๊ฑด ๋ฐ ๊ฒฐ๊ณผ

  • ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: 100๋งŒ ๊ฑด
  • ๊ฒ€์ƒ‰ ์ปฌ๋Ÿผ: ์‚ฌ์—…๋ช…, ์‚ฌ์—…ํ˜•ํƒœ, ์ฃผ์†Œ, ๋„๋กœ๋ช… ์ฃผ์†Œ, ๋ฉ”๋‰ด
  • ๊ฒฐ๊ณผ: ์•ฝ 5์ดˆ ์†Œ์š” image

์ธ๋ฑ์Šค ์ ์šฉ

๊ฐœ์„  ์•„์ด๋””์–ด

DB ์ปฌ๋Ÿผ์— ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•ด๋ณด๋ ค ํ–ˆ์œผ๋‚˜, LIKE ์—ฐ์‚ฐ์—์„œ %ํ‚ค์›Œ๋“œ%์™€ ๊ฐ™์ด ์‹œ์ž‘๊ณผ ๋์„ ์™€์ผ๋“œ์นด๋“œ๋กœ ๋‘˜๋Ÿฌ์‹ธ๋ฉด ์ธ๋ฑ์Šค๊ฐ€ ๋ฌด์šฉ์ง€๋ฌผ์ด ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ

  • %ํ‚ค์›Œ๋“œ%๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ ์„ฑ๋Šฅ ๊ฐœ์„  ํšจ๊ณผ๊ฐ€ ์—†์—ˆ์œผ๋ฉฐ, ํ‚ค์›Œ๋“œ%๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. image image

  • %ํ‚ค์›Œ๋“œ% EXPLAIN image

  • ํ‚ค์›Œ๋“œ% EXPLAIN image

MySQL Full-Text Search

MySQL์˜ Full-Text Search๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒ€์ƒ‰์„ ๊ตฌํ˜„ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

    @Query(value = "SELECT * FROM store WHERE MATCH(business_name, full_location_address, full_road_name_address, business_type) AGAINST(:keyword IN NATURAL LANGUAGE MODE)", nativeQuery = true)
    List<Store> searchByKeyword(@Param("keyword") String keyword, Pageable pageable);

๊ฒฐ๊ณผ

๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋˜์—ˆ์œผ๋‚˜, ์›ํ•˜๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋‚˜์˜ค์ง€ ์•Š์•„ ํ†ตํ•ฉ ๊ฒ€์ƒ‰์œผ๋กœ๋Š” ๋ถ€์ ํ•ฉํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. image image

Elasticsearch ๋„์ž…

DB์—์„œ์˜ ๊ฒ€์ƒ‰ ๋Œ€์‹  Elasticsearch๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. Elasticsearch๋ฅผ ๋„์ž…ํ•œ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ๊ธฐ์กด DB ๊ฒ€์ƒ‰์˜ ํ•œ๊ณ„
    • ์„ฑ๋Šฅ: SQL์˜ LIKE ๊ฒ€์ƒ‰์€ %ํ‚ค์›Œ๋“œ% ๊ตฌ์กฐ์ธ ๊ฒฝ์šฐ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์—†์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์„์ˆ˜๋ก ์†๋„๊ฐ€ ๋А๋ ค์ง‘๋‹ˆ๋‹ค.
    • ์ œํ•œ๋œ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ: Full-Text Search๋Š” ์‚ฌ์šฉ์ž ์˜๋„๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ๋ฐ˜์˜ํ•˜๊ธฐ ์–ด๋ ค์›Œ ๋ณตํ•ฉ ์กฐ๊ฑด ์ฒ˜๋ฆฌ์™€ ๊ฒ€์ƒ‰ ์ •ํ™•๋„์— ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Elasticsearch์˜ ์žฅ์ 
  • ์„ฑ๋Šฅ: ์—ญ์ƒ‰์ธ ๊ตฌ์กฐ๋กœ ๊ฒ€์ƒ‰ ์†๋„๊ฐ€ ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค.
  • ์ •๊ตํ•œ ๊ฒ€์ƒ‰: ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ(Nori)๋ฅผ ํ†ตํ•ด ํ•œ๊ตญ์–ด ๊ฒ€์ƒ‰ ์ตœ์ ํ™” ๋ฐ ํ•„๋“œ๋ณ„ ๊ฐ€์ค‘์น˜ ์„ค์ •์œผ๋กœ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ ํ’ˆ์งˆ ๋†’์Šต๋‹ˆ๋‹ค.
  • ์œ ์—ฐํ•œ ๊ฒ€์ƒ‰: Fuzzy ๊ฒ€์ƒ‰, ๋ถ€๋ถ„ ๋งค์นญ, ๋ณตํ•ฉ ์ฟผ๋ฆฌ ๋“ฑ์„ ์ง€์›ํ•ด ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ์ž ์š”๊ตฌ๋ฅผ ์ถฉ์กฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ™•์žฅ์„ฑ๊ณผ ์‹ค์‹œ๊ฐ„์„ฑ: ์‹ค์‹œ๊ฐ„ ์ƒ‰์ธ๊ณผ ์ˆ˜ํ‰ ํ™•์žฅ์œผ๋กœ ๋ฐ์ดํ„ฐ ์ฆ๊ฐ€์—๋„ ์•ˆ์ •์ ์ธ ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ

  • ๊ฐ„๋‹จํžˆ multi_match ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ํ•„๋“œ๋ณ„ ๊ฐ€์ค‘์น˜๋ฅผ ์ฃผ์–ด ๊ฒ€์ƒ‰ํ–ˆ์„ ๋•Œ, 100๋งŒ๊ฑด์˜ ๋ฐ์ดํ„ฐ์—์„œ 30ms ๋‚ด์— ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, ์„œ์šธ ์ดˆ๋ฐฅ ๊ฒ€์ƒ‰ ์‹œ ๊ด€๋ จ์ด ์—†์–ด๋ณด์ด๋Š” ๊ฐ€๊ฒŒ๊ฐ€ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ƒ์œ„์— ๋‚˜์˜ค๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. image

๊ฒ€์ƒ‰ ์ •ํ™•๋„ ๊ฐœ์„ 

๋ฌธ์ œ

์‚ฌ์šฉ์ž๊ฐ€ ์„œ์šธ์‹œ ์€ํ‰๊ตฌ ์ดˆ๋ฐฅ์ง‘์„ ๊ฒ€์ƒ‰ํ•˜๋ฉด, ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๋Š” ์„œ์šธ ์€ํ‰๊ตฌ์— ์œ„์น˜ํ•œ ์ดˆ๋ฐฅ์ง‘์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ์กด multi_match ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ํ‚ค์›Œ๋“œ๋ฅผ ํ† ํฐํ™”ํ•˜์—ฌ ๊ฐ€๊ฒŒ๋ช…, ์ฃผ์†Œ, ๋ฉ”๋‰ด ๋“ฑ์˜ ํ•„๋“œ์—์„œ ์ผ๋ถ€๋ผ๋„ ๋งค์นญ๋˜๋Š” ๊ฒฝ์šฐ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
  2. ์ด๋กœ ์ธํ•ด ์„œ์šธ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ง€์—ญ์˜ ์ดˆ๋ฐฅ์ง‘์ด ๋†’์€ ์ ์ˆ˜๋ฅผ ๋ฐ›์•„ ์ƒ์œ„์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

  • ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ: ์„œ์šธ ์€ํ‰๊ตฌ ์ดˆ๋ฐฅ์ง‘
  • ์‹ค์ œ ๊ฒฐ๊ณผ: ์„œ์šธ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ง€์—ญ ์ดˆ๋ฐฅ์ง‘์ด ์ƒ์œ„์— ๋‚˜์˜ค๋Š” ๋ฌธ์ œ

ํ•ด๊ฒฐ ๋ฐฉํ–ฅ

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด bool ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์„ ํƒ์ง€

  1. ํ‚ค์›Œ๋“œ ๋ถ„์„ ํ›„ ํ•„๋“œ๋ณ„๋กœ ๊ฐ€์ค‘์น˜๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •

    • ๊ฐ€์ค‘์น˜๋ฅผ ์กฐ์ •ํ•ด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋„์ถœํ•˜๋ ค ํ–ˆ์œผ๋‚˜, ์ž…๋ ฅ๋œ ๋„์‹œ์™€ ๊ตฌ๊ฐ€ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋œ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†์Šต๋‹ˆ๋‹ค.
  2. bool ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ํ•„์ˆ˜ ์กฐ๊ฑด ์ ์šฉ

    • ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ๋„์‹œ์™€ ๊ตฌ, ๋ฉ”๋‰ด๋ฅผ ํ•„ํ„ฐ๋งํ•œ ํ›„, ํ•ด๋‹น ์กฐ๊ฑด์„ must๋กœ ์„ค์ •ํ•ด ํ•„์ˆ˜์ ์œผ๋กœ ํฌํ•จ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์‚ฌ์šฉ์ž ๊ธฐ๋Œ€์— ๋ถ€ํ•ฉํ•˜๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด bool ์ฟผ๋ฆฌ๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ๋ฒ•์€ ๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด์™€ ๊ฐ™์€ ์ž…๋ ฅ ์กฐ๊ฑด์„ ๋ฐ˜๋“œ์‹œ ์ถฉ์กฑ์‹œํ‚ค๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1์ฐจ ๊ฐœ์„ 

ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ•„ํ„ฐ๋งํ•œ ๋’ค, ๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด ์ด๋ฆ„์„ ์ถ”์ถœํ•˜๊ณ  ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๋ฐฉ์‹

  1. ๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด ํ•„ํ„ฐ๋ง

    • ํ‚ค์›Œ๋“œ์—์„œ ๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด ์ •๋ณด๋ฅผ ์ถ”์ถœ.
    • ์ถ”์ถœ๋œ ์ •๋ณด๋ฅผ Elasticsearch์˜ bool ์ฟผ๋ฆฌ์—์„œ must ์กฐ๊ฑด์œผ๋กœ ์ ์šฉํ•˜์—ฌ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜๋„๋ก ์„ค์ •.
  2. ๊ฒ€์ƒ‰ ํ”„๋กœ์„ธ์Šค

    • ์ถ”์ถœ๋œ ์กฐ๊ฑด(๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด)์„ ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์„œ๋ฅผ ํ•„ํ„ฐ๋ง.
      • ์ด ๋‹จ๊ณ„์—์„œ ์ž…๋ ฅ๋œ ์œ„์น˜์™€ ๋ฉ”๋‰ด๋ฅผ ๋งŒ์กฑํ•˜๋Š” ๋ฌธ์„œ๋งŒ ๋‚จ๊น€.
    • ํ•„ํ„ฐ๋ง๋œ ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ๊ฐ€๊ฒŒ๋ช…๊ณผ ๋ฉ”๋‰ด ํ•„๋“œ๋ฅผ match๋กœ ๊ฒ€์ƒ‰.
  3. ์กฐ๊ฑด์ด ์—†์„ ๊ฒฝ์šฐ

    • ๋งŒ์•ฝ ์ž…๋ ฅ๋œ ํ‚ค์›Œ๋“œ์—์„œ ๋„์‹œ, ๊ตฌ, ๋ฉ”๋‰ด ์ •๋ณด๊ฐ€ ์ถ”์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๊ฐ€๊ฒŒ๋ช…๊ณผ ๋ฉ”๋‰ด ํ•„๋“œ๋งŒ์œผ๋กœ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰.
  4. ๊ฐ€๊ฒŒ๋ช…์— ์šฐ์„ ์ˆœ์œ„ ๋ถ€์—ฌ

    • ๊ฐ€๊ฒŒ๋ช… ํ•„๋“œ์—์„œ ํ† ํฐํ™”๋˜์ง€ ์•Š์€ keyword ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒ€์ƒ‰.
    • boost ๊ฐ’์„ ๋ถ€์—ฌํ•˜์—ฌ ๋ฉ”๋‰ด๋ณด๋‹ค ๊ฐ€๊ฒŒ๋ช…์ด ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๋„๋ก ์„ค์ •.

2์ฐจ ๊ฐœ์„ 

1์ฐจ ๊ฐœ์„ ์—์„œ๋Š” ์—ฌ๋Ÿฌ ํ•„๋“œ์— ๋Œ€ํ•ด ์ฟผ๋ฆฌ๋ฅผ ์š”์ฒญํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ์‹์€ ๊ฒ€์ƒ‰ ํ•„๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์„ฑ๋Šฅ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด Elasticsearch์˜ copy_to ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„  ๋ฐฉ์•ˆ

  1. ๊ฒ€์ƒ‰ ํ…์ŠคํŠธ ํ†ตํ•ฉ
    • ๊ฒ€์ƒ‰์— ํ•„์š”ํ•œ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์—˜๋ผ์Šคํ‹ฑ ์„œ์น˜์˜ copy_to๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•˜๋‚˜์˜ ํ•„๋“œ์— ํ†ตํ•ฉํ•˜์—ฌ ์ €์žฅ
  • ์˜ˆ๋ฅผ ๋“ค์–ด:
    • ์ฃผ์†Œ: ์„œ์šธ์‹œ ์€ํ‰๊ตฌ
    • ๊ฐ€๊ฒŒ๋ช…: ๋ง›์ง‘
    • ๋ฉ”๋‰ด: ํ–„๋ฒ„๊ฑฐ, ํ”ผ์ž
    • ํ†ตํ•ฉ๋œ ํ•„๋“œ: ์„œ์šธ์‹œ ์€ํ‰๊ตฌ ๋ง›์ง‘ ํ–„๋ฒ„๊ฑฐ, ํ”ผ์ž

๋” ๋‚˜์€ ๊ฒ€์ƒ‰ ๊ฒฝํ—˜์„ ์œ„ํ•ด

์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ์ฐจ๋ก€ ์ˆ˜์ •ํ•˜๋ฉด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒ€์ƒ‰์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์ด ์—†์–ด ์ ์ ˆํ•œ ๋ฐฉํ–ฅ์„ ์žก๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค. ์ด์— ์บ์น˜ํ…Œ์ด๋ธ”๊ณผ ๊ฐ™์€ ์„œ๋น„์Šค์˜ ๊ฒ€์ƒ‰ ๋ฐฉ์‹์„ ๋ถ„์„ํ•˜์—ฌ ๊ฐœ์„  ์•„์ด๋””์–ด๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

๋ถ„์„ ๋‚ด์šฉ

  • ์†Œ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์ด๋ฆ„์— ์†Œ์Šค๊ฐ€ ํฌํ•จ๋œ ๊ฐ€๊ฒŒ๋“ค์ด ๊ฒ€์ƒ‰๋จ.

    image

  • ์„œ์šธ ์†Œ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์„œ์šธ ์ง€์—ญ ํ•„ํ„ฐ๊ฐ€ ์ ์šฉ๋˜์ง€๋งŒ, ๊ฒฐ๊ณผ๋Š” ์„œ์šธ ์†Œ์Šค์™€ ๊ด€๋ จ ์—†๋Š” ๊ฐ€๊ฒŒ๋„ ํฌํ•จ๋จ.

    image

  • ์„œ์šธ ์—์น˜์„ธ๋Š” ๊ฒ€์ƒ‰๋˜์ง€ ์•Š์ง€๋งŒ, ์„œ์šธ ์—์น˜์„ธ๋กœ์†Œ์Šค์™€ ๊ฐ™์ด ๋” ๊ตฌ์ฒด์ ์ธ ์ž…๋ ฅ์—๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚จ.

    image

  • ์—์น˜์„ธ๋กœ์†Œ์Šค์Šค์Šค๋Š” ๊ฒ€์ƒ‰๋˜์ง€๋งŒ, ์„œ์šธ์—†์ด ์—์น˜์„ธ๋กœ์†Œ์Šค์Šค์Šค๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์Œ.

    image

    image

  • ์—์น˜์„ธ๋ฅด์†Œ ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์•ˆ๋‚˜์˜จ๋‹ค.

    image

  • ์„œ์šธ ๋‚™์‹œ๋Š” ํ•„ํ„ฐ์— ์„œ์šธ์ด ์ฒดํฌ๊ฐ€ ๋œ๋‹ค.

    image

  • ์‹ค์ œ๋กœ ์žˆ๋Š” ์„œ์šธ ๋‚™์—…์„ ๊ฒ€์ƒ‰ ํ•ด๋ณด๋ฉด ์„œ์šธ์— ํ•„ํ„ฐ ์ฒดํฌ๊ฐ€ ์•ˆ๋œ๋‹ค.

    image

์ด๋Ÿฌํ•œ ๋ถ„์„์„ ํ†ตํ•ด ์ƒ๊ฐํ•œ ๊ฒ€์ƒ‰ ๊ตฌํ˜„ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์ •ํ™•ํ•œ ๋งค์นญ ์šฐ์„ 

    • ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ term ๋˜๋Š” prefix ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฐ€๊ฒŒ๋ช…์„ ๋จผ์ € ๊ฒ€์ƒ‰.
  2. ํ†ตํ•ฉ ๊ฒ€์ƒ‰ ์กฐ๊ฑด

    • ๋งŒ์•ฝ ์ •ํ™•ํ•œ ๋งค์นญ ๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ, ํ†ตํ•ฉ ๊ฒ€์ƒ‰์œผ๋กœ ์ง„ํ–‰.
    • ํ†ตํ•ฉ ๊ฒ€์ƒ‰์—์„œ๋Š” copy_to๋กœ ์ƒ์„ฑํ•œ full_text ํ•„๋“œ์— ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ํ•„๋“œ์—์„œ ํ‚ค์›Œ๋“œ๋ฅผ ์ฐพ์Œ.
  3. ์นดํ…Œ๊ณ ๋ฆฌ ์ฒดํฌ์™€ ํ•„ํ„ฐ๋ง

    • ๊ฒ€์ƒ‰๋œ ํ‚ค์›Œ๋“œ์™€ ์ผ์น˜ํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์žˆ์œผ๋ฉด ์ด๋ฅผ ํ™•์ธํ•ด ํ”„๋ก ํŠธ์—”๋“œ์— ์ „๋‹ฌํ•˜์—ฌ, ์›น ํŽ˜์ด์ง€์—์„œ ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์„ ํƒ๋œ ์ƒํƒœ๋กœ ํ‘œ์‹œ๋˜๋„๋ก ํ•จ.
    • Operator๋ฅผ AND๋กœ ์„ค์ •ํ•ด ๋ชจ๋“  ํ‚ค์›Œ๋“œ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๋ฌธ์„œ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ฒ˜๋ฆฌ.
  4. ์ตœ์ ํ™” ๊ณ ๋ ค

    • ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋‘ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ๊ณ ๋ ค ํ•„์š”.

๊ฒ€์ƒ‰ ์ •ํ™•๋„ ํŠœ๋‹

๊ธฐ์กด์—๋Š” ๋ฐฑ์—”๋“œ์—์„œ ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํ”„๋ก ํŠธ์—”๋“œ์— ํ•„ํ„ฐ๋ง๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ–ˆ์œผ๋‚˜, ์ด๋ฅผ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ํ•„ํ„ฐ ์•ˆ์—์„œ ์„ ํƒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๊ฒ€์ƒ‰ ๋กœ์ง

  1. ๊ฐ€๊ฒŒ ์ด๋ฆ„ ๊ฒ€์ƒ‰

    • bool ์ฟผ๋ฆฌ์—์„œ must์™€ prefix ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ€๊ฒŒ ์ด๋ฆ„์„ ๋จผ์ € ๊ฒ€์ƒ‰.
  2. ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ ์ ์šฉ

    • ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญ์— ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ๋ฅผ ํฌํ•จํ–ˆ๋‹ค๋ฉด, district_category.keyword ํ•„๋“œ์— ๋Œ€ํ•ด terms ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์ผ์น˜ํ•˜๋Š” ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •.
  3. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ™•์ธ

    • ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜.
  4. ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ํ†ตํ•ฉ ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰

    • bool ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•ด full_text ํ•„๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋ฉฐ, AND ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด ํ‚ค์›Œ๋“œ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜.
    • filter ๋ถ€๋ถ„์€ ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•ด ์นดํ…Œ๊ณ ๋ฆฌ ์กฐ๊ฑด์ด ์ ์šฉ๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜.

์ตœ์ ํ™”์™€ ๊ฐœ์„ 

์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ๊ฐ๊ฐ ๋‘ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ๊ฒ€์ƒ‰ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜์—ฌ, ๊ฐ€๊ฒŒ๋ช…์œผ๋กœ๋งŒ ๋จผ์ € ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ”๋กœ ํ†ตํ•ฉ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ตœ์ ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํŠœ๋‹ ํ…Œ์ŠคํŠธ

์„œ์šธ๋ณต์ง‘์„ ๊ฒ€์ƒ‰ํ•˜๋ฉฐ ํ†ตํ•ฉ ๊ฒ€์ƒ‰ ๋ฐฉ์‹์œผ๋กœ์˜ ์ „ํ™˜ ํ›„ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ–ˆ๊ณ , ๊ฒ€์ƒ‰ ์ •ํ™•๋„์™€ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

1์ฐจ ํ…Œ์ŠคํŠธ ๋ฐ ๊ฐœ์„ 

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค 1

  1. ์„œ์šธ๋ณต์ง‘ ๊ฒ€์ƒ‰ ์‹œ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๋Š” ์„œ์šธ ์ง€์—ญ์˜ ๋ณต์ง‘๋“ค์ด ์ตœ์ƒ์œ„์— ๋…ธ์ถœ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. ๊ฒฝ์ƒ๋‚จ๋„ ์„œ์šธ๋ณต์ง‘ ๊ฒ€์ƒ‰ ์‹œ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๋Š” ๊ฒฝ์ƒ๋‚จ๋„ ์ง€์—ญ์˜ ์„œ์šธ๋ณต์ง‘์ด ์ƒ์œ„์— ๋…ธ์ถœ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด ์ฟผ๋ฆฌ

boolBuilder.must(m -> m.match(x -> x.field("full_text").query(search.keyword()).operator(Operator.And))).boost(4f);
  • ์„œ์šธ๋ณต์ง‘ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์Œ. image

  • ๊ฒฝ์ƒ๋‚จ๋„ ์„œ์šธ๋ณต์ง‘ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ด. image

๋ฌธ์ œ์  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ

  • ์ฒซ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ์—์„œ ์„œ์šธ๋ณต์ง‘์ด ์ƒ์œ„์— ๋‚˜์˜ค์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด, ๊ฐ€๊ฒŒ ์ด๋ฆ„ ํ•„๋“œ์— ๊ฐ€์ค‘์น˜๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ should ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„ ๋œ ์ฟผ๋ฆฌ

boolBuilder.must(m -> m.match(x -> x.field("full_text").query(search.keyword()).operator(Operator.And))).boost(2f)
          .should(m -> m.match(x -> x.field("title").query(search.keyword()).boost(4f)));
  • ์„œ์šธ๋ณต์ง‘๊ณผ ๊ฒฝ์ƒ๋‚จ๋„ ์„œ์šธ๋ณต์ง‘ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๋ชจ๋‘ ๊ธฐ๋Œ€ํ•˜๋Š”๋Œ€๋กœ ๋‚˜์˜ด. image image

2์ฐจ ํ…Œ์ŠคํŠธ ๋ฐ ๊ฐœ์„ 

ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค 2

  1. ๋ณ„ ๊ฒ€์ƒ‰ ์‹œ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๋Š” ์ •ํ™•ํžˆ "๋ณ„"์ด๋ผ๋Š” ๊ฐ€๊ฒŒ๊ฐ€ ์ตœ์ƒ์œ„์— ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. ๋Œ€๊ตฌ ๋ณ„ ๊ฒ€์ƒ‰ ์‹œ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ๋Š” ๋Œ€๊ตฌ ์ง€์—ญ์— ์œ„์น˜ํ•œ "๋ณ„"์ด๋ผ๋Š” ๊ฐ€๊ฒŒ๊ฐ€ ์ƒ์œ„์— ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด ์ฟผ๋ฆฌ

boolBuilder.must(m -> m.match(x -> x.field("full_text").query(search.keyword()).operator(Operator.And))).boost(2f)
          .should(m -> m.match(x -> x.field("title").query(search.keyword()).boost(4f)));
  • ๋ณ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ๊ธฐ๋Œ€ํ•œ ๊ฒฐ๊ณผ์™€ ๋‹ฌ๋ฆฌ "๋ณ„์‚ฝ๋ณ„"์ด๋ผ๋Š” ๊ฐ€๊ฒŒ๊ฐ€ ์ตœ์ƒ์œ„์— ํ‘œ์‹œ๋จ. image

  • ๋Œ€๊ตฌ ๋ณ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ์–ด๋А ์ •๋„ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”์œผ๋‚˜, ์™„๋ฒฝํ•˜์ง€ ์•Š์Œ. image

๋ฌธ์ œ์  ๋ฐ ๊ฐœ์„  ๋ฐฉํ–ฅ

  • ๊ธฐ์กด should ์กฐ๊ฑด์˜ match ์ฟผ๋ฆฌ๋ฅผ term ์ฟผ๋ฆฌ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ, ๊ฐ€๊ฒŒ ์ด๋ฆ„๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์šฐ์„ ์œผ๋กœ ์ฒ˜๋ฆฌ

๊ฐœ์„ ๋œ ์ฟผ๋ฆฌ

boolBuilder.must(m -> m.match(x -> x.field("full_text").query(search.keyword()).operator(Operator.And))).boost(2f)
          .should(m -> m.term(x -> x.field("title").value(search.keyword()).boost(4f)));
  • ๋ณ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ์ด์ „๊ณผ ๋™์ผํ•˜๊ฒŒ ๊ธฐ๋Œ€ํ•œ ๊ฒฐ๊ณผ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์Œ. image

  • ๋Œ€๊ตฌ ๋ณ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ: ์ผ๋ถ€ ๊ฐœ์„ ์ด ์žˆ์—ˆ์œผ๋‚˜ ์—ฌ์ „ํžˆ ๊ธฐ๋Œ€์— ๋ฏธ์น˜์ง€ ๋ชปํ•จ. image

์ตœ์ข… ๊ฐœ์„  ์ฟผ๋ฆฌ

๊ธฐ์กด ์ฟผ๋ฆฌ๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ์„ 

  • ํ‚ค์›Œ๋“œ๊ฐ€ ๊ฐ€๊ฒŒ๋ช…๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋ฉด ๊ฐ€์ค‘์น˜ 2๋ฅผ ๋ถ€์—ฌ.
  • ํ‚ค์›Œ๋“œ๊ฐ€ ๊ฐ€๊ฒŒ๋ช…๊ณผ ๋ถ€๋ถ„ ์ผ์น˜ํ•˜๋ฉด ๊ฐ€์ค‘์น˜ 1.5๋ฅผ ๋ถ€์—ฌ.
boolBuilder = new BoolQuery.Builder()
        .must(m -> m.match(t -> t
                .field("full_text")
                .query(search.keyword())
                .operator(Operator.And)))
        .should(s -> s.match(t -> t
                .field("title")
                .query(search.keyword())
                .boost(1.5f)))
        .should(s -> s.term(t -> t
                .field("title.keyword")
                .value(search.keyword())
                .boost(2.0f)));

3์ฐจ ํ…Œ์ŠคํŠธ ๋ฐ ๊ฐœ์„ 

๋ฉ”๋‰ด ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

๊ธฐ์กด ๊ฒ€์ƒ‰์—์„œ๋Š” ๊ฐ€๊ฒŒ ์ด๋ฆ„๊ณผ ์ฃผ์†Œ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋„์ถœํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ฉ”๋‰ด ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ฉฐ, ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ๋ฅผ Elasticsearch์— ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.


Elasticsearch ์—…๋ฐ์ดํŠธ ๋ฐฉ์‹

  1. ๊ฐ€๊ฒŒ ๋ฐ ๋ฉ”๋‰ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋”ฐ๋ฅธ ์—…๋ฐ์ดํŠธ

    • ๊ฐ€๊ฒŒ ์ƒ์„ฑ, ์‚ญ์ œ, ์ˆ˜์ •, ๋ณ€๊ฒฝ ์‹œ Elasticsearch์— ์ฆ‰์‹œ ๋ฐ˜์˜.
    • ๋ฉ”๋‰ด ์ƒ์„ฑ, ์ˆ˜์ •, ์‚ญ์ œ, ๋ณ€๊ฒฝ ์‹œ์—๋„ ๋™์ผํ•˜๊ฒŒ ์ฆ‰์‹œ ๋ฐ˜์˜.
  2. ํ˜„์žฌ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ

    • ๋ฐ์ดํ„ฐ๊ฐ€ ์ ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝ์‚ฌํ•ญ ๋ฐœ์ƒ ์‹œ ๋ฐ”๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰.
    • ์ถ”ํ›„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ง€๋ฉด, ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ชจ์•„ Bulk Update ๋ฐฉ์‹์œผ๋กœ ์ „ํ™˜ํ•  ์˜ˆ์ •.
  3. copy_to ํ™œ์šฉ

    • ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ๋ฅผ copy_to๋กœ full_text ํ•„๋“œ์— ์ €์žฅํ•˜์—ฌ, ๊ธฐ์กด ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •.

์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ

์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ฐ€๊ฒŒ ์ •๋ณด์™€ ๋ฉ”๋‰ด ์ •๋ณด๊ฐ€ Elasticsearch์— ์ €์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

image


ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค

  1. ์•„๋ฉ”๋ฆฌ์นด๋…ธ ๊ฒ€์ƒ‰

    • ๋ฉ”๋‰ด์— "์•„๋ฉ”๋ฆฌ์นด๋…ธ"๊ฐ€ ํฌํ•จ๋œ ๊ฐ€๊ฒŒ๊ฐ€ ๊ฒ€์ƒ‰๋จ.
    • ๊ฒฐ๊ณผ: ๋ฉ”๋‰ด ๊ฒ€์ƒ‰์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™. image
  2. ์•„์ด์Šค ์•„๋ฉ”๋ฆฌ์นด๋…ธ ๊ฒ€์ƒ‰

    • ๋ฉ”๋‰ด์— "์•„์ด์Šค ์•„๋ฉ”๋ฆฌ์นด๋…ธ"๊ฐ€ ํฌํ•จ๋œ ๊ฐ€๊ฒŒ๊ฐ€ ๊ฒ€์ƒ‰๋จ.
    • ๊ฒฐ๊ณผ: ๋ฉ”๋‰ด ๊ฒ€์ƒ‰์ด ๋ณตํ•ฉ ํ‚ค์›Œ๋“œ์—์„œ๋„ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™. image

๊ฒฐ๋ก 

  • ๋ฉ”๋‰ด ๋ฐ์ดํ„ฐ๋ฅผ Elasticsearch์— ์ €์žฅํ•˜๋ฉด์„œ ๊ธฐ์กด ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„๋„ full_text ํ•„๋“œ์—์„œ ๋ฉ”๋‰ด ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•ด์กŒ์Šต๋‹ˆ๋‹ค.
  • ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ˜„์žฌ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ ์–ด ๊ฐ€๊ฒŒ ๋ฐ ๋ฉ”๋‰ด์— ๋Œ€ํ•ด update๊ฐ€ ์žˆ์œผ๋ฉด ์ฆ‰์‹œ, ์—˜๋ผ์Šคํ‹ฑ ์„œ์น˜์— crud ์š”์ฒญ์„ ๋ณด๋‚ด์ง€๋งŒ, ์ถ”ํ›„์— ์Œ“์ธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋ฉด Bulk Update ๋ฐฉ์‹์œผ๋กœ์˜ ์ „ํ™˜์„ ๊ณ ๋ ค ์ค‘์ž…๋‹ˆ๋‹ค.



๋ฉค๋ฒ„ ์†Œ๊ฐœ

์ด๋ฆ„ ํฌ์ง€์…˜ Github ๋งํฌ
ํ™ฉํ˜ธ์ง„ ๋ฆฌ๋” [๐Ÿhttps://github.com/ballqs]
์ •์žฌํ˜ธ ๋ถ€๋ฆฌ๋” [๐Ÿhttps://github.com/Nameless1004]
์กฐ์ˆ˜ํ˜„ ํŒ€์› [๐Ÿhttps://github.com/SuHyun-git]
๊น€์œค์„œ ํŒ€์› [๐Ÿhttps://github.com/yunseokim119]
๊ธธ์šฉ์ง„ ํŒ€์› [๐Ÿhttps://github.com/pumaclass/]

Ground Rule

  1. ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ์ฆ‰์‹œ ๊ณต์œ 

    • ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํŒ€์›๋“ค์—๊ฒŒ ๋น ๋ฅด๊ฒŒ ์ƒํ™ฉ์„ ๊ณต์œ ํ•˜์—ฌ ํ˜‘๋ ฅ ํ•ด๊ฒฐ.
  2. ์ผ์ • ๋ฌด์กฐ๊ฑด ์ง€ํ‚ค๊ธฐ

    • ์ผ์ • ๋ณ€๋™ ์‹œ ์Šฌ๋ž™ ๊ณต์œ  ๋ฐ ์ฃผ๋ง ํ™œ์šฉํ•  ๊ฒƒ.
  3. ์‚ฌ์†Œํ•œ ๊ฒƒ๋„ ์งˆ๋ฌธํ•˜๊ธฐ

    • ๊ถ๊ธˆํ•œ ์ ์ด๋‚˜ ๋ง‰ํžŒ ๋ถ€๋ถ„์€ ์‚ฌ์†Œํ•œ ๊ฒƒ์ด๋ผ๋„ ์ฆ‰์‹œ ๋ฌผ์–ด๋ณด๊ณ  ํ•ด๊ฒฐ.
  4. ์Šคํฌ๋Ÿผ์—์„œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… ๋ฐ ๊ตฌํ˜„ ์‚ฌํ•ญ ์„ค๋ช…

    • ๋งค์ผ ์Šคํฌ๋Ÿผ ์‹œ๊ฐ„์— ๊ตฌํ˜„ ์ง„ํ–‰ ์ƒํ™ฉ๊ณผ ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •์„ ๊ณต์œ .
  5. 1Day, 1Code Review, 1PR ์›์น™

    • ํ•˜๋ฃจ์— ํ•˜๋‚˜ ์ด์ƒ์˜ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋ฐ PR ์ƒ์„ฑ.
  6. 1PR ๋‹น 1์ธ ์ด์ƒ ํ™•์ธ ํ›„ ๋จธ์ง€

    • ๊ฐ PR์— ๋Œ€ํ•ด ์ตœ์†Œ 1๋ช… ์ด์ƒ์˜ ์Šน์ธ์„ ํ†ตํ•ด ์ฝ”๋“œ ํ’ˆ์งˆ์„ ๊ฐœ์„ .

์„ฑ๊ณผ ๋ฐ ํšŒ๊ณ 

์ž˜๋œ ์ 

  • ์„ฑ๋Šฅ ์ตœ์ ํ™” ์„ฑ๊ณต

    • Redis ์บ์‹ฑ์„ ๋„์ž…ํ•ด 1048.9ms์—์„œ 4.32ms๋กœ ์•ฝ 24278% ํ–ฅ์ƒ์‹œํ‚ด
    • Like , ์กฐํšŒ์ˆ˜ ๊ธฐ๋Šฅ์„ ์ดˆ๋‹น 1000๋ฒˆ ์ ‘๊ทผ์ด ๋˜์–ด๋„ ๋ฌธ์ œ ์—†์ด ๋™์ž‘
  • ํšจ์œจ์ ์ธ ํ˜‘์—…

    • ํŒ€์› ๊ฐ„ ์—ญํ•  ๋ถ„๋‹ด์ด ๋ช…ํ™•ํ–ˆ์œผ๋ฉฐ, GitHub Actions , Jenkins์„ ํ™œ์šฉํ•œ CI/CD ๊ตฌ์ถ•์œผ๋กœ ๊ฐœ๋ฐœ-๋ฐฐํฌ ์ฃผ๊ธฐ๋ฅผ ๋‹จ์ถ•.
    • ๋งค์ผ ์Šคํฌ๋Ÿผ์„ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ณต์œ ํ•˜๊ณ , ์ ๊ทน์ ์œผ๋กœ ํ•ด๊ฒฐ.
    • GitHub์— commit์‹œ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•ด๋‹น commit์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์‰ฝ๊ฒŒ ํŒŒ์•… ๊ฐ€๋Šฅ

์•„์‰ฌ์šด ์ 

  • ์˜์‚ฌ์†Œํ†ต์ด ์ž˜๋˜์—ˆ์ง€๋งŒ ์ •์ฑ…์ ์ธ ๋ถ€๋ถ„์— ๋Œ€ํ•ด ์ง€์‹๋ถ€์กฑ์œผ๋กœ ์˜๊ฒฌ์ถฉ๋Œ์ด ์žฆ์Œ.
    • ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ๊ฐ„์˜ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜๊ฒฌ ์ถฉ๋Œ์— ์˜ํ•ด์„œ ๋น„๊ต์  ์‹œ๊ฐ„์„ ๋งŽ์ด ์Ÿ์•˜๋‹ค.

ํ–ฅํ›„ ๊ณ„ํš

  • ๊ธฐ์ˆ ์  ๊ณ ๋„ํ™”

    • ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ CI/CD ๊ฐœ์„  ๊ณ„ํš
    • ์—˜๋ผ์Šคํ‹ฑ์„œ์น˜๋ฅผ ํ†ตํ•ด ํฌ๋กค๋ง์‹œ ์•…์„ฑ ํ›„๊ธฐ ๋ฐ ์ €ํ’ˆ์งˆ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ•„ํ„ฐ๋ง ์ž‘์—…
  • ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

    • WebFlux๋ฅผ ๋„์ž…ํ•ด ๋ฆฌ์•กํ‹ฐ๋ธŒํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ I/O๊ธฐ๋Šฅ์„ ๋ชจ๋“ˆ๋กœ ๋นผ๋Š” ์ž‘์—…
    • MSA๋ฅผ ๊ณต๋ถ€ํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ์„œ๋น„์Šค๋กœ ๋‚˜๋ˆ  ๋ฐฐํฌํ•˜๊ธฐ
  • ํ…Œ์ŠคํŠธ ์ž๋™ํ™” ๊ฐ•ํ™”

    • ๊ธฐ์กด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์™ธ์— ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ๋ฐ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์•ˆ์ •์„ฑ์„ ๋”์šฑ ๊ฐ•ํ™”.

โ˜ ์™€์ด์–ดํ”„๋ ˆ์ž„

https://www.figma.com/design/XC7jH231J14F6BCBdgOsf1/Untitled?node-id=0-1&t=VN6XSThorsDXxCW2-1

โ˜ ERD ๋‹ค์ด์–ด๊ทธ๋žจ

image

๐Ÿ“‘ API ๋ช…์„ธ์„œ

์ƒ์„ธ๋ณด๊ธฐ

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors