βμ€μκ° λ°©μ‘, λμΉμ§ λ§κ³ CatchLive νμΈμ!β
βλΉμ μ μ€νΈλ¦¬λ¨Έμ μ€νΈλ¦¬λ° μκ°μ μλμΌλ‘ μΊμΉν΄λ립λλ€.β
- νλ‘μ νΈ κ°μ
- νλ‘μ νΈ λκΈ°
- λ ν¬μ§ν°λ¦¬ μν
- ν΅μ¬ κΈ°λ₯
- κΈ°μ μ€ν
- κ°λ° μ€ κ³ λ―Όκ³Ό ν΄κ²°
- λ©€λ² μκ°
- νκ³
- νλ‘μ νΈλͺ : CatchLive
- κΈ°κ°: 2025.5.26 ~ 2025.6.20 (κΈ°ν 1μ£Ό / κ°λ° λ° λ°°ν¬ 4μ£Ό)
- λͺ©μ : μ€μκ° λΌμ΄λΈ μ€νΈλ¦¬λ° λ Ήνλ₯Ό μν νλ‘μ νΈ
- λμ μ¬μ©μ: λΌμ΄λΈ μ€νΈλ¦¬λ° λ°©μ‘ μκ°μ μ½μμ΄ μμ΄μ λ³΄μ§ λͺ»νλ μ¬λλ€
μ€μκ° λΌμ΄λΈ μ€νΈλ¦¬λ°μ μ μ λ λ§μ μ½ν μΈ κ° μμ±λκ³ μλΉλλ ν΅μ¬ νλ«νΌμ΄ λκ³ μμ΅λλ€. νμ§λ§ νλ«νΌ μ체μμ λΌμ΄λΈ λ°©μ‘μ λ€μ 보기 κΈ°λ₯ μμ΄ μ’ λ£ν΄λ²λ¦¬λ κ²½μ°κ° λ§κ³ , μ¬μ©μλ€μ΄ λμΉ λ°©μ‘μ λ€μ μμ²ν μ μλ λ°©λ²μ μ νμ μ λλ€.
νΉν ν¬λ€ μ€μ¬μ μ½ν μΈ μλΉκ° νλ°ν μ§κΈ, μ€μκ° μ€νΈλ¦¬λ°μ λμΉλ©΄ μμ λ³Ό μ μλ μμ¬μμ μ¬μ©μμκ² ν° λΆνΈν¨μ΄ λ©λλ€. λν ν¬λ¦¬μμ΄ν°λ λ°μ΄ν° λΆμκ° μ μ₯μμλ λ°©μ‘ κΈ°λ‘μ 보κ΄νκ±°λ νμ μ½ν μΈ μ μμ νμ©ν μ μλ μλ¨μ΄ νμν©λλ€.
μ΄ νλ‘μ νΈλ YouTube, μΉμ§μ§(Chzzk) λ± λ€μν νλ«νΌμμ μ€μκ° λ°©μ‘μ΄ μμλλ©΄ μλμΌλ‘ κ°μ§νκ³ , λ°©μ‘ μ’ λ£ μκΉμ§ μμ μ μΌλ‘ λ Ήνν΄μ£Όλ λ°±μλ μμ€ν μ ꡬνν κ²μ λλ€.
μ±λ ꡬλ β λΌμ΄λΈ κ°μ§ β λ Ήν μμ β S3 μ λ‘λ β μλ£ μλ¦Ό β μμ λ€μ΄λ‘λκΉμ§ μλνλ νμ΄νλΌμΈμ ν΅ν΄ ν¬, ν¬λ¦¬μμ΄ν°, νλ«νΌ μ΄μμ λͺ¨λμκ² μ μ©ν μ€νΈλ¦¬λ° λ°±μ μμ€ν μ λ§λλ κ²μ΄ λͺ©νμμ΅λλ€.
μ΄ λ ν¬μ§ν 리λ CatchLiveμ νλ‘ νΈμλ μ ν리μΌμ΄μ μ κ΄λ¦¬νλ μ μ₯μμ λλ€.
λ³Έ νλ‘μ νΈλ Reactμ TypeScript, Viteλ₯Ό κΈ°λ°μΌλ‘ ꡬμΆλμμΌλ©°, ν΄λΌμ΄μΈνΈμμ μ¬μ©μμμ μνΈμμ© λ° API μ°λ, UI λ λλ§ λ±μ λ΄λΉν©λλ€.
βΈ»
λ€μμ src/ λλ ν 리λ₯Ό μ€μ¬μΌλ‘ ν μ£Όμ ν΄λ λ° νμΌμ ꡬμ±μ λλ€.
catch-live-app/
βββ src/
β βββ api/ # λ°±μλ API μμ² κ΄λ ¨ ν¨μλ€μ λͺ¨μλ‘λλ€.
β βββ assets/ # μ΄λ―Έμ§, ν°νΈ λ± μ μ 리μμ€κ° μμΉν©λλ€.
β βββ components/ # μ¬μ¬μ© κ°λ₯ν UI μ»΄ν¬λνΈλ₯Ό μ μν©λλ€.
β βββ config/ # κΈλ‘λ² μ€μ , μΈλΆ μλΉμ€ ν€, νκ²½ λ³μ λ±μ κ΄λ¦¬ν©λλ€.
β βββ constants/ # 곡ν΅μΌλ‘ μ¬μ©νλ μμλ€μ μ μν©λλ€.
β βββ errors/ # μλ¬ νΈλ€λ§ κ΄λ ¨ μ½λμ μλ¬ νμ
μ μ μν©λλ€.
β βββ hooks/ # 컀μ€ν
ν
(Custom Hook)μ μ μν©λλ€.
β βββ pages/ # μ€μ λΌμ°ν
λλ νμ΄μ§ μ»΄ν¬λνΈλ€μ΄ μμΉν©λλ€.
β βββ stores/ # μν κ΄λ¦¬ (μ: Zustand λ±)μ κ΄λ ¨λ μ½λκ° μμΉν©λλ€.
β βββ tests/ # ν
μ€νΈ μ½λκ° μμΉν©λλ€.
β βββ types/ # μ μμμ μ¬μ©νλ TypeScript νμ
μ μ νμΌμ΄ μμΉν©λλ€.
β βββ utils/ # μ νΈλ¦¬ν° ν¨μλ€μ λͺ¨μλλ ν΄λμ
λλ€.
- μ¬μ©μλ μνλ μ€νΈλ¦¬λ¨Έλ₯Ό ꡬλ
ν μ μμ΅λλ€.(CHZZK or YOUTUBE)
- μ΅λ 5λͺ κΉμ§ μ€νΈλ¦¬λ¨Έλ₯Ό ꡬλ ν μ μμ΅λλ€.
- ꡬλ ν μμ λΆν° μ€νΈλ¦¬λ¨Έκ° λΌμ΄λΈ μ€μΌ κ²½μ° μλμΌλ‘ λ Ήνκ° μμλ©λλ€.
- μ¬μ©μλ νμ¬ μμ μ΄ κ΅¬λ μ€μΈ λ Ήν μν©μ λ³Ό μ μμ΅λλ€.
- λ°©μ‘μ΄ μ’
λ£λ κ²½μ°, λ€μ΄λ‘λλ₯Ό ν΅ν΄ λ
Ήν νμΌμ νμΈν μ μμ΅λλ€.
- μ΅λ 3μΌκΉμ§ λ€μ΄λ‘λ κ°λ₯ν©λλ€.
- κ²μμ ν΅ν΄ μμ μ΄ μ°Ύκ³ μΆμ λ Ήν νμΌμ μ°Ύμ μ μμ΅λλ€.
- Language: Node 18
- Framework: NestJS 11
- Database: MySQL 8.xx
- Infrastructure: Redis 7.x
- ORM: Prisma 6.8
- Authentication: OAuth2 + JWT
- CI/CD: GitHub Actions + Docker + AWS Elastic Beanstalk
- Middleware: AWS ElasticCache, AWS S3, AWS RDS
Reactλ μ»΄ν¬λνΈ κΈ°λ°κ³Ό Virtual DOMμ ν΅ν΄ ν¨μ¨μ μ΄κ³ μ μΈμ μΈ UI ꡬμΆμ μ§μνλ JavaScript λΌμ΄λΈλ¬λ¦¬ μ λλ€. λ°μ½λ μ΄ν°λ λͺ¨λ λ±λ‘ λ±μ μΆκ°μ μΈ μμ μμ΄λ μ¬μ¬μ©μ΄ κ°λ₯ν μ»΄ν¬λνΈ κ΅¬μ‘°λ₯Ό μ±ννκ³ μμΌλ©°, Virtual DOM μ ν΅ν΄ ν¨μ¨μ μΈ μν κ΄λ¦¬μ λΉ λ₯Έ DOM μ λ°μ΄νΈλ₯Ό μ§μν©λλ€. μ’μ κ°λ°μ κ²½νμ μ 곡νλ€λ Reactμ κ°λ° λ°©ν₯κ³Ό λ§μ μ μ μλ₯Ό ν΅ν΄ νΈλ¬λΈ μν κ³Ό λλ²κΉ μ μ μ©ν μ 보λ€μ μμ½κ² μ»μ μ μμ΅λλ€.
Angular λ³΄λ€ μ½κ² μ¬μ©ν μ μκ³ , Vue.js λ³΄λ€ λ§μ νΈλ¬λΈμν , λλ²κΉ μ 보λ₯Ό μ»μ μ μμ΄, ν νλ‘μ νΈλ₯Ό μμ μ μΌλ‘ μνν μ μλ Reactλ₯Ό μ¬μ©νκΈ°λ‘ νμ΅λλ€.
Viteλ λ€μ΄ν°λΈ ES λͺ¨λκ³Ό Rollup κΈ°λ° μλ μ΅μ ν νλ‘λμ λΉλλ₯Ό μ 곡νλ λΉλ λꡬμ λλ€. λ²λ€λ§μ΄λΌλ μ μ²λ¦¬, ν¨ν€μ§, λ³κ²½μ¬νκ³Ό κ΄λ ¨λ λΆλΆλ§ μ¬μμ νλ κΈ°λ₯μ ν΅ν΄ κ°λ° μλ²μ λΉλ, μ€ν μκ°μ λν μ€μΌ μ μμ΅λλ€. μ€νμ€μΌλλ λ³κ²½μ¬νμ λ°μνλ HRM κΈ°λ₯κ³Ό λ²λ€λ§ κ³Όμ μμ λΆνμν μ½λλ₯Ό μ κ±°νλ νΈλ¦¬μ °μ΄νΉ, μ¬λ¬ κΈ°μ€λ€λ‘ λ²λ€λ§μ λΆν νμ¬ μ΄κΈ° λ‘λ©μ§μ° λ±μ κ°μμν¬μ μλ μ½λ μ€ν리ν κΈ°λ₯λ μ 곡ν©λλ€.
Webpackμ μ무λ μ¬μ©ν κ²½νμ΄ μμ΄ λ무 λμ΄λκ° λμκ³ , parcelμ Vite λ³΄λ€ λ κ°λ¨νκ² μ¬μ©ν μ μμ§λ§, μ΄μ μ λ²λ€λ§ν λ°μ΄ν°λ₯Ό μ¬μ¬μ©νμ§ μκ³ λ§€λ² μλ‘ λ²λ€λ§μ ν©λλ€. Viteλ parcel λ§νΌμ μλμ§λ§ μΆ©λΆν κ°λ¨ν μ¬μ©λ²κ³Ό μ’μ κΈ°λ₯, λ§μ μ¬μ©μλ€μ΄ μ λ‘λν νΈλ¬λΈμν , λλ²κΉ μ 보λ€μ μ 곡νκΈ° λλ¬Έμ Vite λ₯Ό μ¬μ©νκΈ°λ‘ νμ΅λλ€.
μλ¦Όμ΄λ μν λͺ©λ‘λ€μ μΌμ λ²μ μμλ€ μμ±νκ³ , μ΄λ₯Ό μ€ν¬λ‘€ν΄μ λ³Ό μ μλλ‘ κ³ννκ³ κ°λ°μ μμνμ΅λλ€.
κ·Έλ¬λ μν λͺ©λ‘λ€μ΄ μΌμ λ²μ λ°μ λ²μ΄λμ νλ¨ λ€λΉκ²μ΄μ λ°λ₯Ό λ°μ΄λ΄κ±°λ, λ²μ λ°κΉ₯μΌλ‘ κ³μ μμ±λκ³ , μ€ν¬λ‘€ λ°λ κ³ν μΈμ λΆλͺ¨ 컨ν μ΄λμ μ μ©λμ΄ λͺ©λ‘ μΈ μ»¨ν μ΄λλ€λ κ°μ΄ μ€ν¬λ‘€λλ μ¦μμ΄ λ°μνμ΅λλ€.
width λ heightμ min, maxλ±μ μ§μ νμ§ μμΌλ©΄ λν΄νΈ μ€μ μΈ autoκ° λκ³ ,
λλΆλΆμ κ²½μ°, width, height λ₯Ό λ€μκ³Ό κ°μ 곡μμΌλ‘ κ³μ°ν©λλ€.
'width' + 'μ’μ° margin' + 'μ’μ° border' + 'μ’μ° padding' = blockμ μ 체 widthμ€ν¬λ‘€ λμμΈ μμ 컨ν
μ΄λλ€λΆν° μ΅μλ¨κΉμ§, μ΄λ νλλΌλ auto κ°μΌλ‘ μ€μ λμ΄μλ€λ©΄
λ³ΈμΈμ ν¬κΈ°λ₯Ό μμ 컨ν
μ΄λμ ν¬κΈ°λ₯Ό ꡬν λ€μ κ·Έ κ°μ λ§μΆκΈ° λλ¬Έμ μλμΉ μμ λΆλͺ¨ 컨ν
μ΄λμ μ€ν¬λ‘€μ΄ μ μ©λκ±°λ, λ€λ₯Έ 컨ν
μΈ λ€μ΄ νλ©΄ λ°μΌλ‘ λ°λ €λ μ μμ΅λλ€.
λ°λΌμ μμ 컨ν
μ΄λλΆν° μ΅μλ¨ λΆλͺ¨ 컨ν
μ΄λκΉμ§, auto μ€μ μ΄ λμ§ μλλ‘ min-h-0 κ°μ μ΅μ
λ€μ μμ±ν΄μΌ μλν λλ‘ μΌμ λ²μμμ μμ 컨ν
μ΄λλ€μ΄ μκ³ , μ€ν¬λ‘€ν΄μ λͺ¨λ μμ 컨ν
μ΄λλ₯Ό λ³Ό μ μλλ‘ ν μ μμ΅λλ€.
μκ°μ§λ λͺ»ν CSS λ¬Έμ μκΈ°μ κ½€ μ€λ μκ°μ΄ μμλμ΅λλ€. auto λ μμ 컨ν
μ΄λμ κ°μ λ¨Όμ ꡬνκ³ , κ·Έ κ°μ λ§μΆ°μ λΆλͺ¨μ κ°μ ꡬνλ€λκ²μ λͺ
μ¬ν΄μΌκ² λ€κ³ μκ°νμ΅λλ€.
μ΄μ μ μμ±λ useInfinityQueryλ₯Ό λ³λλ‘ ν
νλ¦Ών μμΌμ, useInfinityQuery λ₯Ό μ¬μμ±ν νμ μμ΄, μ ν΄μ§ ν
νλ¦Ώλλ‘ μ
λ ₯νλ©΄ λμνλλ‘ κ΅¬ννκ³ μμμ΅λλ€.
리ν΄κ°μ νμ μΆλ‘ μ μ€ν¨νμ¬ κ³μ νμ μ€ν¬λ¦½νΈ μ€λ₯κ° λ°μνμμ΅λλ€.
μ΄μ μ μμ±λ μ½λμμ κ³ μ λ μ΅μ
κ°μ μΆκ°λ‘ μ
λ ₯λ°μμ μλλ‘ ...options λ₯Ό μΆκ°νμλλ°, μ΄λ κ² μ΅μ
κ°μ΄ κ³ μ μ΄ μλ λ³μκ° λλ©΄ 리ν΄κ°μ νμ
μΆλ‘ νλλ° μ€ν¨νλκ²μΌλ‘ 보μ
λλ€. λ°λΌμ μ΄μ μλ μλμΌλ‘ InfiniteData<T, number | null>λ‘ λ³νν΄μ λ³ λ¬Έμ μμ΄ μ€νλ λ¦¬ν΄ νμ
T λ₯Ό InfiniteData<T, number | null>λ‘ μ μΈνμ¬ μ¬λ°λ₯Έ 리ν΄κ° νμ
μ μΆλ‘ νλλ‘ μμ νμμ΅λλ€.
μ΅μ κ°μ΄ κ³ μ μ΄μμλ μλμΌλ‘ νμ μ λ³ννμ¬ λ¦¬ν΄νκΈΈλ μλμΌλ‘ νμ μ λ³νν΄μ£Όλ κΈ°λ₯μ΄ λΌμ΄λΈλ¬λ¦¬μ μλ€κ³ μκ°νμ¬ μ€λμκ° λ€λ₯Έ λ°©ν₯μμ λ¬Έμ μ μμΈμ μ°Ύμμ΅λλ€. λ¬Έμ μ μμΈμ μΆλ‘ ν λ μ’ λ μ€ν λ§μΈλλ‘ κ°μ€μ μΈμΈ νμκ° μλ€κ³ μκ°νμ΅λλ€.
μμ λ‘κ·ΈμΈ κΈ°λ₯μ ꡬννλ©΄μ κ°μ₯ κ³ λ―Όνλ λΆλΆμ μΉ΄μΉ΄μ€, λ€μ΄λ², ꡬκΈμ²λΌ μλ‘ λ€λ₯Έ νλ«νΌμ μΈμ¦ λ°©μκ³Ό μλ΅ ν¬λ§·μ μ΄λ»κ² μΌκ΄λκ² μ²λ¦¬ν κ²μΈκ°μμ΅λλ€.
μ²μμλ μΈμ¦ λ‘μ§μ νλμ μλΉμ€(AuthService) μμ λͺ¨λ μμ±νμ΅λλ€. νλ«νΌμ λ°λΌ if λ¬ΈμΌλ‘ μΈμ¦ νλ¦μ λΆκΈ°νλλ°, μ΄ λ°©μμ λΉμ₯μ λμνμ§λ§ μ μ κ΅¬μ‘°κ° λ¬΄κ±°μμ‘μ΅λλ€.
κ° νλ«νΌλ§λ€ μΈκ° μ½λ μμ², ν ν° λ°κΈ, μ¬μ©μ μ 보 μ‘°ν νλ¦μ μ μ¬νμ§λ§, μΈλΆ νλΌλ―Έν°λ API μλν¬μΈνΈ, μλ΅ ν¬λ§·μ΄ λ¬λΌ λΉμ·ν λ‘μ§μ΄ λ°λ³΅λμκ³ , κ·Έλ‘ μΈν΄ νλμ νμΌ λ΄ μ½λλμ΄ λ§μμ§λ©΄μ κ°λ μ±μ΄ μ μ λ¨μ΄μ§λ λ¬Έμ κ° λ°μνμ΅λλ€.
λν μλ‘μ΄ μμ λ‘κ·ΈμΈ λ°©μμ μΆκ°ν λλ§λ€ κΈ°μ‘΄ μ½λμ μμ λμΌ νκ³ , μ΄λ ν₯ν νμ₯μ±κ³Ό μμ μ± λͺ¨λμ μ’μ§ μλ€κ³ νλ¨νμ΅λλ€.
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μ λ΅ ν¨ν΄(Strategy Pattern) μ λμ νμ΅λλ€. ν΅μ¬ μμ΄λμ΄λ νλ«νΌλ³ μΈμ¦ λ‘μ§μ κ°κ°μ μ λ΅ ν΄λμ€λ‘ λΆλ¦¬νκ³ , μ΄λ€μ 곡ν΅λ μΈν°νμ΄μ€λ‘ λ¬Άμ΄ μΌκ΄λ λ°©μμΌλ‘ μ€νν μ μλ ꡬ쑰λ₯Ό λ§λλ κ²μ΄μμ΅λλ€.
λ¨Όμ , μΉ΄μΉ΄μ€, λ€μ΄λ², κ΅¬κΈ λ± κ° μμ λ‘κ·ΈμΈ νλ«νΌμ λν΄ λ³λμ μ λ΅ ν΄λμ€λ₯Ό λ§λ€μμ΅λλ€. κ° μ λ΅ ν΄λμ€λ ν΄λΉ νλ«νΌμ νΉνλ μΈκ° μ½λ μ²λ¦¬, ν ν° λ°κΈ, μ¬μ©μ μ 보 μ‘°ν λ‘μ§λ§μ μ± μμ§λ©°, λͺ¨λ 곡ν΅λ λ©μλ ꡬ쑰λ₯Ό λ°λ¦ λλ€.
κ·Έλ€μ, μ λ΅ κ°μ²΄λ₯Ό μ ννκ³ μ€ννλ ν©ν 리 ν΄λμ€λ₯Ό ꡬμ±νμ¬, μμ λ‘κ·ΈμΈ μμ²μ΄ λ€μ΄μ¬ λ μ΄λ€ νλ«νΌμΈμ§μ λ°λΌ μ μ ν μ λ΅μ μ°Ύμ μ€ννλλ‘ νμ΅λλ€. μ¦, μΈμ¦ νλ¦μ μ§μ μ μμλ βμ΄λ€ μ λ΅μ μ¬μ©ν μ§β κ²°μ λ§ νκ³ , μ€μ μΈμ¦ λ‘μ§μ μ λ΅ ν΄λμ€μ μν μ μμνλ κ΅¬μ‘°λ‘ λ°λ κ²μ λλ€.
μ΄λ¬ν ꡬ쑰 λλΆμ, λλ©μΈ μλΉμ€ κ³μΈ΅(AuthService)μμλ μΉ΄μΉ΄μ€λ λ€μ΄λ²λ ꡬκΈμ΄λ μκ΄μμ΄, λ¨μν getAccessToken, getUserInfo κ°μ κ³΅ν΅ λ©μλλ₯Ό νΈμΆνκΈ°λ§ νλ©΄ λ©λλ€.
νλ«νΌμ μΈλΆ ꡬνμ λͺ°λΌλ λμΌν λ°©μμΌλ‘ λ‘μ§μ μ²λ¦¬ν μ μκ² λμκ³ , λ‘μ§μ μΆμν μμ€μ΄ λμμ Έ κ°λ
μ±κ³Ό μ μ§λ³΄μμ±μ΄ λν ν₯μλμμ΅λλ€.
μ λ΅ ν¨ν΄μ λμ ν λ€λ‘ λ€μκ³Ό κ°μ μ₯μ μ΄ μμμ΅λλ€
- μΈμ¦ λ‘μ§μ΄ κ° μ λ΅ ν΄λμ€μ λͺ ννκ² λΆλ¦¬λμ΄ μμ΄, μ½λλ₯Ό μ΄ν΄νκ³ μ μ§λ³΄μνκΈ° ν¨μ¬ μ¬μμ‘μ΅λλ€.
- μλ‘μ΄ μμ λ‘κ·ΈμΈ νλ«νΌμ μΆκ°ν λλ, κΈ°μ‘΄ λ‘μ§μ μμ νμ§ μκ³ μ λ΅ ν΄λμ€λ₯Ό μλ‘ μΆκ°νκ³ λ±λ‘λ§ νλ©΄ λλ―λ‘ νμ₯μ±μ΄ λ°μ΄λ¬μ΅λλ€.
- μΈμ¦ νλ¦μ΄ νμ€νλλ©΄μ ν μ€νΈ μμ±μ΄ μ¬μμ§κ³ , νλ«νΌλ³ λ¬Έμ λ₯Ό μ λ΅ λ¨μλ‘ λ 립μ μΌλ‘ λλ²κΉ ν μ μμμ΅λλ€.
- κ²°κ³Όμ μΌλ‘ OCP(κ°λ°©-νμ μμΉ) μ μΆ©μ€ν μ§ν€λ κ΅¬μ‘°κ° λμ΄, μ΄νμλ μμ μ μΌλ‘ κΈ°λ₯μ νμ₯ν΄ λκ° μ μλ κΈ°λ°μ λ§λ ¨ν μ μμμ΅λλ€.
μν©
- μ¬μ©μκ° μνλ μ€νΈλ¦¬λ¨Έλ₯Ό ꡬλ
νλ©΄, ν΄λΉ μ€νΈλ¦¬λ¨Έκ° μ€μκ° λ°©μ‘μ μμν λ μλμΌλ‘ λ
Ήνλ₯Ό μννλ μμ€ν
- ꡬλ β μ€μκ° μ€νΈλ¦¬λ¨Έκ° λΌμ΄λΈ μ€μΈμ§ μ£ΌκΈ°μ μΌλ‘ νμΈ β λ Ήν μ§ν
λ¬Έμ
- λ¨μΌ μλ² κ΅¬μ‘°μμλ λ€μκ³Ό κ°μ λ¬Έμ κ° λ°μκ°λ₯
- νμ₯μ± λΆμ‘±: μ€νΈλ¦¬λ¨Έκ° λ§μμ§μλ‘ κ° μ€νΈλ¦¬λ° νλ«νΌμ λν΄ μ£ΌκΈ°μ μΈ Live μν 체ν¬, λ Ήν μ²λ¦¬, νμ²λ¦¬ λ±μ΄ ν μλ²μ μ§μ€λμ΄ λ³λͺ©μ΄ λ°μ
- λΆμμ ν νλ‘μΈμ€ κ΄λ¦¬: λ Ήν μ€μΈ μ€νΈλ¦¬λ°μ μ€λ¨μ΄λ μ€λ₯ λ°μ μ μλ λ³΅κ΅¬κ° μ΄λ €μ
ν΄κ²°
- μμ€ν
μ μλμ κ°μ΄ μν λΆλ¦¬ λ° λΆμ° μ²λ¦¬ κ΅¬μ‘°λ‘ μ¬μ€κ³
- Main Server: μ μ ꡬλ κ΄λ¦¬, λ Ήν μμ²/κ²°κ³Ό νμΈ λ° μμ λ€μ΄λ‘λ, μλ¦Ό, λ§μ΄ νμ΄μ§
- Monitoring Server: κ° νλ«νΌμ μ€νΈλ¦¬λ¨Έ Live μνλ₯Ό μ€μκ° κ°μ§, κ°μ§ μ μ컀μκ² λ Ήν μμ² μ μ‘
- Recording Worker: κ° μ컀λ λ 립μ μΌλ‘ Streamlink κΈ°λ° λ Ήν μν, λ³λ ¬ λ Ήν κ°λ₯, λ Ήν κ²°κ³Όλ₯Ό S3μ μ λ‘λνκ³ DB κΈ°λ‘
νκ³
- μ΄ κ΅¬μ‘° λλΆμ μ€νΈλ¦¬λ¨Έ μκ° λμ΄λλ μμ μ μΌλ‘ λ Ήνκ° κ°λ₯ν΄μ§
- λ¨μΌ μλ² κ΅¬μ‘°μλ€λ©΄ λΆκ°λ₯νλ νμ₯μ±κ³Ό μμ μ±μ ν보ν μ μμκ³ , μ€μ μ΄μ μ€μΈ μμ€ν μμλ μ₯μ 격리, λ³λ ¬μ±, μ₯μ 볡ꡬμ μ΄μ μ΄ λͺ νν΄μ§
μν©
- λͺ¨λν°λ§ μλ²λ λΌμ΄λΈ λ°©μ‘μ κ°μ§νκ³ , μ컀λ λ Ήν νλ‘μΈμ€λ₯Ό μ€ννλ©°, μ΄ λμ TCP μ°κ²°μ ν΅ν΄ λ°μ΄ν°λ₯Ό μ§μ ν΅μ νκ³ ννΈλΉνΈ μ§ν
λ¬Έμ
- μ΄κΈ°μλ TCP κΈ°λ°μ μ§μ μ°κ²°λ‘ μ컀μ λͺ¨λν°λ§ μλ² κ°μ μν νμΈ λ° Job μ λ¬μ μννμ§λ§, μλΉμ€κ° νμ₯λλ©΄μ λ€μκ³Ό κ°μ λ¬Έμ κ° λ°μ
- μ°κ²° κ΄λ¦¬ λΆλ΄ μ¦κ°: μ컀 μκ° λ§μμ§μλ‘, TCP μ°κ²° μκ° κΈ°νκΈμμ μΌλ‘ λμ΄λ μ°κ²° μν μ μ§(keep-alive)μ μ¬μ°κ²°μ λν λΆλ΄μ΄ 컀μ§
- μν κ΄λ¦¬ μ± μμ λΆλͺ νμ±: μμ»€κ° μμλ‘ scale-out/in λλ©΄μ λκ° μ΄λ€ μ컀μ μνλ₯Ό μΆμ νκ³ μ₯μ λ₯Ό κ°μ§ν μ§ μ± μ λΆλ¦¬κ° λͺ¨νΈν΄μ§
- μ μ§λ³΄μ λ° μ₯μ λμ μ΄λ €μ: TCP κΈ°λ°μ ping-pong ꡬ쑰λ μ¬μ°κ²° μ μν 볡ꡬλ job 볡μ λ°©μ§κ° μ΄λ ΅κ³ , λͺ¨λν°λ§ μλ²κ° λ¨μΌ μ₯μ μ (SPOF)μ΄ λ μ μμ
ν΄κ²°
- TCP κΈ°λ° μν κ΄λ¦¬λ₯Ό Redis κΈ°λ° λ©μμ§/μν μμ€ν
μΌλ‘ μμ ν μ΄κ΄νκ³ , λͺ¨λ Job μ λ¬, ννΈλΉνΈ, μν μΆμ μ Redis ν€ μ€μ¬μΌλ‘ μ€κ³
| ν€ μ΄λ¦ | νμ | μν | TTL |
|---|---|---|---|
job:waiting:queue |
List | λͺ¨λν°λ§ μλ²κ° μ컀μκ² μ λ¬ν μμ λκΈ° ν | μμ |
job:fail:queue |
List | μ€ν¨ν μμ μ¬μλ ν | μμ |
recording:worker:<WORKER_ID> |
Set | ν΄λΉ μμ»€κ° μ²λ¦¬ μ€μΈ μΈμ ID 리μ€νΈ | μμ |
job:meta |
Hash | μΈμ ID β μμ μ 보 | μμ |
job:done:queue |
List | μλ£λ μμ ν | μμ |
heartbeat:worker:<WORKER_ID> |
String (TTL) | μ컀 μμ‘΄ νμΈμ© ν€ | 3μ΄ |
νκ³
- Redis κΈ°λ°μΌλ‘ μ νν μ΄ν μμ€ν μ νμ₯μ±, μμ μ±, 볡ꡬ κ°λ₯μ± μΈ‘λ©΄μμ ν¬κ² ν₯μ
- TCP μ°κ²° κΈ°λ° λ°©μμ μκ·λͺ¨ μμ€ν μλ μ ν©νμ§λ§, μν νμ₯μ±κ³Ό μ₯μ 볡μλ ₯μ΄ μꡬλλ νκ²½μμλ ꡬ쑰μ νκ³κ° λλ¬λ¨
- Redis ν€ μ€κ³λ₯Ό μΈλΆννκ³ μν μ λͺ νν λλλ©΄μ, μ₯μ λ°μ μμλ λͺ νν κΈ°μ€μ λ°λΌ μ컀 μνλ₯Ό νλ¨νκ³ μ¬μ²λ¦¬ν μ μκ² λμμ
μν©
- μ컀λ Streamlinkλ₯Ό ν΅ν΄
.tsν¬λ§·μΌλ‘ μμμ μ μ₯νλ©°, λ°©μ‘μ΄ μ’ λ£λ λκΉμ§ λ Ήνλ₯Ό μ§μνλλ‘ μ€κ³λμ΄ μμ
λ¬Έμ
- μ₯μκ° λ°©μ‘ λ
Ήν μκ° μ ν μμ
- λΌμ΄λΈκ° μ μκ° μ΄μ μ§μλλ©΄ μμ»€κ° κ³μ λ Ήννμ¬ μμ μ μ κ° κΈΈμ΄μ§κ³ , κ³Όλν νμΌ ν¬κΈ°κ° λ°μ
- μ€νΈλ¦¬λ¨Έκ° μ€μλ‘ λ°©μ‘μ λμ§ μμΌλ©΄ μμΌκ° λ Ήνκ° μ΄μ΄μ§ μ μλ ꡬ쑰
- 1μκ°λΉ μ½ 1GBμ λ¬νλ
.tsνμΌμ S3 μ μ₯ λΉμ© λ° λ€νΈμν¬ λμνμ λΆλ΄μ μ€
ν΄κ²°
- λ
Ήν νμμμ μ ν λμ
- λ Ήν λ‘μ§μ 6μκ° μ ν λ‘μ§μ μΆκ°ν΄, μ₯μκ° λ°©μ‘ λ Ήνλ₯Ό μλμΌλ‘ μ’ λ£νλλ‘ κ°μ
- .mp4 λ³ν λ° μ©λ μμΆ μΆκ°
- λ
Ήν μλ£ ν
ffmpegλ₯Ό νμ©ν΄.tsβ.mp4μ¬μΈμ½λ© κ³Όμ μΆκ° - μ΅λ μ©λ 50% μ κ°
- λ
Ήν μλ£ ν
νκ³
- λ°μ΄ν° μ μ‘ λ° μ μ₯ λΉμ©μ μ€μ΄κΈ° μν΄ mp4 μμΆ κ³Όμ μ λμ
ν κ²μ μ€μ§μ μΈ λΉμ© μ κ°
- λ€λ§, CPU μμμ λ§μ΄ μλͺ¨νλ μΈμ½λ© μμ μ μμ»€κ° μ§μ μνν κ²½μ°, λ Ήν μ±λ₯ μ νλ μ§μ°μ΄ λ°μν μ μμ΄ λ³λ μλ²λ‘ λΆλ¦¬νλ ꡬ쑰μ νμμ± λλ
- νμμμ κΈ°λ° λ Ήν μ’ λ£λ₯Ό ν΅ν΄ μμ€ν μμ μ±μ λμ΄κ³ , μ₯μ λ μ¬μ©μ μ€μλ‘ μΈν μ₯κΈ° 리μμ€ μ μ λ₯Ό ν¨κ³Όμ μΌλ‘ λ°©μ§
| Name | GitHub | |
|---|---|---|
| λ°κ²½ν | [email protected] | https://github.com/smileboy0014 |
| μ΄μΉλ―Ό | [email protected] | https://github.com/leesm0218 |
| μ΄νμ | [email protected] | https://github.com/soo96 |
λ°κ²½ν
μκ°μκ°μ κΈΈκ² λκ»΄μ‘μ§λ§, μ§λκ³ λ³΄λ ν λ¬μ μ°Έ μ§§μ μκ°μ΄μμ΅λλ€. μΉμ΄νκ² κ³ λ―Όνκ³ ν λ‘ νλ©° κ²°κ³Όλ¬Όμ λ§λ€μ΄κ°λ κ³Όμ μ κ²°μ½ μ½μ§ μμμ§λ§, μΈν μ΄μμ μμνμ΄ μμλ κ°μ§ μκ°μ΄μλ€κ³ μκ°ν©λλ€. νλ‘μ νΈ μμ΄λμ΄ μ μ λΆν° Git μ λ΅, μ»€λ° λ° μ΄μ ν νλ¦Ώ, μ½λ 컨벀μ , κΈ°μ μ€νκΉμ§β 무μ νλ μ΄μ μμ΄ μ ν κ²μ μμμ΅λλ€. μ΄ κ²½νμ λ°νμΌλ‘, μμΌλ‘ μ΄λ€ νκ²½μμ λꡬμ μμ νλλΌλ κ·Έλμ κ³ λ―Όκ³Ό μ νμ κΈ°μ΅νλ©° μ΅μ μ κ²°κ³Όλ₯Ό λΌ μ μμ κ²μ΄λΌ λ―Ώμ΅λλ€.μ’μλ μ : μ€κ³λΆν° λ°°ν¬κΉμ§ μλΉμ€ κ°λ°μ μ 체 μ¬μ΄ν΄μ μ§μ κ²½νν΄λ³Ό μ μμλ μ μ΄ κ°μ₯ μ’μμ΅λλ€.
λ¨μν κΈ°μ μ μ ννλ λ° κ·ΈμΉμ§ μκ³ , ν©λΉν μ΄μ λ₯Ό λ°νμΌλ‘ ν©λ¦¬μ μΈ κ²°μ μ λ΄λ¦¬λ μ¬κ³ λ°©μμ λ°°μΈ μ μμλ κ²λ ν° μνμ΄μμ΅λλ€.
λν, μ½λ 리뷰λ₯Ό ν΅ν΄ μλ‘μ μκ°μ 곡μ νκ³ ν λ‘ νλ κ³Όμ μ ν΅ν΄ ν κ°λ°μ μ§μ ν μλ―Έλ₯Ό 체κ°ν μ μμλ μκ°μ΄μμ΅λλ€.
μμ¬μ λ μ : ν λ¬μ΄λΌλ μ§§μ κΈ°κ° μμ νλ‘μ νΈ κΈ°νλΆν° λ°°ν¬κΉμ§ λͺ¨λ κ³Όμ μ μννλ κ²μ μ½μ§ μμμ΅λλ€.
νΉν μ견 μΆ©λμ΄ μμμ λ, μ‘°κΈ λ μ°μνκ² μ‘°μ¨νκ³ μ€λνλ€λ©΄ λΆνμν μκ° μλͺ¨λ₯Ό μ€μΌ μ μμμ κ²μ΄λΌλ μμ¬μμ΄ λ¨μ΅λλ€.
μμΌλ‘λ μ견 μ°¨μ΄κ° μκΈ°λ©΄ λͺ
νν κ·Όκ±°μ μλ£λ₯Ό ν¨κ» μ€λΉν΄ λννλ λ°©μμ ν΅ν΄ λμ± μμ°μ μΈ λ
Όμλ₯Ό μ΄λμ΄λ³΄κ³ μΆμ΅λλ€.
보μν μ : νΌλλ°± μκ°μ λ°μ μ견λ€μ λ°μν΄, μλ₯Ό λ€μ΄ κ²μ κΈ°λ₯ κ°μ μ΄λ λ Ήν μ€ μ€νΈλ¦¬λ¨Έμ ꡬλ μκ° μ무λ μμ κ²½μ° μλμΌλ‘ λ Ήνλ₯Ό μ’ λ£νλ κΈ°λ₯ λ±μ 보μνλ©΄ μλΉμ€ μμ±λλ₯Ό νμΈ΅ λ λμΌ μ μμ κ²μ΄λΌ μκ°ν©λλ€.
μ΄μΉλ―Ό
μμ΄λμ΄ λ°κ΅΄ κΈ°κ°μ΄ ν¬ν¨λ κ°λ°κΈ°κ°μ μ λ§ μ§§λ€λκ²μ λκΌμ΅λλ€. NodeJsλ‘ κ°λ¨ν νλ‘κ·Έλλ°λ§ νμκΈ°μ λ°±μλμ λ μ΄μ΄λ μν€ν μ³μ λͺ¨λνμ ν΄λ¦° μν€ν μ³μ μ΅μνμ§ μμμ λλμ± μ§§μ μκ°μ΄μλκ² κ°μ΅λλ€. μ΄λ¬ν κ²½νμ΄ μ’ λ λμ μ€λ ₯μ λ°λ°νμ΄ λλλ‘ λμ± λ Έλ ₯νκ² μ΅λλ€.μ’μλμ : νμλΆλ€μ μ½λ λ
Ένμ°μ μκ°μ 리뷰λ₯Ό ν΅ν΄ λ³Ό μ μμμ΅λλ€.
μκ²¬μ΄ μκ°λ¦¬λλΌλ μλ‘ λλ¦μ κ·Όκ±°λ₯Ό μ μνλ©΄μ ν λ‘ νλκ²λ μ’μμ΅λλ€.
μμ¬μ λμ : μμλ³΄λ€ κ°λ° μλκ° λλμ Έμ λ€λ₯Έ νμλΆλ€κ³Ό κ²°κ³Όλ¬Όμ κ°μ λ°©ν₯μ λκ³ μλ‘ μ΄μΌκΈ°λ₯Ό ν΄λ³΄κ³ μΆμλλ° κ·Έλ¬μ§ λͺ»ν΄ μμ¬μ μ΅λλ€.
보μν μ : 미리 κ³νν κ°λ°κ³νκ³Ό μ€κ³λ λ§μ κ°λ°μ΄ μμλλ λ°λΌκ°κΈ°μ κΈκΈνκ³ , μ€λ₯μ λν μ 보λ₯Ό μ°ΎκΈ° νλ€μ΄ μμλ³΄λ€ κΈ°κ°μ΄ λ§μ΄ μμλμμ΅λλ€. μμΌλ‘ μ€κ³ν λ μ°Έκ³ νμ¬ κ³νμ μ립νκ±°λ, μ΄λ¬ν μν©μ λμ²νλ λ Ένμ°κ° μλμ§ μμλ΄μΌ λκ² μ΅λλ€.
μ΄νμ
μ΄λ² νλ‘μ νΈλ₯Ό ν΅ν΄ μ€κ³λΆν° κ°λ°, λ°°ν¬κΉμ§μ μ κ³Όμ μ νμλ€κ³Ό ν¨κ» κ²½νν μ μμμ΅λλ€. κΈ°ν λ¨κ³λΆν° μ΄λ€ κ΅¬μ‘°λ‘ μ ν리μΌμ΄μ μ μ€κ³ν μ§ κ³ λ―Όνκ³ , μ΄λ₯Ό μ€μ μ½λλ‘ κ΅¬ννλ©°, λ§μ§λ§μλ λ°°ν¬κΉμ§ μ± μμ§λ κ³Όμ μ ν λ¨μλ‘ μννλ€λ μ μμ μ€λ¬΄μ κ°κΉμ΄ κ²½νμ μμ μ μμμ΅λλ€.μ’μλ μ : κΈ°λ₯μ νλνλ κ°λ°ν΄λκ°λ κ³Όμ μμ λͺ¨λ μμ¬κ²°μ μ νμλ€κ³Ό ν¨κ» λ
Όμνκ³ ν©μν΄ λκ°λ€λ μ μ΄ μ’μμ΅λλ€.
μ΄λ€ λ°©ν₯μ΄ λ λμ μ νμΌμ§ λμμμ΄ λννλ©° κ²°μ νκ³ , μμμΉ λͺ»ν λ¬Έμ κ° λ°μνμ λλ κ°μ ν΄κ²°μ±
μ μ μνκ³ ν¨κ» κ³ λ―Όνλ©° νμ΄κ°λ νμν¬κ° νλ‘μ νΈμ ν° μλλ ₯μ΄ λμμ΅λλ€.
μμ¬μ λ μ : μ΄κΈ°μ μμ
λ‘κ·ΈμΈ κΈ°λ₯μ μΉ΄μΉ΄μ€, λ€μ΄λ², κ΅¬κΈ μΈ κ°μ§ λͺ¨λ ꡬννλ €λ€ λ³΄λ, μμλ³΄λ€ λ§μ 리μμ€κ° μ΄λ°μ μ§μ€λμμ΅λλ€.
κ° νλ«νΌλ§λ€ μΈμ¦ λ°©μμ΄ λ¬λΌ ꡬν λμ΄λμ ν
μ€νΈ λΆλ΄μ΄ μ»Έκ³ , μ΄λ‘ μΈν΄ ν΅μ¬ κΈ°λ₯ κ°λ°μ΄ μ§μ°λλ κ²°κ³Όλ‘ μ΄μ΄μ‘μ΅λλ€.
λμ΄μΌλ³΄λ©΄ μ²μλΆν° λͺ¨λ νλ«νΌμ ꡬνν기보λ€λ ν κ°μ§(μ: μΉ΄μΉ΄μ€)λ§ μ°μ λμ
νκ³ , μ£Όμ κΈ°λ₯ κ°λ°μ μ§μ€νμΌλ©΄ νλ‘μ νΈμ μ λ°μ μΈ μμ±λμ μΌμ μΈ‘λ©΄μμ λ λμ κ²°κ³Όλ₯Ό μ»μ μ μμμ κ²μ΄λΌ μμ¬μμ΄ λ¨μ΅λλ€.
보μν μ : μ΄λ² κ²½νμ ν΅ν΄ κΈ°λ₯λ³ μ€μλμ λμ΄λ, μ¬μ©μ μν₯λλ₯Ό κ³ λ €ν μμ μ°μ μμ μ€μ μ νμμ±μ λκΌμ΅λλ€. μμΌλ‘λ μ΄κΈ° μ€κ³ λ¨κ³μμ μ 체 λ‘λλ§΅μ μ μ°νκ² μ€κ³νκ³ , κΌ νμν κΈ°λ₯λΆν° μ°μ ꡬννμ¬ μ μ§μ μΌλ‘ νμ₯ν΄λκ°λ μ λ΅μ μ μ©νλ € ν©λλ€. μ΄λ₯Ό ν΅ν΄ νμ λ μκ°κ³Ό μμμ λ³΄λ€ ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μλλ‘ κ°μ ν΄λκ° κ³νμ λλ€.




