Spring Boot λ‘λ© μκ° λ° λΉλ μκ° λ¨μΆνκΈ°
κ°μ
νλ‘μ νΈμ λͺ¨λ μμ μ½λλμ΄ μ¦κ°ν¨μ λ°λΌ λ‘컬μμ Spring Boot μ ν리μΌμ΄μ μ μμ ν ꡬλνλ λ° μμλλ μκ°μ΄ μ§μμ μΌλ‘ κΈΈμ΄μ‘λ€. μ΄λ‘ μΈν΄ λ‘컬μμ μ½λλ₯Ό μμ νκ³ λ€μ ꡬλνμ¬ ν μ€νΈνλ κ³Όμ μμ λΆνμν μκ°μ΄ λμ΄λ¬κ³ , λΉλ μκ°λ μ¦κ°νλ©΄μ CI μνμκ°μ΄ κΈΈμ΄μ Έ κ°λ° μμ°μ±μ΄ κ³μ μ νλμλ€. μ΄λ₯Ό κ°μ νκΈ° μν΄ μ ν리μΌμ΄μ λ‘λ© μκ°κ³Ό λΉλ μκ°μ λ¨μΆν μ μλ λ°©λ²μ μ°Ύμλ³΄κ³ μ μ©ν΄ 보μλ€.(Spring Boot v3.2.7, Gradle v8.5 μ¬μ© μ€)
1. λΆνμν μ»΄ν¬λνΈ μ€μΊ λ²μ μΆμ λ° μ§μ° μ΄κΈ°ν(lazy initialization) μ€μ
μ μ© μ΄ν μ ν리μΌμ΄μ λ‘λ© μκ° 47% λ¨μΆ
- Mac(M4 Pro): 53μ΄ → 22μ΄
- Windows(ASUS gu603): 90μ΄ → 48μ΄
2. Gradle λ³λ ¬ μ²λ¦¬(parallel execution) λ° λΉλ μΊμ(build cache) νμ©
μ μ© μ΄ν λΉλ μκ° 91% λ¨μΆ
- μ 체 λΉλ κΈ°μ€: 3λΆ 16μ΄ → 17μ΄
1. μ§μ° μ΄κΈ°ν(lazy initialization) μ€μ
Springμ κΈ°λ³Έμ μΌλ‘ μ ν리μΌμ΄μ ꡬλ μμ μ 컨ν μ€νΈμ λ±λ‘λ λͺ¨λ μ±κΈν€ λΉμ μ¦μ μμ±νκ³ μ΄κΈ°ννλ€. κ·Έλ¬λ μ€μ κ°λ° μμ μμλ λͺ¨λ λΉμ μ¬μ©νλ κ²½μ°λ μ¬λ§ν΄μ μ μλ€. λΉμ₯ λ΄κ° μν νλ‘μ νΈλ§ νλλΌλ μ¬λ¬ μ€μΏΌλκ° λμΌν λ ν¬μ§ν 리μμ λͺ¨λλ³λ‘ λλ μ¬μ©νλλ° λ€λ₯Έ μ€μΏΌλμ λͺ¨λ κ°μ κ²½μ°λ μ¬μ©νμ§ μκ³ , λ΄κ° μ¬μ©νλ λͺ¨λμμλ μ§κΈ κ°λ°νλ λ‘μ§ λ§κ³ λ μ¬μ©λμ§ μλ λΉλ€μ΄ λλ€μλ€.
μ΄λ¬ν μν©μμ spring.main.lazy-initialization=true μ€μ μ μ μ©νλ©΄, λͺ¨λ λΉμ μμ±μ ν λ²μ μ€μ μ¬μ© μμ κΉμ§ μ§μ°μν¬ μ μλ€.
μ¦μ μ΄κΈ°ν λ°©μκ³Ό λ¬λ¦¬ μ§μ° μ΄κΈ°ν λ°©μμμλ λΆνμν λΉμ μμ±νμ§ μμΌλ―λ‘, μ ν리μΌμ΄μ λ‘λ© μ νμν ν΄λμ€μ λΉμ μκ° λν κ°μνμ¬ λ‘λ© μκ°μ΄ ν¬κ² λ¨μΆλ μ μλ€.
μ€μ λ‘ νλ‘μ νΈμμ Java Flight Recorder(JFR)λ₯Ό νμ©νμ¬ μ§μ° μ΄κΈ°ν μ μ© μ νλ‘ λ©μλ νΈμΆ νμκ° μΌλ§λ μ€μ΄λ€μλμ§ λΉκ΅ν΄ 보μλ€.
-XX:StartFlightRecording=duration=60s,filename=boot.jfr,settings=profile
JFRμ VM optionsμ μ μ΅μ μ μ£Όκ³ μ€ννλ©΄ μμ§μ΄ κ°λ₯νκ³ , IntelliJλ₯Ό μ¬μ© μ€μ΄λΌλ©΄ λ³λλ‘ JMCλ₯Ό μ€μΉνμ§ μκ³ λ JFRμ IntelliJμμ μ΄μ΄λ³Ό μ μλ€.
Profiler κ²°κ³Ό
μ΄κΈ° λ‘λ© μ λ©μλ νΈμΆ νμκ° μ λ° μ΄μ κ°μνλ€.
κ·Έλ¦¬κ³ μ΄μ λ°λΌ λ‘λ©μ΄ μλ£λλ μκ°λ μ λ° μ΄μμ΄ μ€μ΄λ€μλ€.
μ±λ₯μ΄ μ’μλ° μ κΈ°λ³Έ μ€μ μ΄ μλκΉ?
μ§μ° μ΄κΈ°νλ₯Ό μ€μ νλ©΄ λΆνΈ λ‘λ© μλκ° λμ λκ² λΉ¨λΌμ§λ€. κ·Έλ°λ°λ μ€νλ§μ κΈ°λ³Έ μ€μ μ μ μ¦μ μ΄κΈ°νμΌκΉ?
μ§μ° μ΄κΈ°νκ° μ΄κΈ° λ‘λ© μ μ±λ₯μ μΌλ‘ λ°μ΄λλ°λ κΈ°λ³Έ μ€μ μ΄ μλ μ΄μ λ μν μ°Έμ‘°, λ©λͺ¨λ¦¬ λΆμ‘± μ€λ₯ λ±μ λ¬Έμ λ₯Ό μ¦μ λ°κ²¬νμ§ λͺ»νλ λ± μ μ¬μ λ¬Έμ κ° λ°μν μ μκΈ° λλ¬Έμ΄λ€. λ°λΌμ λ‘컬μμ λμΈ λλ§ μ νμ μΌλ‘ μ μ©νλ κ²μ΄ μμ νκ² μ±λ₯μ μ΄μ μ λ릴 μ μλ€κ³ μκ°λλ€.
λ§μ½ λͺ¨λ λΉμ μ§μ° μ΄κΈ°ννλ κ²μ΄ λΆλ΄μ€λ½κ±°λ, λ°°ν¬ νκ²½μμλ μ μ©νκ³ μΆλ€λ©΄ @Lazyλ₯Ό μ¬μ©ν΄ μ νμ μΌλ‘ ν μ€νΈν΄ λ³΄κ³ νλμ© μ μ©νλ©΄ λ κ² κ°λ€.
2. Gradle λ³λ ¬ μ²λ¦¬(parallel execution) λ° λΉλ μΊμ(build cache)
Gradleμ λΉλ μ±λ₯μ κ°μ μ λν μμΈν λ¬Έμλ Gradle Performance λ¬Έμλ₯Ό μ°Έκ³ νλ©΄ λλ€. μ±λ₯κ°μ μΈμλ λͺ¨λ μμ±μ λν΄ μκ³ μΆλ€λ©΄ Gradle Propertiesλ¬Έμλ₯Ό μ°Έκ³ νμ.
μ±λ₯ κ°μ κ³Ό κ΄λ ¨λ μ£Όμ μμ±μ μλ μΈ κ°μ§μ΄λ€.
1. org.gradle.daemon=true
Gradle λΉλλ₯Ό μν΄ JVMμ λ§€λ² μλ‘ λμ°λ λμ λ°±κ·ΈλΌμ΄λμμ νμ μ€νλλ λ°λͺ¬ νλ‘μΈμ€λ₯Ό μ¬μ¬μ©νλ κΈ°λ₯μ΄λ€. JVM μ΄κΈ°ν λΉμ©μ μ κ°ν μ μκΈ° λλ¬Έμ λΉλ μμμ΄ ν¨μ¬ λΉ¨λΌμ§λ€. λ€λ§ Gradle v3.0λΆν°λ defaultκ° trueμ΄κΈ° λλ¬Έμ λͺ μμ μΌλ‘ μ€μ νμ§ μμλ μλ§ λλΆλΆμ νλ‘μ νΈμμ κΈ°λ³Έμ μΌλ‘ νμ±νλμ΄ μμ κ°λ₯μ±μ΄ ν¬λ€.
2. org.gradle.caching=true
μ΄μ λΉλμμ μμ±λ task κ²°κ³Ό(μ»΄νμΌ κ²°κ³Ό, 리μμ€ μ²λ¦¬ λ±)λ₯Ό μ μ₯ν΄ λμλ€κ°, λ€μ λΉλ μ μ λ ₯κ°μ΄ λμΌν κ²½μ° ν΄λΉ κ²°κ³Όλ₯Ό μ¬μ¬μ©νλ κΈ°λ₯μ΄λ€. νΉν λ©ν° λͺ¨λκ³Ό κ°μ νλ‘μ νΈμμ κ³΅ν΅ λͺ¨λμ΄ μμ£Ό μ¬μ¬μ©λλ κ²½μ°μ ν° ν¨κ³Όλ₯Ό λ³Ό μ μλ€.
μ°Έκ³ λ‘ ./gradlew cleanμ μ€ννλλΌλ μΊμλ μμ λμ§ μκ³ μ μ§λλ€. λ°λΌμ λ³λλ‘ μΊμλ₯Ό μ§μ°μ§ μλ ν clean ν buildλ₯Ό μννλλΌλ μΊμλ μ μ©λλ€. μΊμλ₯Ό μμ νλ €λ©΄ Gradleμ μΊμ λλ ν°λ¦¬λ₯Ό μ§μ μμ νλ©΄ λλ€. (~/.gradle/)
3. org.gradle.parallel=true
μλ‘ μμ‘΄νμ§ μλ taskλ€μ λμμ λ³λ ¬λ‘ μννμ¬ λΉλ μλλ₯Ό λμΈλ€. μ΄λ 'μμ‘΄κ΄κ³μ λ°λ₯Έ μμλ₯Ό λ°λ‘ μ§μ ν΄μ£Όμ΄μΌ νλ?' μΆμ μλ μμ§λ§ μμ‘΄ κ΄κ³μ λ°λ₯Έ μ€ν μμλ λ°λ‘ μ μν΄μ£Όμ§ μλλΌλ 보μ₯λλ€. Gradleμ λΉλ μ€ν μ μ νμ€ν¬ κ° μμ‘΄ κ΄κ³ κ·Έλνλ₯Ό ꡬμ±νλλ° μ΄ κ·Έλνλ₯Ό κΈ°λ°μΌλ‘ νμ€ν¬μ μ€ν μμλ₯Ό μλμΌλ‘ κ΄λ¦¬νκΈ° λλ¬Έμ΄λ€.
λ°λΌμ μμ‘΄μ±μ΄ μλ νμ€ν¬λ λ°λμ μ ν νμ€ν¬κ° μλ£λ ν μ€νλλ©°, μμ‘΄μ±μ΄ μλ νμ€ν¬λ λ³λ ¬λ‘ μ€νλλ€.
μ μ©λ°©λ²μ project rootμ gradle.propertiesλ₯Ό λ§λ€κ³ μμ±μ νμ©ν΄ μ£Όλ©΄ λλ€.
# gradle.properties
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.caching=true
μ μ© ν λ©λͺ¨λ¦¬ λΆμ‘± λ¬Έμ
ν΄λΉ μ€μ λ€μ μ μ©ν μ΄ν λΉλ μ€ λ©λͺ¨λ¦¬ λΆμ‘± λ¬Έμ κ° λ°μν μ μλ€. μ΄ κ²½μ° μλ μμμ²λΌ λ³ΈμΈ νκ²½μ λ§κ² JVM ν λ©λͺ¨λ¦¬μ λ©νμ€νμ΄μ€ ν¬κΈ°λ₯Ό μ‘°μ ν΄μ£Όλ©΄ λλ€.
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
Profiler κ²°κ³Ό
./gradlew build --scan λͺ λ Ήμ΄λ₯Ό ν΅ν΄ λΉλ λ©νλ°μ΄ν°λ₯Ό λΆμνλ€.
κΈ°λ³Έ μ€μ μΌλ‘ λΉλλ₯Ό μνν κ²°κ³Ό μ΄ 26κ°μ νλ‘μ νΈμμ 363κ°μ νμ€ν¬κ° μ€νλμκ³ , μ 체 λΉλ μκ°μ 3λΆ 16μ΄κ° μμλμλ€.
org.gradle.caching=true μ΅μ μ μ μ©ν κ²½μ°, λμΌνκ² 363κ°μ νμ€ν¬κ° μ€νλμμ§λ§ μ΄ μ€ 70κ°μ νμ€ν¬κ° μΊμλ‘ μ²λ¦¬λμλ€. λλΆμ μ½ 1λΆ 37μ΄λ₯Ό μ μ½νμ¬ μ 체 λΉλ μκ°μ 1λΆ 35μ΄λ‘ λ¨μΆλμλ€.
org.gradle.parallel=true μ΅μ κΉμ§ μΆκ° μ μ©ν κ²°κ³Ό λ³λ ¬ μ²λ¦¬κ° ν¨κ³Όμ μΌλ‘ μ΄λ€μ§ κ²μ νμλΌμΈμμ νμΈν μ μλ€. μ 체 λΉλ μκ°μ λ¨ 17μ΄λ‘ μ±λ₯μ΄ νκΈ°μ μΌλ‘ κ°μ λμλ€.
μ μμ±λ€μ μΆκ°ν¨μΌλ‘μ¨ λ‘컬λΏλ§ μλλΌ CIλ¨κ³μμλ λΉλ μκ°μ λν μ€μΌ μ μμλ€.
μ 리
μ΄λ² μ΅μ ν μμ μ ν΅ν΄ Spring Boot μ ν리μΌμ΄μ μ λ‘λ© μκ°μ μ΅λ 47%, λΉλ μκ°μ μ΅λ 91%κΉμ§ λ¨μΆν μ μμλ€. νΉν μ§μ° μ΄κΈ°νμ Gradleμ μΊμ λ° λ³λ ¬ μ²λ¦¬ μ€μ μ μ μ© λ°©λ²μ΄ κ°λ¨νλ©΄μλ λμ λλ μ±λ₯ ν₯μμ μ 곡νκΈ°μ λμ²λΌ λλΉλλ μκ° μ€λ²ν€λμ λν΄ κ°μ κ³ λ―Όμ νλ€λ©΄ ν λ²μ―€ μ μ©ν΄ 보면 μ’μ κ² κ°λ€.