Fan-Out On Write
Fan-Out on Write: μ°κΈ° μμ μ ν¬μμ
"Fan-Out on Write"λ Fan-Out ꡬ쑰λ₯Ό ꡬ체μ μΌλ‘ μ°κΈ° μμ μ μ μ©ν λ°©μμ
λλ€.
μ΄λ Fan-Out ν¨ν΄μ νμ₯ λλ νΉμνλ ꡬνμΌλ‘ λ³Ό μ μμΌλ©°, λ°μ΄ν°κ° μμ±λλ μμ (μ°κΈ° μμ )μ 미리 μ¬λ¬ λμμ λ°μ΄ν°λ₯Ό λΆλ°°νλ κ²μ μλ―Έν©λλ€.
λνμ μΈ μλ‘ μμ λ―Έλμ΄λ₯Ό λ€ μ μμ΅λλ€. μ¬μ©μκ° κΈμ μμ±νλ©΄(Write), κ·Έ κΈμ΄ μ¦μ λͺ¨λ νλ‘μμ νμλΌμΈ(νΌλ)μ 볡μ λμ΄ μ μ₯λ©λλ€. μ¦, κΈμ μΈ λλ§λ€ νλ‘μ μλ§νΌ "fan-out"μ΄ λ°μνλ κ²μ λλ€.
(μ°Έκ³ λ‘ μ΄μ λ°λλλ λ°©μμΈ "Fan-Out on Read"λ μ½κΈ° μμ μ μ¬λ¬ κ³³μμ λ°μ΄ν°λ₯Ό μ’ ν©ν΄ 보μ¬μ£Όλ λ°©μμ λλ€.)
νΈμν°μμ μ μ©λλ λ°©μ
νΈμν°μμ ν μ¬μ©μκ° μ νΈμμ μμ±νλ©΄, λ€μκ³Ό κ°μ κ³Όμ μ΄ μΌμ΄λ©λλ€.
νΈμ μ μ₯: μμ±λ νΈμμ DBμ μ μ₯λ©λλ€.
νλ‘μ λͺ©λ‘ μ‘°ν: ν΄λΉ νΈμ μμ±μλ₯Ό νλ‘μ°νλ λͺ¨λ μ¬μ©μμ λͺ©λ‘μ μ‘°νν©λλ€.
νμλΌμΈ μ λ°μ΄νΈ: μ‘°νλ νλ‘μλ€μ "νμλΌμΈ" DBμ ν΄λΉ νΈμμ μΆκ°(μ°κΈ°)ν©λλ€.
νΉμ μ¬μ©μκ° νΌλλ₯Ό μμ±νλ©΄ ν΄λΉ μ¬μ©μλ₯Ό νλ‘μ°νλ νλ‘μλ€μ νμλΌμΈμ νΌλκ° λ³΅μ λμ΄ μ μ₯λ©λλ€.
μ¦, μ¬μ©μκ° νΌλλ₯Ό μμ±ν λλ§λ€ νλ‘μ μλ§νΌ μ°κΈ°(fan-out)μ΄ λ°μνκ² λ©λλ€.
μ νλ‘μ μλ§νΌ μ°κΈ°κ° λ°μνλκ°?
κ²°λ‘ λΆν° λ§μλ리면, νΈμν° κ°μ SNSμμ νλ‘μλ€μ΄ μ΅μ νΈμμ μ¦κ°μ μΌλ‘ μμ μ νμλΌμΈμμ λ³΄λ €λ©΄,
λ¨μν "μ½κΈ°"λ§μΌλ‘λ νμ¬μ κ°μ μ¬μ©μ κ²½νμ μ 곡νκΈ° μ΄λ ΅κΈ° λλ¬Έμ μΆκ°μ μΈ μ°κΈ° μμ
μ΄ νμν©λλ€.
π€ μ "μ½κΈ°"λ§μΌλ‘λ λΆμ‘±ν κΉ? (Fan-Out on Read λ°©μμ λ¬Έμ )
λ§μ½ 'μ°κΈ°' μμ μμ΄ 'μ½κΈ°'λ‘λ§ νμλΌμΈμ ꡬννλ€λ©΄, λ€μ μν©μ κ°μ ν΄ λ³Ό μ μμ΅λλ€.
μ΄ λ°©μμ λ¨μν΄ λ³΄μ΄μ§λ§, νΈμν°μ κ°μ κ±°λ κ·λͺ¨ μλΉμ€μμλ λ€μκ³Ό κ°μ μ¬κ°ν λ¬Έμ κ° λ°μν μ μμ΅λλ€.
μ±λ₯ λ¬Έμ :
μ¬μ©μκ° νμλΌμΈμ μ΄ λλ§λ€ νλ‘μ°νλ μλ°±, μμ² λͺ μ νΈμμ μ€μκ°μΌλ‘ κ²μ, μ‘°ν, μ λ ¬ν΄μΌ ν©λλ€.
λ§μ½ νλ‘μ μ€ μΈκΈ° κ³μ (μ: μλ°±λ§ κ°μ νΈμμ μμ±)μ΄ μλ€λ©΄, ν΄λΉ μ¬μ©μμ νΈμμ κ°μ Έμ€λ λ°λ§λ λ§μ μκ°μ΄ μμλ μ μμ΅λλ€.
μμ΅ λͺ μ μ¬μ©μκ° λμμ νμλΌμΈμ μ΄λ €κ³ νλ€λ©΄, DBλ μμ²λ 쿼리 λΆνλ‘ λ§λΉλκ±°λ μ¬μ©μλ€μ νΈμμ 보λ λ° λͺ λΆμ© κΈ°λ€λ €μΌ ν μλ μμ΅λλ€.
볡μ‘ν 쿼리:
μΌλ°μ μΈ RDBμμ μ¬λ¬ μ¬μ©μμ νΈμμ μ‘°μΈ(join)νκ³ μ λ ¬νλ 쿼리λ λ§€μ° λ³΅μ‘νκ³ λ¦¬μμ€λ₯Ό λ§μ΄ μλͺ¨ν©λλ€.
νμ₯μ± λ¬Έμ :
μ¬μ©μ μμ νΈμ μκ° κΈ°νκΈμμ μΌλ‘ λμ΄λ μλ‘ μμ€ν μ νμ₯νκΈ° μ΄λ ΅μ΅λλ€.
μ°κΈ°κ° νμν μ΄μ (Fan-out on Writeμ λ³Έμ§)
"Fan-Out on Write" λ°©μμ μ¬μ©νλ μ΄μ λ, μ¬μ©μκ° νμλΌμΈμ μ½μ λμ μλλ₯Ό κ·ΉλννκΈ° μν΄μμ
λλ€.
μ¦, μ½κΈ° μμ μ κ°λ¨νκ³ λΉ λ₯΄κ² λ§λ€κΈ° μν΄ μ°κΈ° μμ μ 미리 λͺ¨λ μ€λΉ μμ μ ν΄λλ κ²μ λλ€.
λΉμ λ₯Ό λ€μ΄λ³΄κ² μ΅λλ€.
μ½κΈ° λ°©μ (Fan-out on Read)
μΉκ΅¬μκ² μ νλ₯Ό κ±Έ λλ§λ€, κ·Έ μΉκ΅¬κ° λ€λ₯Έ λͺ¨λ μΉκ΅¬μκ² μΌμΌμ΄ μ νν΄μ μ 보λ₯Ό λ¬Όμ΄λ³Έ λ€μ, κ·Έ μ 보λ₯Ό μ’ ν©ν΄μ λμκ² λ§ν΄μ£Όλ κ²κ³Ό κ°μ΅λλ€. (λ§€λ² μ€μκ°μΌλ‘ μ 보λ₯Ό μμ§νλ λ°©μ)
μ°κΈ° λ°©μ (Fan-out on Write)
μΉκ΅¬λ€μ΄ μ€μν μΌμ΄ μκΈΈ λλ§λ€ λμ κ°μΈ λΉμμκ² κ·Έ λ΄μ©μ 미리 μ λ¬ν΄ λκ³ , λ΄κ° κΆκΈν λλ§λ€ λΉμκ° μ΄λ―Έ μ 리λ λ³΄κ³ μλ₯Ό μ¦μ 건λ€μ£Όλ κ²κ³Ό κ°μ΅λλ€. (μ 보λ₯Ό 미리 κ°μΈνλ 곡κ°μ νΈμν΄λλ λ°©μ)
μ¬κΈ°μ 'κ°μΈ λΉμ' μν μ΄ κ° νλ‘μμ 'κ°μΈ νμλΌμΈ μ μ₯μ'μ΄λ©°, μ¬κΈ°μ νΈμμ 미리 μ λ¬ν΄λλ νμκ° λ°λ‘ νλ‘μ μλ§νΌ λ°μνλ μ°κΈ° μμ μ λλ€.
μ΄λ κ² κ΅¬μ±νλ©΄, μ¬μ©μκ° νμλΌμΈμ μ΄ λ λ¨μν μμ μ κ°μΈ νμλΌμΈ μ μ₯μμμ λ°μ΄ν°λ₯Ό κ°μ Έμ€κΈ°λ§ νλ©΄ λλ―λ‘, λ§€μ° λΉ λ₯΄κ² μ 보λ₯Ό λ³Ό μ μμ΅λλ€.
κ²°λ‘ μ μΌλ‘, κ°λ³ μ μ₯μμ νΈμμ 미리 'μ°κΈ°' ν΄λλ κ²μ΄ ν¨μ¬ ν¨μ¨μ μ΄λΌκ³ νλ¨ν κ²μ
λλ€. μ΄λ μ½κΈ° μ±λ₯μ μν΄ μ°κΈ° λΆνλ₯Ό κ°μνλ μ λ΅μ
λλ€.
Fan-Out on Write μμ€ν
κ΅¬μ± μμ
1. νΈμ μμ± μλΉμ€ (Tweet Write Service)
μν : μ¬μ©μλ‘λΆν° νΈμ μμ± μμ²μ λ°μ μ²λ¦¬ν©λλ€.
κΈ°μ : μ ν리μΌμ΄μ μλ²λ‘ API μλν¬μΈνΈ(μ:
POST /tweets)λ₯Ό ꡬνν©λλ€.μλ λ°©μ:
μ ν리μΌμ΄μ μλ²κ° μ¬μ©μλ‘λΆν° νΈμ μμ± μμ²μ λ°μ΅λλ€.
νΈμ λ΄μ©μ DBμ μ μ₯ν©λλ€.
μ μ₯ μ±κ³΅ ν, νΈμ κ΄λ ¨ μ 보(νΈμ ID, μμ±μ ID λ±)λ₯Ό λ©μμ§ λΈλ‘컀μ νΉμ ν ν½(Topic)μΌλ‘ λ°ν(publish)ν©λλ€. (μ΄ κ³Όμ μ΄ Fan-out on Writeλ₯Ό μμνλ ν΅μ¬ νΈλ¦¬κ±°μ λλ€.)
μ¬μ©μμκ² νΈμ μμ± μ±κ³΅ μλ΅μ λ°νν©λλ€.
2. λ©μμ§ λΈλ‘컀 (Message Broker)
μν :
νΈμ μμ± μ΄λ²€νΈ(λ©μμ§)λ₯Ό μμ§νκ³ , μ΄λ₯Ό νμλ‘ νλ λ€λ₯Έ μλΉμ€(subscriber)μ μ λ¬ν©λλ€.
λΆμ° μμ€ν μμ μλΉμ€ κ°μ λΉλκΈ° ν΅μ μ λ΄λΉν©λλ€.
κΈ°μ : μνμΉ μΉ΄νμΉ΄(Apache Kafka), RabbitMQ λ±
μλ λ°©μ:
νΈμ μλΉμ€λ‘λΆν° λ°μ νΈμ μ΄λ²€νΈλ₯Ό Topic(λλ Queue)μ μ μ₯νκ³ , μ΄λ₯Ό ꡬλ νλ 컨μλ¨Έλ€μ΄ κ°μ Έκ° μ μλλ‘ λκΈ°μν΅λλ€.
3. νλ‘μ μλΉμ€ / νμλΌμΈ μμ± μλΉμ€ (Timeline Generation Service)
μν :
λ©μμ§ λΈλ‘컀λ‘λΆν° νΈμ μ΄λ²€νΈλ₯Ό ꡬλ (subscribe)ν©λλ€.
νΈμ μμ±μμ νλ‘μλ€μ μ°Ύμ κ° νλ‘μμ κ°μΈ νμλΌμΈμ μ λ°μ΄νΈν©λλ€. (μ΄ μλΉμ€κ° Fan-out on Writeμ ν΅μ¬μ μΈ "μ°κΈ°" λΆλΆμ λ΄λΉν©λλ€.)
κΈ°μ : μ ν리μΌμ΄μ μλ²(컨μλ¨Έ)μμ λ©μμ§ λΈλ‘컀μ μ΄λ²€νΈλ₯Ό μλΉ(consume)ν μ μκ² κ΅¬μ±ν©λλ€.
μλ λ°©μ:
λ©μμ§ λΈλ‘컀λ‘λΆν° μλ‘μ΄ νΈμ μ΄λ²€νΈ λ©μμ§λ₯Ό μμ ν©λλ€.
λ©μμ§μ ν¬ν¨λ μ¬μ©μ IDλ₯Ό νμ©νμ¬ 'νλ‘μ° DB'(μ: Redis, RDB λ±)μμ ν΄λΉ μμ±μλ₯Ό νλ‘μ°νλ λͺ¨λ μ¬μ©μμ λͺ©λ‘μ μ‘°νν©λλ€. (μ΄ DBλ νλ‘μ°/νλ‘μ κ΄κ³λ₯Ό ν¨μ¨μ μΌλ‘ μ‘°νν μ μλλ‘ μ΅μ νλμ΄ μμ΄μΌ ν©λλ€.)
μ‘°νλ κ° νλ‘μμ λν΄, νΈμ μ 보λ₯Ό νλ‘μμ 'κ°μΈ νμλΌμΈ DB'(μ£Όλ‘ NoSQL)μ μ μ₯(μ°κΈ°)ν©λλ€. (Redisμ Sorted Set, Cassandraμ Wide Column Store κ°μ κ΅¬μ‘°κ° μ΄ μ©λμ ν¨μ¨μ μ λλ€.)
μ΄ κ³Όμ μ νλ‘μ μκ° λ§μ κ²½μ°(μ: μλ°±λ§ λͺ ) λΆνκ° ν΄ μ μμΌλ―λ‘, λμμ± λ° λΆν κ΄λ¦¬κ° μ€μν©λλ€. λ³λ ¬ μ²λ¦¬ λλ λΉλκΈ° μ²λ¦¬(μ: Springμ
@Async, WebFlux)λ₯Ό μ κ·Ήμ μΌλ‘ νμ©ν΄μΌ ν©λλ€.
4. νμλΌμΈ μ‘°ν μλΉμ€ (Timeline Read Service)
μν : μ¬μ©μκ° μμ μ νμλΌμΈ μ‘°νλ₯Ό μμ²ν λ, 미리 λ§λ€μ΄μ§ κ°μΈ νμλΌμΈ λ°μ΄ν°λ₯Ό μ‘°ννμ¬ λ°νν©λλ€.
κΈ°μ : μ€νλ§ λΆνΈ μ ν리μΌμ΄μ μλ²μμ API μλν¬μΈνΈ(μ:
GET /timeline)λ₯Ό ꡬνν©λλ€.μλ λ°©μ:
μ ν리μΌμ΄μ μλ²κ° μ¬μ©μλ‘λΆν° νμλΌμΈ μ‘°ν μμ²μ λ°μ΅λλ€.
μ¬μ©μ IDλ₯Ό κΈ°λ°μΌλ‘ 'κ°μΈ νμλΌμΈ DB'(NoSQL)μμ ν΄λΉ μ¬μ©μμ 미리 ꡬμ±λ νΈμ λͺ©λ‘μ μ‘°νν©λλ€.
μ‘°νλ νΈμ λͺ©λ‘μ μ¬μ©μμκ² λ°νν©λλ€.
μ΄ μμ μλ 볡μ‘ν μ‘°μΈμ΄λ μ λ ¬ μμ΄ λ¨μν 'μ½κΈ°'λ§ λ°μνλ―λ‘ λ§€μ° λΉ λ₯Έ μλ΅ μλλ₯Ό 보μ₯ν μ μμ΅λλ€.
Last updated