Technical Challenges

1. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•

Event-Driven Streaming Architecture ์ „ํ™˜

๋ฌธ์ œ ์ƒํ™ฉ

์ดˆ๊ธฐ ์‹œ์Šคํ…œ์€ FastAPI ํฌ๋กค๋Ÿฌ๊ฐ€ LibreView์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ MySQL์— ์ €์žฅํ•˜๋ฉด, Spring Boot Scheduler๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋‹จ์ˆœ ๋ฐฐ์น˜ ๊ตฌ์กฐ์˜€์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ธ‰๊ฒฉํ•œ ํ˜ˆ๋‹น ๋ณ€ํ™”๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ–ˆ๊ณ , ์‚ฌ์šฉ์ž๋Š” ์ง€์—ฐ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ฒŒ ๋˜๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

์‹ค์‹œ๊ฐ„์„ฑ ํ™•๋ณด๋ฅผ ์œ„ํ•ด Event-Driven Streaming Architecture๋กœ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

์•„ํ‚คํ…์ฒ˜ ๊ตฌ์„ฑ

  • Airflow: ํฌ๋กค๋ง ์Šค์ผ€์ค„ ๊ด€๋ฆฌ ๋ฐ ETL ์›Œํฌํ”Œ๋กœ์šฐ ์กฐ์œจ

  • Kafka: ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ์ „๋‹ฌ ๋ฐ ๋ฉ”์‹œ์ง€ ์œ ์‹ค ๋ฐฉ์ง€

  • Spring Boot Consumer: Kafka ๋ฉ”์‹œ์ง€ ๊ตฌ๋… ํ›„ MySQL ์ ์žฌ

  • Redis Cache: ์ตœ์‹  ๋ฐ์ดํ„ฐ ์บ์‹ฑ์œผ๋กœ ๋น ๋ฅธ ์กฐํšŒ ์ง€์›

  • WebSocket (STOMP): ํด๋ผ์ด์–ธํŠธ์— ์‹ค์‹œ๊ฐ„ ํ‘ธ์‹œ

Kafka Topic์œผ๋กœ ๋ฐœํ–‰๋œ ๋ฐ์ดํ„ฐ๋Š” Consumer์—์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ์ฆ‰์‹œ MySQL์— ์ €์žฅ๋˜๊ณ , WebSocket์„ ํ†ตํ•ด ๋Œ€์‹œ๋ณด๋“œ์— ์‹ค์‹œ๊ฐ„ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

LibreView โ†’ Airflow (ETL) โ†’ Kafka (Producer)
                              โ†“
                        Spring Boot (Consumer)
                        โ”œโ”€โ”€ MySQL (Storage)
                        โ”œโ”€โ”€ Redis (Cache)
                        โ””โ”€โ”€ WebSocket โ†’ Dashboard

๊ฒฐ๊ณผ

๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์ฆ‰์‹œ ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜์˜๋˜๋Š” ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ ํ˜ˆ๋‹น ๋ณ€ํ™” ๋ชจ๋‹ˆํ„ฐ๋ง์ด ๊ฐ€๋Šฅํ•ด์กŒ์Šต๋‹ˆ๋‹ค.


2. ์•ˆ์ •์ ์ธ ํŒŒ์ดํ”„๋ผ์ธ ์žฌ๊ตฌ์„ฑ

Modular DAG ๊ธฐ๋ฐ˜ ์•ˆ์ •์„ฑ ํ™•๋ณด

๋ฌธ์ œ ์ƒํ™ฉ

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

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

Modular DAG ๊ธฐ๋ฐ˜ ํŒŒ์ดํ”„๋ผ์ธ์„ Airflow๋กœ ์žฌ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๊ฐœ์„ ์‚ฌํ•ญ

  • Task ๋…๋ฆฝํ™”: crawl โ†’ validate โ†’ store โ†’ aggregate๋กœ ๋ถ„๋ฆฌ

  • ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ: S3 ์ €์žฅ๊ณผ MySQL ์ ์žฌ ๋™์‹œ ์ˆ˜ํ–‰

  • ๋ถ€๋ถ„ ์žฌ์‹คํ–‰: XCom์„ ํ™œ์šฉํ•ด ์‹คํŒจํ•œ Task๋งŒ ์žฌ์‹คํ–‰

  • ๊ฒฐํ•ฉ๋„ ์™„ํ™”: Kafka๋กœ ์ˆ˜์ง‘(Producer)๊ณผ ์ฒ˜๋ฆฌ(Consumer) ๋ถ„๋ฆฌ

  • ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ: Spark Streaming์œผ๋กœ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ

  • ๋ฐฐ์น˜ ์ง‘๊ณ„: Spark Batch๋กœ ์ผ์ผ ํ†ต๊ณ„ ์ž๋™ ๊ณ„์‚ฐ

๊ฒฐ๊ณผ

๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋กœ ์ „ํ™˜ํ•˜์—ฌ ํŒŒ์ดํ”„๋ผ์ธ์˜ ์•ˆ์ •์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํ–ฅ์ƒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.


3. ๋ฐ์ดํ„ฐ ํ’ˆ์งˆ ๊ด€๋ฆฌ ์ฒด๊ณ„ ๊ตฌ์ถ•

๋‹ค์ธต ๊ฒ€์ฆ์„ ํ†ตํ•œ ์‹ ๋ขฐ๋„ ํ™•๋ณด

๋ฌธ์ œ ์ƒํ™ฉ

์™ธ๋ถ€ ํฌ๋กค๋ง ๋ฐ์ดํ„ฐ์—์„œ ๋ˆ„๋ฝ, ์ค‘๋ณต, ๋น„์ •์ƒ ๊ฐ’์ด ๋ฐœ๊ฒฌ๋˜์–ด ํ†ต๊ณ„ ๋ถ„์„ ๊ฒฐ๊ณผ์˜ ์‹ ๋ขฐ๋„๊ฐ€ ์ €ํ•˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

Airflow์— Data Validation Layer๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๋‹ค์ธต ๊ฒ€์ฆ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ ๋กœ์ง

  • ๋ฒ”์œ„ ๊ฒ€์ฆ: ๋น„์ •์ƒ ํ˜ˆ๋‹น๊ฐ’(40~400mg/dL ๋ฒ”์œ„ ์™ธ) ์ œ๊ฑฐ

  • ์ค‘๋ณต ์ œ๊ฑฐ: pet_id + timestamp ๊ธฐ์ค€ deduplication

  • ํƒ€์ž„์กด ์ •๊ทœํ™”: UTC โ†’ KST ๋ณ€ํ™˜

  • ๋ฉฑ๋“ฑ์„ฑ ๋ณด์žฅ: Kafka Consumer์— idempotency ๋กœ์ง ์ ์šฉ

  • DB ์ œ์•ฝ: MySQL UNIQUE INDEX๋กœ ์ค‘๋ณต ์ฐจ๋‹จ

  • ์ž๋™ ์•Œ๋ฆผ: ์ด์ƒ์น˜ ๋น„์œจ ์ดˆ๊ณผ ์‹œ Slack Webhook ๋ฐœ์†ก

๊ฒฐ๊ณผ

๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์ด ๊ฐ•ํ™”๋˜์–ด ํ†ต๊ณ„ ๋ถ„์„์— ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


4. ์ฒ˜๋ฆฌ ๊ณ„์ธต ๋ถ„๋ฆฌ ์„ค๊ณ„

Lambda Architecture ๊ธฐ๋ฐ˜ ์—ญํ•  ๋ถ„๋‹ด

๋ฌธ์ œ ์ƒํ™ฉ

๋ชจ๋“  ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ์„œ๋ฒ„ ๋ถ€ํ•˜๊ฐ€ ์ฆ๊ฐ€ํ–ˆ๊ณ , ํ†ต๊ณ„ ์ง‘๊ณ„ ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹œ ์‘๋‹ต ์ง€์—ฐ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

Lambda Architecture ํŒจํ„ด์œผ๋กœ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ณ„์ธต์„ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ณ„์ธต๋ณ„ ์—ญํ• 

  • Speed Layer (์‹ค์‹œ๊ฐ„): Kafka + Spark Streaming โ†’ Redis ์บ์‹ฑ

  • Batch Layer (์ •๊ธฐ ์ง‘๊ณ„): Airflow + Spark Batch โ†’ MySQL Summary Table

  • Serving Layer (์กฐํšŒ): Spring Boot โ†’ MySQL & Redis

Spark Batch๋Š” ๋งค์ผ ์ƒˆ๋ฒฝ Airflow DAG์— ์˜ํ•ด ์‹คํ–‰๋˜๋ฉฐ, ์ „๋‚  ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•˜์—ฌ ํ‰๊ท  ํ˜ˆ๋‹น, ์ŠคํŒŒ์ดํฌ ํšŸ์ˆ˜ ๋“ฑ์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ

์‹ค์‹œ๊ฐ„์„ฑ๊ณผ ์ง‘๊ณ„ ํšจ์œจ์„ฑ์„ ๋™์‹œ์— ํ™•๋ณดํ•˜๊ณ , ์„œ๋ฒ„ ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐ์‹œํ‚จ ์•ˆ์ •์ ์ธ ์šด์˜ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.


5. ์‚ฌ๋ฃŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์ถ•

ํฌ๋กค๋ง ๊ธฐ๋ฐ˜ ์ •๋ณด ์ˆ˜์ง‘ ๋ฐ ๊ด€๋ฆฌ

๋ฌธ์ œ ์ƒํ™ฉ

๋ฐ˜๋ ค๋™๋ฌผ ์‚ฌ๋ฃŒ์— ๋Œ€ํ•œ ์ฒด๊ณ„์ ์ธ ์ •๋ณด๊ฐ€ ๋ถ€์กฑํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์˜์–‘ ์„ฑ๋ถ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ๋ฃŒ๋ฅผ ๋น„๊ตํ•˜๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

Selenium์„ ํ™œ์šฉํ•ด ์‚ฌ๋ฃŒ ์ •๋ณด๋ฅผ ์ž๋™ ์ˆ˜์ง‘ํ•˜๊ณ  MongoDB์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๋‚ด์šฉ

  • ๋‹ค๋‚˜์™€์—์„œ ๊ฐœยท๊ณ ์–‘์ด ์‚ฌ๋ฃŒ ์ •๋ณด ํฌ๋กค๋ง

  • ์˜์–‘ ์„ฑ๋ถ„ ๋ฐ์ดํ„ฐ ์ •๊ทœํ™” (๋‹จ๋ฐฑ์งˆ, ํƒ„์ˆ˜ํ™”๋ฌผ, GI ์ง€์ˆ˜ ๋“ฑ)

  • MongoDB ์Šคํ‚ค๋งˆ ์„ค๊ณ„ ๋ฐ ์ธ๋ฑ์‹ฑ

  • ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ•„ํ„ฐ๋ง API ๊ตฌํ˜„ (์ €ํƒ„์ˆ˜ํ™”๋ฌผ, ์ €GI, ๊ณ ๋‹จ๋ฐฑ ๋“ฑ)

๊ฒฐ๊ณผ

์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ์˜์–‘ ๊ธฐ์ค€์— ๋งž๋Š” ์‚ฌ๋ฃŒ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.

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


6. ๋„๋ฉ”์ธ ๊ธฐ์ค€ ์ •๋ฆฝ

์ˆ˜์˜์‚ฌ ํ˜‘์—…์„ ํ†ตํ•œ ์ž„๊ณ„๊ฐ’ ํ‘œ์ค€ํ™”

๋ฌธ์ œ ์ƒํ™ฉ

ํŒ€ ๋‚ด๋ถ€์— ๋ฐ˜๋ ค๋™๋ฌผ ๊ฑด๊ฐ• ๋ฐ์ดํ„ฐ ํ•ด์„ ์ „๋ฌธ ์ง€์‹์ด ๋ถ€์กฑํ•ด, ํ˜ˆ๋‹น ์ •์ƒ ๋ฒ”์œ„์™€ ์•Œ๋ฆผ ๊ธฐ์ค€์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ํ•ด๊ฒฐ

์ˆ˜์˜์‚ฌ ๋ฐ ๋ฐ˜๋ ค๋™๋ฌผ ๋ณดํ˜ธ์ž ์ธํ„ฐ๋ทฐ๋ฅผ ํ†ตํ•ด ๋„๋ฉ”์ธ ์ง€์‹์„ ์ˆ˜์ง‘ํ•˜๊ณ , ์‹œ์Šคํ…œ ์„ค๊ณ„์— ๋ฐ˜์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ™•๋ฆฝ๋œ ๊ธฐ์ค€

  • ์ˆ˜์˜์‚ฌ ์ž๋ฌธ์œผ๋กœ ํ˜ˆ๋‹น ์ •์ƒ ๋ฒ”์œ„(80~120mg/dL) ๋ฐ ์ŠคํŒŒ์ดํฌ ์ •์˜(30๋ถ„ ๋‚ด 30% ์ด์ƒ ๋ณ€ํ™”) ํ™•๋ฆฝ

  • ๋ณดํ˜ธ์ž ์ธํ„ฐ๋ทฐ๋กœ ์•Œ๋ฆผ ๋นˆ๋„ ๋ฐ ๋ฆฌํฌํŠธ ์ง€ํ‘œ ๊ฒ€์ฆ

  • ์•Œ๋ฆผ ์šฐ์„ ์ˆœ์œ„(์ €ํ˜ˆ๋‹น > ๊ณ ํ˜ˆ๋‹น > ์ŠคํŒŒ์ดํฌ) ๋กœ์ง ๊ตฌํ˜„

๊ฒฐ๊ณผ

๋„๋ฉ”์ธ ๊ธฐ์ค€์„ ๋ช…ํ™•ํžˆ ์ •์˜ํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํ•ด์„์˜ ์ผ๊ด€์„ฑ๊ณผ ์•Œ๋ฆผ ๋กœ์ง์˜ ์‹ ๋ขฐ๋„๋ฅผ ๋†’์˜€์Šต๋‹ˆ๋‹ค.

Last updated