Spring Boot

์˜ํ•œ๋‹˜์˜ ์Šคํ”„๋ง ๋ถ€ํŠธ - ํ•ต์‹ฌ ์›๋ฆฌ์™€ ํ™œ์šฉ ๊ฐ•์˜๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

Intro

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๋„๊ตฌ

ํ•ต์‹ฌ ๊ธฐ๋Šฅ

  • WAS: Tomcat ๊ฐ™์€ ์›น ์„œ๋ฒ„๋ฅผ ๋‚ด์žฅํ•ด์„œ ๋ณ„๋„์˜ ์›น ์„œ๋ฒ„ ์„ค์น˜ ๋ถˆํ•„์š”

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ด€๋ฆฌ : ์†์‰ฌ์šด ๋นŒ๋“œ ๊ตฌ์„ฑ์„ ์œ„ํ•œ ์Šคํƒ€ํ„ฐ ์ข…์†์„ฑ ์ œ๊ณต ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ๊ด€๋ฆฌ

  • ์ž๋™ ๊ตฌ์„ฑ: ํ”„๋กœ์ ํŠธ ์‹œ์ž‘์— ํ•„์š”ํ•œ ์Šคํ”„๋ง๊ณผ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋นˆ์„ ์ž๋™ ๋“ฑ๋ก

  • ์™ธ๋ถ€ ์„ค์ •: ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ ธ์•ผ ํ•˜๋Š” ์™ธ๋ถ€ ์„ค์ • ๊ณตํ†ตํ™”

  • ํ”„๋กœ๋•์…˜ ์ค€๋น„: ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•œ ๋ฉ”ํŠธ๋ฆญ, ์ƒํƒœ ํ™•์ธ ๊ธฐ๋Šฅ ์ œ๊ณต

์›น ์„œ๋ฒ„์™€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ

๋ฐฉ์‹์˜ ๋ณ€ํ™”

์ „ํ†ต ๋ฐฉ์‹

  • ์ž๋ฐ” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์‹œ ์„œ๋ฒ„์— ํ†ฐ์บฃ ๊ฐ™์€ WAS(์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„) ์„ค์น˜๊ฐ€ ํ•„์š”

  • WAS์—์„œ ๋™์ž‘ํ•˜๋„๋ก ์„œ๋ธ”๋ฆฟ ์ŠคํŽ™์— ๋งž์ถ”์–ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  WAR ํ˜•์‹์œผ๋กœ ๋นŒ๋“œํ•ด์„œ .war ํŒŒ์ผ์„ ์ƒ์„ฑ

  • ์ƒ์„ฑ๋œ .war ํŒŒ์ผ์„ WAS์— ์ „๋‹ฌํ•ด์„œ ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ „์ฒด ๊ฐœ๋ฐœ ์ฃผ๊ธฐ๊ฐ€ ๋™์ž‘

  • ๊ณผ๊ฑฐ ๋ฐฉ์‹์€ WAS ๊ธฐ๋ฐ˜ ์œ„์—์„œ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹คํ–‰์ด ํ•„์š”ํ•˜๊ณ , IDE ๊ฐ™์€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋„ WAS์™€ ์—ฐ๋™ํ•ด์„œ ์‹คํ–‰๋˜๋„๋ก ๋ณต์žกํ•œ ์ถ”๊ฐ€ ์„ค์ •์ด ํ•„์š”

์ตœ๊ทผ ๋ฐฉ์‹

  • ์ตœ๊ทผ์—๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ๋‚ด์žฅ ํ†ฐ์บฃ์„ ํฌํ•จ(์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ์•ˆ์— WAS๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‚ด์žฅ)

  • ๊ฐœ๋ฐœ์ž๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  JAR๋กœ ๋นŒ๋“œํ•œ ๋‹ค์Œ์— ํ•ด๋‹น JAR๋ฅผ ์›ํ•˜๋Š” ์œ„์น˜์—์„œ ์‹คํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด WAS๋„ ํ•จ๊ป˜ ์‹คํ–‰

  • IDE ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ WAS ์„ค์น˜์™€ ์—ฐ๋™ํ•˜๋Š” ๋ณต์žกํ•œ ์ผ์€ ๋ถˆํ•„์š”

JAR & WAR

JAR (Java Archive)

java -jar abc.jar

  • ์ž๋ฐ”๋Š” ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์™€ ๊ด€๋ จ ๋ฆฌ์†Œ์Šค๋ฅผ ์••์ถ•ํ•œ .jar ๋ผ๋Š” ์••์ถœ ํŒŒ์ผ์ด ์กด์žฌ

  • JAR ํŒŒ์ผ์€ JVM ์œ„์—์„œ ์ง์ ‘ ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ œ๊ณต

  • ์ง์ ‘ ์‹คํ–‰ํ•  ๊ฒฝ์šฐ main() ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ณ , MANIFEST.MF ํŒŒ์ผ์— ์‹คํ–‰ํ•  ๋ฉ”์ธ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค ์ง€์ • ํ•„์š”

WAR (Web Application Archive)

  • .war ํŒŒ์ผ์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„(WAS)์— ๋ฐฐํฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํŒŒ์ผ

  • JAR ํŒŒ์ผ์ด JVM ์œ„์—์„œ ์‹คํ–‰๋œ๋‹ค๋ฉด, WAR๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„ ์œ„์—์„œ ์‹คํ–‰

  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„ ์œ„์—์„œ ์‹คํ–‰๋˜๊ณ , HTML ๊ฐ™์€ ์ •์  ๋ฆฌ์†Œ์Šค์™€ ํด๋ž˜์Šค ํŒŒ์ผ์„ ๋ชจ๋‘ ํ•จ๊ป˜ ํฌํ•จํ•˜๊ธฐ ๋•Œ๋ฌธ์— JAR ๋Œ€๋น„ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•˜๊ณ  WAR ๊ตฌ์กฐ๋ฅผ ์ง€์ผœ์•ผ ํ•จ

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”

  • ์„œ๋ธ”๋ฆฟ์€ ์ดˆ๊ธฐํ™” ์ธํ„ฐํŽ˜์ด์Šค(ServletContainerInitializer)๋ฅผ ์ œ๊ณต

    • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ๊ธฐ๋Šฅ ์ œ๊ณต

    • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹คํ–‰ ์‹œ์ ์— ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ์ธ onStartup() ์„ ํ˜ธ์ถœ

    • ์—ฌ๊ธฐ์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ดˆ๊ธฐํ™” ํ•˜๊ฑฐ๋‚˜ ๋“ฑ๋ก

public interface ServletContainerInitializer {

    /**
     * Set<Class<?>> c
     * - ๋” ์œ ์—ฐํ•œ ์ดˆ๊ธฐํ™” ๊ธฐ๋Šฅ ์ œ๊ณต
     * - @HandlesTypes ์• ๋…ธํ…Œ์ด์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ
     * 
     * ServletContext ctx
     * - ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ž์ฒด ๊ธฐ๋Šฅ ์ œ๊ณต
     * - ์ด ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ•„ํ„ฐ๋‚˜ ์„œ๋ธ”๋ฆฟ ๋“ฑ๋ก ๊ฐ€๋Šฅ
     */
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws
ServletException;
}

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ์„ค์ • example

์ดˆ๊ธฐํ™” ์ˆœ์„œ

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ์‹คํ–‰

    • ServletContainerInitializer ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , resources/META-INF/services/jakarta.servlet.ServletContainerInitializer ํŒŒ์ผ์— ๋“ฑ๋ก๋œ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ์‹คํ–‰

    • ์ปจํ„ฐ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ @HandlesTypes(AppInit.class) ๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ AppInit ๊ตฌํ˜„์ฒด๋ฅผ ๋ชจ๋‘ ์ฐพ์•„์„œ ์ƒ์„ฑ ๋ฐ ์‹คํ–‰

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ๊ฐœ๋… ์ƒ์„ฑ ์ด์œ 

  • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•ด ServletContainerInitializer ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„๊ณผ META-INF/services/ jakarta.servlet.ServletContainerInitializer ํŒŒ์ผ์— ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ์ง€์ •ํ•ด์•ผ ํ•˜์ง€๋งŒ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™”๋Š” ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๋Š” ํŽธ๋ฆฌํ•จ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™”๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ์ƒ๊ด€์—†์ด ์›ํ•˜๋Š” ๋ชจ์–‘์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•œ ์˜์กด์„ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ / ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” example

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ๋“ฑ๋ก

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ๋งŒ๋“ค๊ธฐ

  • ์Šคํ”„๋งMVC ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ธฐ

  • ์Šคํ”„๋งMVC๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋””์ŠคํŒจ์ฒ˜ ์„œ๋ธ”๋ฆฟ์„ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ๋“ฑ๋กํ•˜๊ธฐ

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ๋“ฑ๋ก example

์Šคํ”„๋ง MVC ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ์ง€์›

๋ฒˆ๊ฑฐ๋กญ๊ณ  ๋ฐ˜๋ณต์ ์ธ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ๊ณผ์ •์„ ์Šคํ”„๋ง MVC์ด ์ง€์›

  • ๊ฐœ๋ฐœ์ž๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ๊ณผ์ •์€ ์ƒ๋žตํ•˜๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋งŒ ์ž‘์„ฑ

  • WebApplicationInitializer ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„

  • spring-web ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ณด๋ฉด, ์•„๋ž˜ ํŒŒ์ผ๋“ค์„ ์ด๋ฏธ ๋“ฑ๋กํ•ด๋‘” ๊ฒƒ์„ ํ™•์ธ

  • META-INF/services/jakarta.servlet.ServletContainerInitializer

  • org.springframework.web.SpringServletContainerInitializer

package org.springframework.web;

public interface WebApplicationInitializer {
  void onStartup(ServletContext servletContext) throws ServletException;
}

์Šคํ”„๋ง MVC ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™” ์ง€์›(WebApplicationInitializer ๊ตฌํ˜„) example

์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ๋‚ด์žฅ ํ†ฐ์บฃ

Tomcat Library

implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.5'

WAR ๋ฐฐํฌ ๋ฐฉ์‹์˜ ๋‹จ์ 

  • WAS(ex. tomcat) ๋ณ„๋„ ์„ค์น˜ ํ•„์š”

  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • ๋ณต์žก

  • ๋ฐฐํฌ ๊ณผ์ • ๋ณต์žก

  • ๋ฒ„์ „ ๋ณ€๊ฒฝ ์‹œ WAS ์žฌ์„ค์น˜ ํ•„์š”

๋‚ด์žฅ ํ†ฐ์บฃ: ์„œ๋ธ”๋ฆฟ

  • ๋‚ด์žฅ ํ†ฐ์บฃ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ†ฐ์บฃ ์„œ๋ฒ„ ์„ค์น˜, IDE์— ๋ณ„๋„์˜ ๋ณต์žกํ•œ ํ†ฐ์บฃ ์„ค์ • ์—†์ด main() ๋ฉ”์„œ๋“œ๋งŒ ์‹คํ–‰ํ•˜๋ฉด ํ†ฐ์บฃ๊นŒ์ง€ ๋งค์šฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‹คํ–‰

์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ๋‚ด์žฅ ํ†ฐ์บฃ: ์„œ๋ธ”๋ฆฟ example

๋‚ด์žฅ ํ†ฐ์บฃ: ์Šคํ”„๋ง

  • ๋‚ด์žฅ ํ†ฐ์บฃ์— ์Šคํ”„๋ง ์—ฐ๋™

์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ๋‚ด์žฅ ํ†ฐ์บฃ: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์—ฐ๊ฒฐ example

๋‚ด์žฅ ํ†ฐ์บฃ: ๋นŒ๋“œ์™€ ๋ฐฐํฌ

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ํฌํ•จ๋œ ๋‚ด์žฅ ํ†ฐ์บฃ์„ ๋นŒ๋“œ ๋ฐฐํฌํ•˜๊ธฐ

  • main() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ jar ํ˜•์‹์œผ๋กœ ๋นŒ๋“œ

  • jar ์•ˆ์—๋Š” META-INF/MANIFEST.MF ํŒŒ์ผ์— ์‹คํ–‰ํ•  main() ๋ฉ”์„œ๋“œ์˜ ํด๋ž˜์Šค๋ฅผ ์ง€์ •

    Manifest-Version: 1.0
    Main-Class: hello.embed.EmbedTomcatSpringMain
  • build.gradle ์ ์šฉ ์‹œ

    • Jar ์•ˆ์—๋Š” Jar๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(jar)์—์„œ ์ œ๊ณต๋˜๋Š” ํด๋ž˜์Šค๋“ค์ด ํฌํ•จ๋œ fat jar ๋˜๋Š” uber jar ๋ฅผ ํ™œ์šฉ

    task buildFatJar(type: Jar) {
        manifest {
            attributes 'Main-Class': 'hello.embed.EmbedTomcatSpringMain'
        }
         // ํŒŒ์ผ๋ช… ์ค‘๋ณต ์‹œ ๊ฒฝ๊ณ 
        duplicatesStrategy = DuplicatesStrategy.WARN
        // ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ๋Œ๋ฆฌ๋ฉด์„œ class ํŒŒ์ผ๋“ค์„ ๋ฝ‘์•„๋‚ด๊ณ , ๋นŒ๋“œ ์‹œ ํฌํ•จ
        from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
        with jar
    }
    • ๋นŒ๋“œ: ./gradlew clean buildFatJar

    • ์‹คํ–‰: java -jar embed-0.0.1-SNAPSHOT.jar

๋ถ€ํŠธ ํด๋ž˜์Šค ๋งŒ๋“ค์–ด ๋ณด๊ธฐ

์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ๋‚ด์žฅ ํ†ฐ์บฃ: ํŽธ๋ฆฌํ•œ ๋ถ€ํŠธ ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ example

์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ์›น ์„œ๋ฒ„

์‹คํ–‰ ๊ณผ์ •

@SpringBootApplication
public class BootApplication {

	public static void main(String[] args) {
		SpringApplication.run(BootApplication.class, args);
	}
}
  • ์Šคํ”„๋ง ๋ถ€ํŠธ ์‹คํ–‰์€ Java main() ๋ฉ”์„œ๋“œ์—์„œ SpringApplication.run() ํ˜ธ์ถœ

  • ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฉ”์ธ ์„ค์ • ์ •๋ณด๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š”๋ฐ, ๋ณดํ†ต @SpringBootApplication ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ํ˜„์žฌ ํด๋ž˜์Šค๋ฅผ ์ง€์ •

  • @SpringBootApplication ์• ๋…ธํ…Œ์ด์…˜ ์•ˆ์—๋Š” @ComponentScan์„ ํฌํ•จํ•œ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์ด ์„ค์ •

    • ๊ธฐ๋ณธ ์„ค์ •์€ ํ˜„์žฌ ํŒจํ‚ค์ง€์™€ ๊ทธ ํ•˜์œ„ ํŒจํ‚ค์ง€ ๋ชจ๋‘๋ฅผ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”

SpringApplication.run(BootApplication.class, args); ์ฝ”๋“œ ํ•œ ์ค„์—์„œ

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ (new AnnotationConfigServletWebServerApplicationContext())

  • WAS(๋‚ด์žฅ ํ†ฐ์บฃ) ์ƒ์„ฑ (Tomcat tomcat = new Tomcat())

์‹คํ–‰ ๊ฐ€๋Šฅ Jar(Executable Jar)

Fat Jar์˜ ๋ฌธ์ œ์ (๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™•์ธ ์–ด๋ ค์›€, ํŒŒ์ผ๋ช… ์ค‘๋ณต ํ•ด๊ฒฐ ์–ด๋ ค์›€)์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด jar ๋‚ด๋ถ€์— jar๋ฅผ ํฌํ•จํ•˜์—ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ์ƒˆ๋กญ๊ฒŒ ์ •์˜ํ•œ ํŠน๋ณ„ํ•œ ๊ตฌ์กฐ์˜ jar

boot-0.0.1-SNAPSHOT.jar
  META-INF
    MANIFEST.MF
  org/springframework/boot/loader
    JarLauncher.class : ์Šคํ”„๋ง ๋ถ€ํŠธ main() ์‹คํ–‰ ํด๋ž˜์Šค
  BOOT-INF
    classes : ๊ฐœ๋ฐœํ•œ class ํŒŒ์ผ๊ณผ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ
      hello/boot/BootApplication.class
      hello/boot/controller/HelloController.class
      โ€ฆ
    lib : ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
        spring-webmvc-6.0.4.jar
        tomcat-embed-core-10.1.5.jar
        ...
    classpath.idx : ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ์Œ
    layers.idx : ์Šคํ”„๋ง ๋ถ€ํŠธ ๊ตฌ์กฐ ์ •๋ณด

Jar ์‹คํ–‰ ์ •๋ณด

  • java -jar xxx.jar ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด META-INF/MANIFEST.MF ํŒŒ์ผ์„ ์ฐพ๊ณ , ์—ฌ๊ธฐ์— ์žˆ๋Š” Main-Class ๋ฅผ ์ฝ์–ด์„œ main() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰

Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: hello.boot.BootApplication
Spring-Boot-Version: 3.0.2
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Build-Jdk-Spec: 17
  • Main-Class

    • JarLauncher(org/springframework/boot/loader/JarLauncher)๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ๋นŒ๋“œ ์‹œ ์‚ฝ์ž…

    • JarLauncher: ๋‚ด๋ถ€ jar(classes, lib)์™€ ํŠน๋ณ„ํ•œ ๊ตฌ์กฐ์˜ ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ์ฝ์–ด๋“ค์ด๋Š” ๊ธฐ๋Šฅ

    • ์ดํ›„ Start-Class ์— ์ง€์ •๋œ main() ํ˜ธ์ถœ

  • Start-Class

    • main() ์ด ์žˆ๋Š” hello.boot.BootApplication

  • Spring-Boot-Version : ์Šคํ”„๋ง ๋ถ€ํŠธ ๋ฒ„์ „

  • Spring-Boot-Classes : ๊ฐœ๋ฐœํ•œ ํด๋ž˜์Šค ๊ฒฝ๋กœ

  • Spring-Boot-Lib : ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฒฝ๋กœ

  • Spring-Boot-Classpath-Index : ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ์Œ

  • Spring-Boot-Layers-Index : ์Šคํ”„๋ง ๋ถ€ํŠธ ๊ตฌ์กฐ ์ •๋ณด

์Šคํ”„๋ง ๋ถ€ํŠธ ๋กœ๋”

  • org/springframework/boot/loader ํ•˜์œ„์— ์žˆ๋Š” ํด๋ž˜์Šค

  • JarLauncher ๋ฅผ ํฌํ•จํ•œ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅ Jar๋ฅผ ์‹ค์ œ๋กœ ๊ตฌ๋™์‹œํ‚ค๋Š” ํด๋ž˜์Šค๋“ค์ด ํฌํ•จ

  • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๋นŒ๋“œ ์‹œ ์ด ํด๋ž˜์Šค๋“ค์„ ํฌํ•จ

์‹คํ–‰ ๊ณผ์ •

1.java -jar xxx.jar

2.MANIFEST.MF ์ธ์‹

3.JarLauncher.main() ์‹คํ–‰

  • BOOT-INF/classes/ ์ธ์‹

  • BOOT-INF/lib/ ์ธ์‹

4.BootApplication.main() ์‹คํ–‰

์Šคํ”„๋ง ๋ถ€ํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ๊ด€๋ฆฌ

  • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์ˆ˜ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์„ ์ง์ ‘ ๊ด€๋ฆฌ

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์„ ์ƒ๋žตํ•ด๋„ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ๋ถ€ํŠธ ๋ฒ„์ „์— ๋งž์ถ˜ ์ตœ์ ํ™”๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์„ ์„ ํƒ

  • ์ž˜ ์•Œ๋ ค์ง€์ง€ ์•Š๊ฑฐ๋‚˜ ๋Œ€์ค‘์ ์ด์ง€ ์•Š์•„์„œ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ฒ„์ „์„ ์ง์ ‘ ๋ช…์‹œ

  • ๋ฒ„์ „ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด io.spring.dependency-management ํ”Œ๋Ÿฌ๊ทธ์ธ ์‚ฌ์šฉ ํ•„์š”

plugins {
  id 'org.springframework.boot' version '3.0.2'
  id 'io.spring.dependency-management' version '1.1.0' 
  id 'java'
}

...

dependencies {
 //์Šคํ”„๋ง ์›น, MVC
 implementation 'org.springframework:spring-webmvc'
 //๋‚ด์žฅ ํ†ฐ์บฃ
 implementation 'org.apache.tomcat.embed:tomcat-embed-core'
 //JSON ์ฒ˜๋ฆฌ
 implementation 'com.fasterxml.jackson.core:jackson-databind'
 //์Šคํ”„๋ง ๋ถ€ํŠธ ๊ด€๋ จ
 implementation 'org.springframework.boot:spring-boot'
 implementation 'org.springframework.boot:spring-boot-autoconfigure'
 //LOG ๊ด€๋ จ
 implementation 'ch.qos.logback:logback-classic'
 implementation 'org.apache.logging.log4j:log4j-to-slf4j'
 implementation 'org.slf4j:jul-to-slf4j'
 //YML ๊ด€๋ จ
 implementation 'org.yaml:snakeyaml'
}

์Šคํ”„๋ง ๋ถ€ํŠธ ์Šคํƒ€ํ„ฐ

Spring Boot application starters

  • ๊ฐ„ํŽธํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ ์‹œ์ž‘์— ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ์„ ๋ชจ์•„๋‘” ์Šคํ”„๋ง ๋ถ€ํŠธ ์Šคํƒ€ํ„ฐ ์ œ๊ณต

dependencies {
  // ์Šคํ”„๋ง ์›น MVC, ๋‚ด์žฅ ํ†ฐ์บฃ, JSON ์ฒ˜๋ฆฌ, ์Šคํ”„๋ง ๋ถ€ํŠธ ๊ด€๋ จ, LOG, YML ๋“ฑ ํฌํ•จ
 implementation 'org.springframework.boot:spring-boot-starter-web'
 // ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA, ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๋“ฑ ํฌํ•จ
 implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ๋ณ€๊ฒฝ

Version Properties

ext['tomcat.version'] = '10.1.4'

Auto Configuration

Auto Configuration example

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” Auto Configuration ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š”๋ฐ, ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ๋“ค์„ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•ด ์ค€๋‹ค.

  • JdbcTemplate , DataSource , TransactionManager .. ๋“ฑ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ž๋™ ๊ตฌ์„ฑ์„ ์ œ๊ณตํ•ด์„œ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก

  • spring-boot-autoconfigure ํ”„๋กœ์ ํŠธ ์•ˆ์—์„œ ์ˆ˜ ๋งŽ์€ ์ž๋™ ๊ตฌ์„ฑ ์ œ๊ณต

ex. JdbcTemplateAutoConfiguration

@AutoConfiguration(after = DataSourceAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ DatabaseInitializationDependencyConfigurer.class,
JdbcTemplateConfiguration.class,
NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}

@AutoConfiguration : ์ž๋™ ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ด ์• ๋…ธํ…Œ์ด์…˜ ๋“ฑ๋ก

  • ๋‚ด๋ถ€์— @Configuration ์œผ๋กœ ๋นˆ์„ ๋“ฑ๋กํ•˜๋Š” ์ž๋ฐ” ์„ค์ • ํŒŒ์ผ๋กœ ์‚ฌ์šฉ

  • after = DataSourceAutoConfiguration.class

    • ์ž๋™ ๊ตฌ์„ฑ์ด ์‹คํ–‰๋˜๋Š” ์ˆœ์„œ ์ง€์ •

    • JdbcTemplate ์€ DataSource ๊ฐ€ ํ•„์š”๋ฏ€๋กœ DataSource ๋ฅผ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•ด์ฃผ๋Š” DataSourceAutoConfiguration ์ดํ›„ ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •

@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })

  • IF๋ฌธ๊ณผ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต

  • ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์„ค์ •์ด ๋™์ž‘

  • ์—†๋‹ค๋ฉด ์„ค์ •๋“ค์ด ๋ชจ๋‘ ๋ฌดํšจํ™” ๋˜๊ณ , ๋นˆ๋„ ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ

  • JdbcTemplate ์€ DataSource, JdbcTemplate ํด๋ž˜์Šค๊ฐ€ ์žˆ์–ด์•ผ ๋™์ž‘์ด ๊ฐ€๋Šฅ

@Import : ์Šคํ”„๋ง์—์„œ ์ž๋ฐ” ์„ค์ • ์ถ”๊ฐ€ ์‹œ ์‚ฌ์šฉ

์ฐธ๊ณ . JdbcTemplateConfiguration

@Configuration : ์ž๋ฐ” ์„ค์ • ํŒŒ์ผ๋กœ ์‚ฌ์šฉ

@ConditionalOnMissingBean(JdbcOperations.class)

  • JdbcOperations(JdbcTemplate ๋ถ€๋ชจ ์ธํ„ฐํŽ˜์ด์Šค) ๋นˆ์ด ์—†์„ ๋•Œ ๋™์ž‘

  • ๋‚ด๊ฐ€ ๋“ฑ๋กํ•œ JdbcTemplate ๊ณผ ์ค‘๋ณต ๋“ฑ๋ก๋˜๋Š” ๋ฌธ์ œ ๋ฐฉ์ง€

์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ž๋™ ๊ตฌ์„ฑ


@Conditional

  • ํŠน์ • ์ƒํ™ฉ์ผ ๋•Œ๋งŒ ํŠน์ • ๋นˆ๋“ค์„ ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ๋„์™€์ฃผ๋Š” ๊ธฐ๋Šฅ

  • Condition ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉ

    /**
     * ConditionContext : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ, ํ™˜๊ฒฝ ์ •๋ณด๋“ฑ์ด ๋‹ด์€ ํด๋ž˜์Šค
     * AnnotatedTypeMetadata : ์• ๋…ธํ…Œ์ด์…˜ ๋ฉ”ํƒ€ ์ •๋ณด๋ฅผ ๋‹ด์€ ํด๋ž˜์Šค
     */
    package org.springframework.context.annotation;
      public interface Condition {
      boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    }

@conditional example

  • ์˜ˆ๋ฅผ ๋“ค์–ด, @Conditional(MemoryCondition.class) ์„ ์–ธ์ด ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ

    • MemoryCondition matches() ์‹คํ–‰

    • ๊ฒฐ๊ณผ๊ฐ€ true ์ผ ๊ฒฝ์šฐ

      • MemoryConfig ๋Š” ์ •์ƒ ๋™์ž‘ -> memoryController, memoryFinder ๋นˆ ๋“ฑ๋ก

    • ๊ฒฐ๊ณผ๊ฐ€ false ์ผ ๊ฒฝ์šฐ

      • MemoryConfig ๋Š” ๋ฌดํšจํ™” -> memoryController, memoryFinder ๋นˆ์€ ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ

  • ์œ„ ์ฝ”๋“œ๋Š” @ConditionalOnProperty(name = "memory", havingValue = "on") ํ•œ ์ค„๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ Condition Annotations

  • @ConditionalOnClass, @ConditionalOnMissingClass

    • ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋™์ž‘. ๋‚˜๋จธ์ง€๋Š” ๊ทธ ๋ฐ˜๋Œ€

  • @ConditionalOnBean, @ConditionalOnMissingBean

    • ๋นˆ์ด ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋™์ž‘. ๋‚˜๋จธ์ง€๋Š” ๊ทธ ๋ฐ˜๋Œ€

  • @ConditionalOnProperty

    • ํ™˜๊ฒฝ ์ •๋ณด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋™์ž‘.

  • @ConditionalOnResource

    • ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋™์ž‘.

  • @ConditionalOnWebApplication, @ConditionalOnNotWebApplication

    • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ธ ๊ฒฝ์šฐ ๋™์ž‘.

  • @ConditionalOnExpression

    • SpEL ํ‘œํ˜„์‹์— ๋งŒ์กฑํ•˜๋Š” ๊ฒฝ์šฐ ๋™์ž‘.

    ์ฐธ๊ณ . Condition Annotations

    • ์ฃผ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ ์ž๋™ ๊ตฌ์„ฑ์— ์‚ฌ์šฉ

์ž๋™ ๊ตฌ์„ฑ

์ž๋™ ๊ตฌ์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งŒ๋“ค๊ธฐ

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒ์„ฑ ํ”„๋กœ์ ํŠธ

    • Config ํŒŒ์ผ์— ์ž๋™ ๊ตฌ์„ฑ ์ถ”๊ฐ€

      @AutoConfiguration
      @ConditionalOnProperty(name = "memory", havingValue = "on")
      public class MemoryAutoConfig {
          @Bean
          public MemoryController memoryController() {
              return new MemoryController(memoryFinder());
          }
          @Bean
          public MemoryFinder memoryFinder() {
              return new MemoryFinder();
          }
      }
    • ์ž๋™ ๊ตฌ์„ฑ ๋Œ€์ƒ ํด๋ž˜์Šค ์ง€์ •

      • src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

        memory.MemoryAutoConfig
      • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์‹œ์ž‘ ์‹œ์ ์— ํ•ด๋‹น ํŒŒ์ผ์˜ ์ •๋ณด๋ฅผ ์ฝ์–ด์„œ ์ž๋™ ๊ตฌ์„ฑ์œผ๋กœ ์‚ฌ์šฉ

      • ๋‚ด๋ถ€์— ์žˆ๋Š” MemoryAutoConfig๊ฐ€ ์ž๋™์œผ๋กœ ๋นˆ ๋“ฑ๋ก

    • ๋นŒ๋“œ: ./gradlew clean build

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ํ”„๋กœ์ ํŠธ

    • dependencies ์ถ”๊ฐ€: implementation files('libs/memory-v1.jar')

    • ์Šคํ”„๋ง ๋ถ€ํŠธ ์ž๋™ ๊ตฌ์„ฑ์ด ์ ์šฉ๋˜์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์„ ์œ„ํ•œ ๋นˆ๋“ค์ด ์ž๋™์œผ๋กœ ๋“ฑ๋ก

    • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์ • ํ•„์š” ์‹œ VM ์˜ต์…˜ ์ถ”๊ฐ€: -Dmemory=on

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ

  • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์•„๋ž˜ ๊ฒฝ๋กœ์— ์žˆ๋Š” ํŒŒ์ผ์„ ์ฝ์–ด์„œ ์Šคํ”„๋ง ๋ถ€ํŠธ ์ž๋™ ๊ตฌ์„ฑ์œผ๋กœ ์‚ฌ์šฉ

    • resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

    • ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” spring-boot-autoconfigure ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ๋„ ์ž๋™ ๊ตฌ์„ฑ์„ ์‚ฌ์šฉ

      • org.springframework.boot.autoconfigure.AutoConfiguration.imports

  • ํ•ด๋‹น ํŒŒ์ผ์„ ์ฝ๊ณ  ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹

    • @SpringBootApplication ์‹คํ–‰ -> @EnableAutoConfiguration(์ž๋™ ๊ตฌ์„ฑ ํ™œ์„ฑํ™”) -> @Import(AutoConfigurationImportSelector.class)(์Šคํ”„๋ง ์„ค์ • ์ •๋ณด) -> resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ํŒŒ์ผ์„ ์—ด์–ด์„œ ์„ค์ • ์ •๋ณด ์„ ํƒ

ImportSelector

  • @Import์— ์„ค์ • ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•

    • ์ •์ ์ธ ๋ฐฉ๋ฒ•: ์ฝ”๋“œ์— ๋Œ€์ƒ์„ ์ง€์ •

      @Configuration
      @Import({AConfig.class, BConfig.class})
      public class AppConfig {...}
    • ๋™์ ์ธ ๋ฐฉ๋ฒ•: ์„ค์ •์œผ๋กœ ์‚ฌ์šฉํ•  ๋Œ€์ƒ์„ ๋™์ ์œผ๋กœ ์„ ํƒ

      • ImportSelector ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ -> ๋‹จ์ˆœํžˆ hello.selector.HelloConfig ์„ค์ • ์ •๋ณด ๋ฐ˜ํ™˜

        package org.springframework.context.annotation;
        
        public interface ImportSelector {
        String[] selectImports(AnnotationMetadata importingClassMetadata);
        //...
        }
      • ๋ฐ˜ํ™˜๋˜์–ด ์„ค์ • ์ •๋ณด๋กœ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค๋ฅผ ๋™์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

        public class HelloImportSelector implements ImportSelector {
            @Override
            public String[] selectImports(AnnotationMetadata importingClassMetadata) {
                return new String[]{"hello.selector.HelloConfig"};
            }
        }
        
        ...
        
        @Configuration
        @Import(HelloImportSelector.class)
        public static class SelectorConfig {
        }

์ž๋™๊ตฌ์„ฑ์˜ ์‚ฌ์šฉ

  • ๋ณดํ†ต ํ•„์š”ํ•œ ๋นˆ๋“ค์€ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”ํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ๋“ฑ๋กํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ž๋™๊ตฌ์„ฑ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ œ๊ณตํ•  ๋•Œ ์‚ฌ์šฉ

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

์™ธ๋ถ€์„ค์ •

ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋ณ€ํ•˜๋Š” ์„ค์ •๊ฐ’์„ ์‹คํ–‰ ์‹œ์ ์— ์ฃผ์ž…

์„ค์ •๊ฐ’ ์™ธ๋ถ€ ์„ค์ •์„ ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋„ค ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  • OS ํ™˜๊ฒฝ ๋ณ€์ˆ˜: OS์—์„œ ์ง€์›ํ•˜๋Š” ์™ธ๋ถ€ ์„ค์ •. ํ•ด๋‹น OS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค์—์„œ ์‚ฌ์šฉ

  • ์ž๋ฐ” ์‹œ์Šคํ…œ ์†์„ฑ: ์ž๋ฐ”์—์„œ ์ง€์›ํ•˜๋Š” ์™ธ๋ถ€ ์„ค์ •. ํ•ด๋‹น JVM ์•ˆ์—์„œ ์‚ฌ์šฉ

    • java -Durl=devdb -Dusername=dev_user -Dpassword=dev_pw -jar app.jar

  • ์ž๋ฐ” ์ปค๋งจ๋“œ ๋ผ์ธ ์ธ์ˆ˜: ์ปค๋งจ๋“œ ๋ผ์ธ์—์„œ ์ „๋‹ฌํ•˜๋Š” ์™ธ๋ถ€ ์„ค์ •. ์‹คํ–‰์‹œ main(args) ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉ

    • java -jar app.jar dataA dataB

  • ์ž๋ฐ” ์ปค๋งจ๋“œ ๋ผ์ธ ์˜ต์…˜ ์ธ์ˆ˜: ์Šคํ”„๋ง์—์„œ ์ปค๋งจ๋“œ ๋ผ์ธ ์ธ์ˆ˜๋ฅผ key=value ํ˜•์‹์œผ๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ‘œ์ค€ ๋ฐฉ์‹(--) ์ •์˜

  • ์™ธ๋ถ€ ํŒŒ์ผ(์„ค์ • ๋ฐ์ดํ„ฐ): ํ”„๋กœ๊ทธ๋žจ์—์„œ ์™ธ๋ถ€ ํŒŒ์ผ์„ ์ง์ ‘ ์ฝ์–ด์„œ ์‚ฌ์šฉ

    • ๋กœ๋”ฉ ์‹œ์ ์— ํŒŒ์ผ(.properties, .yml)์„ ์ž๋™์œผ๋กœ ์ฝ์–ด์„œ ๊ทธ ์†์˜ ๊ฐ’๋“ค์„ ์™ธ๋ถ€ ์„ค์ •๊ฐ’์œผ๋กœ ์‚ฌ์šฉ

    • ํ”„๋กœํ•„: spring.profiles.active={profile} ์„ค์ •์œผ๋กœ ํ”„๋กœํ•„ ์ง€์ •

      • ์•„๋ž˜ ๊ทœ์น™์œผ๋กœ ์„ค์ • ํ”„๋กœํ•„์— ๋งž๋Š” ๋‚ด๋ถ€ ํŒŒ์ผ(์„ค์ • ๋ฐ์ดํ„ฐ) ์กฐํšŒ

      • application-{profile}.properties

    • ์ปค๋งจ๋“œ ๋ผ์ธ ์˜ต์…˜ ์ธ์ˆ˜ ์‹คํ–‰: --spring.profiles.active=dev

    • ์ž๋ฐ” ์‹œ์Šคํ…œ ์†์„ฑ ์‹คํ–‰: -Dspring.profiles.active=dev

์Šคํ”„๋ง ํ†ตํ•ฉ

  • ์ถ”์ƒํ™”(Environment, PropertySource)๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€ ์„ค์ •๊ฐ’์ด ์–ด๋””์— ์œ„์น˜ํ•˜๋“  ์ผ๊ด€์„ฑ ์žˆ๊ณ , ํŽธ๋ฆฌํ•˜๊ฒŒ ์„ค์ •๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ์Œ

  • PropertySource: ์Šคํ”„๋ง์€ ๋กœ๋”ฉ ์‹œ์ ์— ํ•„์š”ํ•œ PropertySource ๋“ค์„ ์ƒ์„ฑํ•˜๊ณ , Environment ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์—ฐ๊ฒฐ

  • Environment: ๋ชจ๋“  ์™ธ๋ถ€ ์„ค์ •(์ปค๋ฉ˜๋“œ ๋ผ์ธ ์˜ต์…˜ ์ธ์ˆ˜, ์ž๋ฐ” ์‹œ์Šคํ…œ ์†์„ฑ, OS ํ™˜๊ฒฝ๋ณ€์ˆ˜, ์„ค์ • ํŒŒ์ผ)์€ Environment ๋ฅผ ํ†ตํ•ด ์กฐํšŒ

์šฐ์„ ์ˆœ์œ„

  • ๋” ์œ ์—ฐํ•œ ๊ฒƒ์ด ์šฐ์„ ๊ถŒ

  • ๋ฒ”์œ„๊ฐ€ ๋„’์€ ๊ฒƒ ๋ณด๋‹ค ์ข์€ ๊ฒƒ์ด ์šฐ์„ ๊ถŒ

url=local.db.com
username=local_user
password=local_pw
#---
spring.config.activate.on-profile=dev
url=dev.db.com
username=dev_user
password=dev_pw
#---
spring.config.activate.on-profile=prod
url=prod.db.com
username=prod_user
password=prod_pw
  • ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฌธ์„œ๋ฅผ ์œ„์—์„œ ์•„๋ž˜๋กœ ์ˆœ์„œ๋Œ€๋กœ ์ฝ์œผ๋ฉด์„œ ๊ฐ’์„ ์„ค์ •. ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฎ์–ด์“ฐ๊ธฐ

  • ๋…ผ๋ฆฌ ๋ฌธ์„œ์— spring.config.activate.on-profile ์˜ต์…˜์ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ํ”„๋กœํ•„์„ ์‚ฌ์šฉํ•  ๋•Œ(--spring.profiles.active)๋งŒ ๋…ผ๋ฆฌ ๋ฌธ์„œ ์ ์šฉ

์™ธ๋ถ€ ์„ค์ • ์šฐ์„ ์ˆœ์œ„

(๋‚ด๋ ค๊ฐˆ์ˆ˜๋ก ์šฐ์„ ์ˆœ์œ„ ๋†’์•„์ง)

  • ์„ค์ • ๋ฐ์ดํ„ฐ(application.properties)

  • OS ํ™˜๊ฒฝ๋ณ€์ˆ˜

  • ์ž๋ฐ” ์‹œ์Šคํ…œ ์†์„ฑ

  • ์ปค๋งจ๋“œ ๋ผ์ธ ์˜ต์…˜ ์ธ์ˆ˜

  • @TestPropertySource(in Test)

์„ค์ • ๋ฐ์ดํ„ฐ ์šฐ์„ ์ˆœ์œ„

(๋‚ด๋ ค๊ฐˆ์ˆ˜๋ก ์šฐ์„ ์ˆœ์œ„ ๋†’์•„์ง)

  • jar ๋‚ด๋ถ€ application.properties

  • jar ๋‚ด๋ถ€ ํ”„๋กœํ•„ ์ ์šฉ ํŒŒ์ผ application-{profile}.properties

  • jar ์™ธ๋ถ€ application.properties

  • jar ์™ธ๋ถ€ ํ”„๋กœํ•„ ์ ์šฉ ํŒŒ์ผ application-{profile}.properties

applicaiton.properties์— ์„ค์ • ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ์ผ๋ถ€ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๋Š” ์ž๋ฐ” ์‹œ์Šคํ…œ ์†์„ฑ์ด๋‚˜ ์ปค๋งจ๋“œ ๋ผ์ธ ์˜ต์…˜ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

์™ธ๋ถ€ ์„ค์ • ์‚ฌ์šฉ

Environment

String url = env.getProperty("my.datasource.url");
String username = env.getProperty("my.datasource.username");
String password = env.getProperty("my.datasource.password");
int maxConnection = env.getProperty("my.datasource.etc.max-connection", Integer.class);
Duration timeout = env.getProperty("my.datasource.etc.timeout", Duration.class);
List<String> options = env.getProperty("my.datasource.etc.options", List.class);

@Value

  • ์™ธ๋ถ€ ์„ค์ •๊ฐ’์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ฃผ์ž…

  • ๋‚ด๋ถ€์—์„œ๋Š” Environment ์‚ฌ์šฉ

  • ํ•„๋“œ, ํŒŒ๋ผ๋ฏธํ„ฐ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ

  • ํƒ€์ž… ์ปจ๋ฒ„ํŒ…์„ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰

  • ์™ธ๋ถ€ ์„ค์ • ์ •๋ณด์˜ ํ‚ค ๊ฐ’์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž…๋ ฅ, ์ฃผ์ž… ๋ฐ›์•„์•ผ ํ•˜๋Š” ๋‹จ์ 

  • ๊ธฐ๋ณธ๊ฐ’ ์‚ฌ์šฉ ์‹œ: @Value("${my.datasource.etc.max-connection:1}")

@Value("${my.datasource.url}")
private String url;
@Value("${my.datasource.username}")
private String username;
@Value("${my.datasource.password}")
private String password;
@Value("${my.datasource.etc.max-connection}")
private int maxConnection;
@Value("${my.datasource.etc.timeout}")
private Duration timeout;
@Value("${my.datasource.etc.options}")
private List<String> options;

@ConfigurationProperties

  • Type-safe Configuration Properties

  • ์™ธ๋ถ€ ์„ค์ •์˜ ๋ฌถ์Œ, ๊ณ„์ธต ์ •๋ณด๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์‚ฌ์šฉ

  • ํƒ€์ž… ์•ˆ์ „ํ•œ ์„ค์ • ์†์„ฑ ์‚ฌ์šฉ(ํƒ€์ž…์ด ๋‹ค๋ฅด๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ)

  • ์บ๋ฐฅ ํ‘œ๊ธฐ๋ฒ•์„ ๋‚™ํƒ€ ํ‘œ๊ธฐ๋ฒ•์œผ๋กœ ์ค‘๊ฐ„์— ์ž๋™์œผ๋กœ ๋ณ€ํ™˜

  • ๊ฐ’ ๋ณ€๊ฒฝ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์„ธํ„ฐ ๋Œ€์‹  ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์ž.

  • @DefaultValue: ํ•ด๋‹น ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉ

  • ์ˆซ์ž์˜ ๋ฒ”์œ„, ๋ฌธ์ž์˜ ๊ธธ์ด ๊ฒ€์ฆ์„ ์œ„ํ•ด ์ž๋ฐ” ๋นˆ ๊ฒ€์ฆ๊ธฐ(java bean validation) ์‚ฌ์šฉ ๊ฐ€๋Šฅ

    • dependency: implementation 'org.springframework.boot:spring-boot-starter-validation

๊ฐ€์žฅ ์ข‹์€ ์˜ˆ์™ธ๋Š” ์ปดํŒŒ์ผ ์˜ˆ์™ธ, ๊ทธ๋ฆฌ๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ.

๊ฐ€์žฅ ๋‚˜์œ ์˜ˆ์™ธ๋Š” ๊ณ ๊ฐ ์„œ๋น„์Šค ์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ์˜ˆ์™ธ

my.datasource.url=local.db.com
my.datasource.username=username
my.datasource.password=password
my.datasource.etc.max-connection=1
my.datasource.etc.timeout=3500ms
my.datasource.etc.options=CACHE,ADMIN

...

@Getter
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV2 {
    private String url;
    private String username;
    private String password;
    private Etc etc;

    public MyDataSourcePropertiesV2(String url, String username, String password, @DefaultValue Etc etc) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.etc = etc;
    }

    @Getter
    public static class Etc {
        private int maxConnection;
        private Duration timeout;
        private List<String> options;

        public Etc(int maxConnection, Duration timeout, @DefaultValue("DEFAULT") List<String> options) {
            this.maxConnection = maxConnection;
            this.timeout = timeout;
            this.options = options;
        }
    }
}

YAML

YAML(YAML Ain't Markup Language)์€ ์ฝ๊ธฐ ์ข‹์€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋ชฉํ‘œ

  • ํ™•์žฅ์ž๋Š” yaml, yml(์ฃผ๋กœ ์‚ฌ์šฉ)

  • application.properties, application.yml ๋™์‹œ ์‚ฌ์šฉ ์‹œ application.properties ์šฐ์„ ๊ถŒ

  • ---๋กœ ๋…ผ๋ฆฌ ํŒŒ์ผ ๊ตฌ๋ถ„

  • spring.config.active.on-profile ๋กœ ํ”„๋กœํ•„ ์ ์šฉ

  • --spring.profiles.active=dev

@Profile

@Profile ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ํ”„๋กœํ•„์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์—๋งŒ ๋นˆ ๋“ฑ๋ก

  • ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ํ•ด๋‹น ๋นˆ์„ ๋“ฑ๋กํ• ์ง€ ๋ง์ง€ ์„ ํƒ

  • ๊ฐ ํ™˜๊ฒฝ ๋ณ„๋กœ ์™ธ๋ถ€ ์„ค์ • ๊ฐ’, ๋“ฑ๋ก๋˜๋Š” ์Šคํ”„๋ง ๋นˆ ๋ถ„๋ฆฌ

  • ์Šคํ”„๋ง์€ @Conditional ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด์„œ @Profile ๊ธฐ๋Šฅ์„ ์ œ๊ณต

์•ก์ธ„์—์ดํ„ฐ

Production-ready Features

๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‘์„ ์œ„ํ•ด ์„œ๋น„์Šค์— ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ , ์ง€ํ‘œ๋“ค์„ ์‹ฌ์–ด์„œ ๊ฐ์‹œํ•˜๋Š” ํ™œ๋™์ด ์ค‘์š”

ํ”„๋กœ๋•์…˜ ์ค€๋น„ ๊ธฐ๋Šฅ: ํ”„๋กœ๋•์…˜์„ ์šด์˜์— ๋ฐฐํฌํ•  ๋•Œ ์ค€๋น„ํ•ด์•ผ ํ•˜๋Š” ๋น„ ๊ธฐ๋Šฅ์  ์š”์†Œ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ด์•„์žˆ๋Š”์ง€, ๋กœ๊ทธ ์ •๋ณด๋Š” ์ •์ƒ ์„ค์ • ๋˜์—ˆ๋Š”์ง€, ์ปค๋„ฅ์…˜ ํ’€์€ ์–ผ๋งˆ๋‚˜ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š”์ง€ ๋“ฑ ํ™•์ธ ํ•„์š”

    • ์ง€ํ‘œ(metric): CPU ์‚ฌ์šฉ๋Ÿ‰

    • ์ถ”์ (trace): ์ด์Šˆ ์ฝ”๋“œ ์ถ”์ 

    • ๊ฐ์‚ฌ(auditing): ๊ณ ๊ฐ ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ์ด๋ ฅ ์ถ”์ 

    • ๋ชจ๋‹ˆํ„ฐ๋ง: ์‹œ์Šคํ…œ ์ƒํƒœ

Dependency

implementation 'org.springframework.boot:spring-boot-starter-actuator'
  • http://localhost:8080/actuator ๋กœ ํ™•์ธ ๊ฐ€๋Šฅ

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ ์ •๋ณด: http://localhost:8080/actuator/health

    • ๊ฐ ์—”๋“œํฌ์ธํŠธ๋Š” /actuator/{์—”๋“œํฌ์ธํŠธ๋ช…} ํ˜•์‹์œผ๋กœ ์ ‘๊ทผ

    • ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณต๋ฐ›๊ธฐ ์œ„ํ•ด ์—”๋“œํฌ์ธํŠธ ๋…ธ์ถœ ์„ค์ • ์ถ”๊ฐ€(๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๋ฅผ ์›น์— ๋…ธ์ถœ)

      • ์—”๋“œํฌ์ธํŠธ๋Š” shutdown ์ œ์™ธํ•˜๊ณ  ๋Œ€๋ถ€๋ถ„ ๊ธฐ๋ณธ์œผ๋กœ ํ™œ์„ฑํ™”

      • ํŠน์ • ์—”๋“œํฌ์ธํŠธ ํ™œ์„ฑํ™” ์‹œ management.endpoint.{์—”๋“œํฌ์ธํŠธ๋ช…}.enabled=true

      management:
        endpoints:
          web:
            exposure:
              include: "*"

Endpoints

  • /actuator:

  • /actuator/beans: ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ์ŠคํŠธ๋ง ๋นˆ ๋ชฉ๋ก

  • /actuator/caches:

    • /actuator/caches/{cache}:

  • /actuator/health: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฌธ์ œ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ธ์ง€(์ „์ฒด ์ƒํƒœ, db, mongo, redis, diskspace, ping ๋“ฑ ํ™•์ธ ๊ฐ€๋Šฅ)

    • /actuator/health/{*path}:

    • ํ—ฌ์Šค ์ปดํฌ๋„ŒํŠธ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉด ์ „์ฒด ์ƒํƒœ๋Š” DOWN

    • ํ—ฌ์Šค ์ •๋ณด๋ฅผ ๋” ์ž์„ธํžˆ ๋ณด๊ธฐ ์œ„ํ•œ ์˜ต์…˜ management.endpoint.health.show-details=always

    • ๊ฐ„๋žตํžˆ ๋ณด๊ธฐ ์œ„ํ•œ ์˜ต์…˜ management.endpoint.health.show-components=always

  • /actuator/info: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋ณธ ์ •๋ณด (default ๋น„ํ™œ์„ฑํ™”)

    • management.info.<id>.enabled=true

    • java : ์ž๋ฐ” ๋Ÿฐํƒ€์ž„ ์ •๋ณด

    • os : OS ์ •๋ณด

    • env : Environment ์—์„œ info. ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ •๋ณด

    • build : ๋นŒ๋“œ ์ •๋ณด (META-INF/build-info.properties ํŒŒ์ผ ํ•„์š”)

      // build.gradle ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋นŒ๋“œ ์ •๋ณด ํŒŒ์ผ ์ƒ์„ฑ
      springBoot {
        buildInfo()
      }
    • git : git ์ •๋ณด (git.properties ํŒŒ์ผ ํ•„์š”)

      // git.properties plugin ์ถ”๊ฐ€
      id "com.gorylenko.gradle-git-properties" version "2.4.1"
  • /actuator/conditions: condition์„ ํ†ตํ•ด ๋นˆ ๋“ฑ๋ก ์‹œ ํ‰๊ฐ€ ์กฐ๊ฑด๊ณผ ์ผ์น˜ํ•˜๊ฑฐ๋‚˜ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์ด์œ  ํ‘œ์‹œ

  • /actuator/configprops: @ConfigurationProperties ๋ชฉ๋ก

    • /actuator/configprops/{prefix}:

  • /actuator/env: Environment ์ •๋ณด

    • /actuator/env/{toMatch}:

  • /actuator/loggers: ๋กœ๊น… ๊ด€๋ จ ์ •๋ณด ํ™•์ธ. ์‹ค์‹œ๊ฐ„ ๋ณ€๊ฒฝ

    • ํŠน์ • ํŒจํ‚ค์ง€์— ๋กœ๊ทธ ๋ ˆ๋ฒจ ์„ค์ •(default. INFO)

      logging.level.hello.controller: debug
    • ํŠน์ • ๋กœ๊ฑฐ ์ด๋ฆ„ ๊ธฐ์ค€์œผ๋กœ ์กฐํšŒ. /actuator/loggers/{name}

      • /actuator/loggers/hello.controller

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์ง€ ์•Š๊ณ , (๋ฉ”๋ชจ๋ฆฌ์—) ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋กœ๊ทธ ๋ ˆ๋ฒจ ๋ณ€๊ฒฝ

      POST http://localhost:8080/actuator/loggers/hello.controller
      
      {
        "configuredLevel": "TRACE"
      }
  • /actuator/heapdump:

  • /actuator/threaddump: ์“ฐ๋ ˆ๋“œ ๋คํ”„ ์ •๋ณด

  • /actuator/metrics: : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”ํŠธ๋ฆญ ์ •๋ณด

    • /actuator/metrics/{requiredMetricName}

      /actuator/metrics/jvm.memory.used : JVM ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰
      --- availableTags
      /actuator/metrics/jvm.memory.used?tag=area:heap
      
      /actuator/metrics/http.server.requests : HTTP ์š”์ฒญ์ˆ˜
      --- availableTags
      /actuator/metrics/http.server.requests?tag=uri:/log
      /actuator/metrics/http.server.requests?tag=uri:/log&tag=status:200
  • /actuator/scheduledtasks:

  • /actuator/mappings: @RequestMapping ์ •๋ณด ๋ชฉ๋ก

  • /httpexchanges: HTTP ํ˜ธ์ถœ ์‘๋‹ต ์ •๋ณด. HttpExchangeRepository ๊ตฌํ˜„ ๋นˆ ๋“ฑ๋ก ํ•„์š”

    • ์ตœ๋Œ€ 100๊ฐœ์˜ HTTP ์š”์ฒญ ์ œ๊ณต(์ตœ๋Œ€ ์š”์ฒญ ์ดˆ๊ณผ ์‹œ ๊ณผ๊ฑฐ ์š”์ฒญ์„ ์‚ญ์ œ

    • setCapacity() ๋กœ ์ตœ๋Œ€ ์š”์ฒญ์ˆ˜๋ฅผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

    • ๋‹จ์ˆœํ•˜๊ณ  ์ œํ•œ์ด ๋งŽ์€ ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ๋งŒ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๊ณ , ์‹ค์ œ ์šด์˜ ์„œ๋น„์Šค์—์„œ๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์ด๋‚˜ ํ•€ํฌ์ธํŠธ, Zipkin ๊ฐ™์€ ๋‹ค๋ฅธ ๊ธฐ์ˆ  ์‚ฌ์šฉ ์ถ”์ฒœ

  • /shutdown: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ. ๊ธฐ๋ณธ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”

๋ณด์•ˆ์„ ์œ„ํ•ด ๋‚ด๋ถ€๋ง์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ํฌํŠธ ์„ค์ •

management.server.port=9292
  • ์™ธ๋ถ€๋ง์„ ํ†ตํ•ด ์ ‘๊ทผ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด /actuator ๊ฒฝ๋กœ์— ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ, ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ, ์Šคํ”„๋ง ์‹œํํ‹ฐ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ • ํ•„์š”

๋ชจ๋‹ˆํ„ฐ๋ง

์„œ๋น„์Šค ์šด์˜ ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ CPU, ๋ฉ”๋ชจ๋ฆฌ, ์ปค๋„ฅ์…˜ ์‚ฌ์šฉ, ๊ณ ๊ฐ ์š”์ฒญ ์ˆ˜ ๊ฐ™์€ ์ˆ˜ ๋งŽ์€ ์ง€ํ‘œ๋“ค์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค.

๊ทธ๋ž˜์•ผ ์–ด๋””์— ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์‚ฌ์ „ ๋Œ€์‘์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์‹ค์ œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์›์ธ์„ ๋น ๋ฅด๊ฒŒ ํŒŒ์•…ํ•˜๊ณ  ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ

์ˆ˜ ๋งŽ์€ ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์ด ์žˆ๊ณ , ๊ฐ ํˆด๋งˆ๋‹ค ์ „๋‹ฌ ๋ฐฉ์‹์ด ๋‹ค๋ฅธ๋ฐ ์ด ๋ชจ๋“  ๊ฒƒ๋“ค์„ ์ถ”์ƒํ™”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ(Micrometer)

  • ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋Š” application metric facade ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š”๋ฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”ํŠธ๋ฆญ(์ธก์ • ์ง€ํ‘œ)์„ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๊ฐ€ ์ •ํ•œ ํ‘œ์ค€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ชจ์•„์„œ ์ œ๊ณต (์ถ”์ƒํ™”๋œ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋กœ ๊ตฌํ˜„์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ์Œ)

  • spring boot actuator ๋Š” ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋ฅผ ๊ธฐ๋ณธ ๋‚ด์žฅํ•ด์„œ ์‚ฌ์šฉ

  • ๊ฐœ๋ฐœ์ž๋Š” ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๊ฐ€ ์ •ํ•œ ํ‘œ์ค€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฉ”ํŠธ๋ฆญ(์ธก์ • ์ง€ํ‘œ)๋ฅผ ์ „๋‹ฌ

    • ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์— ๋งž๋Š” ๊ตฌํ˜„์ฒด ์„ ํƒ

    • ์ดํ›„ ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋งŒ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ ๊ฐ€๋Šฅ

Micrometer Documentation

๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด

AppOptics

Atlas

CloudWatch

Datadog

Dynatrace

Elastic

Ganglia

Graphite

Humio

Influx

Instana

JMX

KairosDB

New Relic

Prometheus

SignalFx

Stackdriver

StatsD

Wavefront

๋ฉ”ํŠธ๋ฆญ

Supported Metrics and Meters

๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ์™€ ์•ก์ธ„์—์ดํ„ฐ๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฉ”ํŠธ๋ฆญ

  • JVM ๋ฉ”ํŠธ๋ฆญ jvm.*

    • ๋ฉ”๋ชจ๋ฆฌ ๋ฐ ๋ฒ„ํผ ํ’€ ์„ธ๋ถ€ ์ •๋ณด

    • ๊ฐ€๋น„์ง€ ์ˆ˜์ง‘ ๊ด€๋ จ ํ†ต๊ณ„

    • ์Šค๋ ˆ๋“œ ํ™œ์šฉ

    • ๋กœ๋“œ ๋ฐ ์–ธ๋กœ๋“œ๋œ ํด๋ž˜์Šค ์ˆ˜

    • JVM ๋ฒ„์ „ ์ •๋ณด

    • JIT ์ปดํŒŒ์ผ ์‹œ๊ฐ„

  • ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ system.*, process.*, disk.*

    • CPU ์ง€ํ‘œ

    • ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ๋ฉ”ํŠธ๋ฆญ

    • ๊ฐ€๋™ ์‹œ๊ฐ„ ๋ฉ”ํŠธ๋ฆญ

    • ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋””์Šคํฌ ๊ณต๊ฐ„

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ๋ฉ”ํŠธ๋ฆญ application.*

    • application.started.time: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘์— ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„ (ApplicationStartedEvent๋กœ ์ธก์ • - ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์™„์ „ํžˆ ์‹คํ–‰๋œ ์ƒํƒœ. ์ดํ›„์— ์ปค๋งจ๋“œ ๋ผ์ธ ๋Ÿฌ๋„ˆ๊ฐ€ ํ˜ธ์ถœ)

    • application.ready.time : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ค€๋น„๊ฐ€ ๋˜๋Š”๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„ (ApplicationReadyEvent ๋กœ ์ธก์ •- ์ปค๋งจ๋“œ ๋ผ์ธ ๋Ÿฌ๋„ˆ๊ฐ€ ์‹คํ–‰๋œ ์ดํ›„์— ํ˜ธ์ถœ)

  • ์Šคํ”„๋ง MVC ๋ฉ”ํŠธ๋ฆญ

    • http.server.requests: ์Šคํ”„๋ง MVC ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ชจ๋“  ์š”์ฒญ ์ •๋ณด

    • TAG ๋กœ ์ •๋ณด๋ฅผ ๋ถ„๋ฅ˜ํ•ด์„œ ํ™•์ธ ๊ฐ€๋Šฅ

      • uri : ์š”์ฒญ URI

      • method : HTTP ๋ฉ”์„œ๋“œ(GET, POST..)

      • status : HTTP Status ์ฝ”๋“œ(200, 400, 500..)

      • exception : ์˜ˆ์™ธ

      • outcome : ์ƒํƒœ์ฝ”๋“œ ๊ทธ๋ฃน(1xx:INFORMATIONAL, 2xx:SUCCESS, 3xx:REDIRECTION, 4xx:CLIENT_ERROR, 5xx:SERVER_ERROR)

  • ํ†ฐ์บฃ ๋ฉ”ํŠธ๋ฆญ tomcat.

    • ํ†ฐ์บฃ์˜ ์ตœ๋Œ€ ์“ฐ๋ ˆ๋“œ, ์‚ฌ์šฉ ์“ฐ๋ ˆ๋“œ ์ˆ˜๋ฅผ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๋ฉ”ํŠธ๋ฆญ ํ™•์ธ ๊ฐ€๋Šฅ

      server:
        tomcat:
          mbeanregistry:
            enabled: true
  • ๋ฐ์ดํ„ฐ ์†Œ์Šค ๋ฉ”ํŠธ๋ฆญ: DataSource, Connection Pool ๊ด€๋ จ ๋ฉ”ํŠธ๋ฆญ ์ •๋ณด jdbc.connections.

    • ์ตœ๋Œ€ ์ปค๋„ฅ์…˜, ์ตœ์†Œ ์ปค๋„ฅ์…˜, ํ™œ์„ฑ ์ปค๋„ฅ์…˜, ๋Œ€๊ธฐ ์ปค๋„ฅ์…˜ ์ˆ˜ ๋“ฑ ํ™•์ธ ๊ฐ€๋Šฅ

  • ๋กœ๊ทธ ๋ฉ”ํŠธ๋ฆญ : logback ๋กœ๊ทธ์— ๋Œ€ํ•œ ๋ฉ”ํŠธ๋ฆญ ์ •๋ณด

    • trace, debug, info, warn, error ๊ฐ ๋กœ๊ทธ ๋ ˆ๋ฒจ์— ๋”ฐ๋ฅธ ๋กœ๊ทธ ์ˆ˜ ํ™•์ธ ๊ฐ€๋Šฅ

  • ๊ธฐํƒ€

    • HTTP ํด๋ผ์ด์–ธํŠธ ๋ฉ”ํŠธ๋ฆญ(RestTemplate , WebClient)

    • ์บ์‹œ ๋ฉ”ํŠธ๋ฆญ

    • ์ž‘์—… ์‹คํ–‰๊ณผ ์Šค์ผ€์ค„ ๋ฉ”ํŠธ๋ฆญ

    • ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”ํŠธ๋ฆญ

    • ๋ชฝ๊ณ DB ๋ฉ”ํŠธ๋ฆญ

    • ๋ ˆ๋””์Šค ๋ฉ”ํŠธ๋ฆญ

  • ์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ

ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค & ๊ทธ๋ผํŒŒ๋‚˜

  • ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค : ๋ฉ”ํŠธ๋ฆญ์„ ์ง€์†ํ•ด์„œ ์ˆ˜์ง‘ํ•˜๊ณ  DB์— ์ €์žฅํ•˜๋Š” ์—ญํ• 

  • ๊ทธ๋ผํŒŒ๋‚˜ : ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ž˜ํ”„๋กœ ๋ณด์—ฌ์ฃผ๋Š” ํˆด

    • ๋‹ค์–‘ํ•œ ๊ทธ๋ž˜ํ”„๋ฅผ ์ œ๊ณตํ•˜๊ณ , ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๋ฅผ ํฌํ•จํ•œ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ์†Œ์Šค ์ง€์›

\1. ์Šคํ”„๋ง ๋ถ€ํŠธ ์•ก์ธ„์—์ดํ„ฐ, ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ˆ˜ ๋งŽ์€ ๋ฉ”ํŠธ๋ฆญ ์ž๋™ ์ƒ์„ฑ

  • ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ๊ตฌํ˜„์ฒด๋Š” ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๊ฐ€ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ํฌ๋ฉง์œผ๋กœ ๋ฉ”ํŠธ๋ฆญ์„ ์ƒ์„ฑ

\2. ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๋Š” ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ๋ฉ”ํŠธ๋ฆญ์„ ์ง€์†ํ•ด์„œ ์ˆ˜์ง‘

\3. ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๋Š” ์ˆ˜์ง‘ํ•œ ๋ฉ”ํŠธ๋ฆญ์„ ๋‚ด๋ถ€ DB์— ์ €์žฅ

\4. ์‚ฌ์šฉ์ž๋Š” ๊ทธ๋ผํŒŒ๋‚˜ ๋Œ€์‹œ๋ณด๋“œ ํˆด์„ ํ†ตํ•ด ๊ทธ๋ž˜ํ”„๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ฉ”ํŠธ๋ฆญ์„ ์กฐํšŒ(ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๋ฅผ ํ†ตํ•ด ์กฐํšŒ)

ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค

๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๊ณ  ๋ณด๊ด€ํ•˜๋Š” DB

.

์„ค์น˜

  • https://prometheus.io/download/

  • https://github.com/prometheus/prometheus/releases/download/v2.42.0/prometheus-2.42.0.darwin-amd64.tar.gz

  • Mac OS: darwin

์‹คํ–‰

  • ์‹œ์Šคํ…œ ํ™˜๊ฒฝ์„ค์ • - ๋ณด์•ˆ ๋ฐ ๊ฐœ์ธ ์ •๋ณด ๋ณดํ˜ธ - ์ผ๋ฐ˜ - ํ™•์ธ ์—†์ด ํ—ˆ์šฉ

  • terminal - ./prometheus

  • http://localhost:9090/

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •

    • ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”ํŠธ๋ฆญ์„ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก, ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ํฌ๋ฉง์— ๋งž์ถ”์–ด ๋ฉ”ํŠธ๋ฆญ ์ƒ์„ฑ

    • ๊ฐ ๋ฉ”ํŠธ๋ฆญ๋“ค์€ ๋‚ด๋ถ€์—์„œ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ ์ธก์ •๋˜์–ด ์–ด๋–ค ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ• ์ง€๋งŒ ์ง€์ •

      // ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ ์•ก์ธ„์—์ดํ„ฐ๊ฐ€ ์ž๋™์œผ๋กœ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ๊ตฌํ˜„์ฒด๋ฅผ ๋“ฑ๋กํ•ด์„œ ๋™์ž‘ํ•˜๋„๋ก ์„ค์ •
      implementation 'io.micrometer:micrometer-registry-prometheus'
    • ์•ก์ธ„์—์ดํ„ฐ์— ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์ž๋™ ์ถ”๊ฐ€

      • /actuator/prometheus

  • ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ์„ค์ •

    • ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”ํŠธ๋ฆญ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์ˆ˜์ง‘ํ•˜๋„๋ก ์„ค์ •

์ˆ˜์ง‘ ์„ค์ •

prometheus.yml

scrape_configs:
 - job_name: "prometheus"
   static_configs:
     - targets: ["localhost:9090"]
 # ํ•˜๋‹จ ์ถ”๊ฐ€
 - job_name: "spring-actuator" # ์ˆ˜์ง‘ํ•˜๋Š” ์ž„์˜ ์ด๋ฆ„
   metrics_path: '/actuator/prometheus' # ์ˆ˜์ง‘ ๊ฒฝ๋กœ ์ง€์ •(1์ดˆ์— ํ•œ ๋ฒˆ์”ฉ ํ˜ธ์ถœํ•ด์„œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘)
   scrape_interval: 1s # ์ˆ˜์ง‘ ์ฃผ๊ธฐ (10s~1m ๊ถŒ์žฅ)
   static_configs: # ์ˆ˜์ง‘ํ•  ์„œ๋ฒ„ ์ •๋ณด(IP, PORT)
     - targets: ['localhost:8080']

http://localhost:9090/

  • ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค ๋ฉ”๋‰ด -> Status -> Configuration, Targets ์—์„œ ์ถ”๊ฐ€ํ•œ ์„ค์ • ํ™•์ธ

์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ

  • ๊ธฐ๋ณธ๊ธฐ๋Šฅ

    • Table: Evaluation time ์„ ์ˆ˜์ •ํ•ด์„œ ๊ณผ๊ฑฐ ์‹œ๊ฐ„ ์กฐํšŒ

    • Graph: ๋ฉ”ํŠธ๋ฆญ์„ ๊ทธ๋ž˜ํ”„๋กœ ์กฐํšŒ

  • ํ•„ํ„ฐ: ๋ ˆ์ด๋ธ” ๊ธฐ์ค€์œผ๋กœ ํ•„ํ„ฐ ์‚ฌ์šฉ. ์ค‘๊ด„ํ˜ธ({}) ๋ฌธ๋ฒ• ์‚ฌ์šฉ

    • ๋ ˆ์ด๋ธ” ์ผ์น˜ ์—ฐ์‚ฐ์ž

      • = : ์ œ๊ณต๋œ ๋ฌธ์ž์—ด๊ณผ ์ •ํ™•ํžˆ ๋™์ผํ•œ ๋ ˆ์ด๋ธ” ์„ ํƒ

      • != : ์ œ๊ณต๋œ ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์ง€ ์•Š์€ ๋ ˆ์ด๋ธ” ์„ ํƒ

      • =~ : ์ œ๊ณต๋œ ๋ฌธ์ž์—ด๊ณผ ์ •๊ทœ์‹ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ด๋ธ” ์„ ํƒ

      • !~ : ์ œ๊ณต๋œ ๋ฌธ์ž์—ด๊ณผ ์ •๊ทœ์‹ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๋ ˆ์ด๋ธ” ์„ ํƒ

      example.
      
      uri=/log , method=GET ์กฐ๊ฑด์œผ๋กœ ํ•„ํ„ฐ
        -> http_server_requests_seconds_count{uri="/log", method="GET"}
      
      /actuator/prometheus ๋Š” ์ œ์™ธํ•œ ์กฐ๊ฑด์œผ๋กœ ํ•„ํ„ฐ
        -> http_server_requests_seconds_count{uri!="/actuator/prometheus"}
      
      method ๊ฐ€ GET, POST ์ธ ๊ฒฝ์šฐ๋ฅผ ํฌํ•จํ•ด์„œ ํ•„ํ„ฐ
        -> http_server_requests_seconds_count{method=~"GET|POST"}
      
      /actuator ๋กœ ์‹œ์ž‘ํ•˜๋Š” uri ๋Š” ์ œ์™ธํ•œ ์กฐ๊ฑด์œผ๋กœ ํ•„ํ„ฐ
        -> http_server_requests_seconds_count{uri!~"/actuator.*"}
  • ์—ฐ์‚ฐ์ž ์ฟผ๋ฆฌ์™€ ํ•จ์ˆ˜

    • + (๋ง์…ˆ), - (๋นผ๊ธฐ), * (๊ณฑ์…ˆ), / (๋ถ„ํ• ), % (๋ชจ๋“ˆ๋กœ), ^ (์Šน์ˆ˜/์ง€์ˆ˜)

    • sum: ํ•ฉ๊ณ„

      • sum(http_server_requests_seconds_count)

    • sum by: SQL group by ์™€ ์œ ์‚ฌ

      • sum by(method, status)(http_server_requests_seconds_count)

    • count: ๋ฉ”ํŠธ๋ฆญ ์ž์ฒด์˜ ์ˆ˜ ์นด์šดํŠธ

      • count(http_server_requests_seconds_count)

    • topk: ์ƒ์œ„ ๋ฉ”ํŠธ๋ฆญ ์กฐํšŒ

      • topk(3, http_server_requests_seconds_count)

    • ์˜คํ”„์…‹ ์ˆ˜์ •์ž

      • http_server_requests_seconds_count offset 10m

      • ํ˜„์žฌ ๊ธฐ์ค€ ํŠน์ • ๊ณผ๊ฑฐ ์‹œ์ ์˜ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜

    • ๋ฒ”์œ„ ๋ฒกํ„ฐ ์„ ํƒ๊ธฐ

      • http_server_requests_seconds_count[1m]

      • ์ง€๋‚œ 1๋ถ„๊ฐ„์˜ ๋ชจ๋“  ๊ธฐ๋ก๊ฐ’ ์„ ํƒ

      • ์ฐจํŠธ์— ๋ฐ”๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์—†๊ณ , ๋ฐ์ดํ„ฐ๋กœ๋Š” ํ™•์ธ ๊ฐ€๋Šฅ

      • ๊ฒฐ๊ณผ๋ฅผ ์ฐจํŠธ์— ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•ฝ๊ฐ„์˜ ๊ฐ€๊ณต ํ•„์š”

๊ฒŒ์ด์ง€์™€ ์นด์šดํ„ฐ

๊ฒŒ์ด์ง€(Gauge)

  • ์ž„์˜๋กœ ์˜ค๋ฅด๋‚ด์ผ ์ˆ˜ ์žˆ๋Š” ๊ฐ’(ex. CPU ์‚ฌ์šฉ๋Ÿ‰, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ์‚ฌ์šฉ์ค‘์ธ ์ปค๋„ฅ์…˜)

์นด์šดํ„ฐ(Counter)

  • ๋‹จ์ˆœํ•˜๊ฒŒ ์ฆ๊ฐ€ํ•˜๋Š” ๋‹จ์ผ ๋ˆ„์  ๊ฐ’(ex. HTTP ์š”์ฒญ ์ˆ˜, ๋กœ๊ทธ ๋ฐœ์ƒ ์ˆ˜)

  • increase()

    • ์ง€์ •ํ•œ ์‹œ๊ฐ„ ๋‹จ์œ„๋ณ„๋กœ ์ฆ๊ฐ€ ํ™•์ธ

    • increase(http_server_requests_seconds_count{uri="/log"}[1m])

  • rate()

    • ๋ฒ”์œ„ ๋ฐฑํ„ฐ์—์„œ ์ดˆ๋‹น ํ‰๊ท  ์ฆ๊ฐ€์œจ ๊ณ„์‚ฐ

  • irate()

    • rate ์™€ ์œ ์‚ฌ. ๋ฒ”์œ„ ๋ฒกํ„ฐ์—์„œ ์ดˆ๋‹น ์ˆœ๊ฐ„ ์ฆ๊ฐ€์œจ ๊ณ„์‚ฐ

๊ธฐ๋ณธ๊ธฐ๋Šฅ

์—ฐ์‚ฐ์ž

ํ•จ์ˆ˜

๊ทธ๋ผํŒŒ๋‚˜

  • https://grafana.com/grafana/download

  • https://dl.grafana.com/enterprise/release/grafana-enterprise-9.3.6.darwin-amd64.tar.gz

์‹คํ–‰

  • ์••์ถ•์„ ํ’€๊ณ  bin ํด๋” ์ด๋™ ํ›„ ./grafana-server

  • http://localhost:3000/

  • ์ดˆ๊ธฐ ๊ณ„์ • -> admin/admin

์—ฐ๋™

  • ๋ฐ์ดํ„ฐ์†Œ์Šค ์ถ”๊ฐ€

    • ์„ค์ •(Configuration) -> Data sources -> Add data source -> Prometheus

    • URL ์ •๋ณด: http://localhost:9090

    • Save & test

๋Œ€์‹œ๋ณด๋“œ

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

    • \1. ์™ผ์ชฝ Dashboards ๋ฉ”๋‰ด

    • \2. New ๋ฒ„ํŠผ -> New Dashboard

    • \3. ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ Save dashboard ์ €์žฅ

    • \4. Dashboard name ์ž…๋ ฅ

๋งคํŠธ๋ฆญ ํ™œ์šฉ

๋น„์ฆˆ๋‹ˆ์Šค์— ํŠนํ™”๋œ ๋ถ€๋ถ„(์ฃผ๋ฌธ์ˆ˜, ์ทจ์†Œ์ˆ˜, ์žฌ๊ณ  ์ˆ˜๋Ÿ‰ ๋“ฑ)์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก ๊ฐ€๋Šฅ

MeterRegistry

  • ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํ•ต์‹ฌ ์ปดํฌ๋„ŒํŠธ

  • ์Šคํ”„๋ง์„ ํ†ตํ•ด์„œ ์ฃผ์ž… ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๊ณ , ์นด์šดํ„ฐ, ๊ฒŒ์ด์ง€ ๋“ฑ์„ ๋“ฑ๋ก

Counter

  • ๋‹จ์กฐ๋กญ๊ฒŒ ์ฆ๊ฐ€ํ•˜๋Š” ๋‹จ์ผ ๋ˆ„์  ์ธก์ • ํ•ญ๋ชฉ

    • ๋‹จ์ผ ๊ฐ’, ๋ณดํ†ต ํ•˜๋‚˜์”ฉ ์ฆ๊ฐ€, ๋ˆ„์ ์ด๋ฏ€๋กœ ์ „์ฒด ๊ฐ’์„ ํฌํ•จ(total)

  • ๊ฐ’์„ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ 0์œผ๋กœ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ ๊ฐ€๋Šฅ

  • ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ์—์„œ ๊ฐ’์„ ๊ฐ์†Œํ•˜๋Š” ๊ธฐ๋Šฅ๋„ ์ง€์›ํ•˜์ง€๋งŒ, ๋ชฉ์ ์— ๋งž์ง€ ์•Š์Œ

  • ์˜ˆ) HTTP ์š”์ฒญ์ˆ˜ (increase() , rate() ํ™œ์šฉ)

Gauge

  • ์ž„์˜๋กœ ์˜ค๋ฅด๋‚ด๋ฆด ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ์ˆซ์ž ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฉ”ํŠธ๋ฆญ

  • ๊ฐ’์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋ณด๋Š”๋ฐ ์‚ฌ์šฉ(๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐ์†Œ)

  • ์นด์šดํ„ฐ, ๊ฒŒ์ด์ง€์˜ ์‰ฌ์šด ๊ตฌ๋ถ„์„ ์œ„ํ•ด ๊ฐ’์ด ๊ฐ์†Œํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€๋ฅผ ๊ณ ๋ฏผํ•ด๋ณด์ž

  • ex. ์ฐจ๋Ÿ‰ ์†๋„, CPU ์‚ฌ์šฉ๋Ÿ‰, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ..

Timer

  • ์‹œ๊ฐ„ ์ธก์ •์— ์‚ฌ์šฉ

  • ์‹คํ–‰ ์‹œ๊ฐ„๋„ ํ•จ๊ป˜ ์ธก์ • ๊ฐ€๋Šฅ(์นด์šดํ„ฐ์™€ ์œ ์‚ฌ)

  • ์•„๋ž˜ ๋‚ด์šฉ์„ ํ•œ ๋ฒˆ์— ์ธก์ •

    • seconds_count : ๋ˆ„์  ์‹คํ–‰ ์ˆ˜() - counter

      • increase(my_order_seconds_count{method="order"}[1m])

    • seconds_sum : ์‹คํ–‰ ์‹œ๊ฐ„์˜ ํ•ฉ - sum

    • seconds_max : ์ตœ๋Œ€ ์‹คํ–‰ ์‹œ๊ฐ„(๊ฐ€์žฅ ์˜ค๋ž˜๊ฑธ๋ฆฐ ์‹คํ–‰ ์‹œ๊ฐ„) - gauge

      • 1~3๋ถ„ ๋งˆ๋‹ค ์ตœ๋Œ€ ์‹คํ–‰ ์‹œ๊ฐ„์„ ๋‹ค์‹œ ๊ณ„์‚ฐ(๋‚ด๋ถ€์— ํƒ€์ž„ ์œˆ๋„์šฐ๋ผ๋Š” ๊ฐœ๋… ์กด์žฌ)

      • my_order_seconds_max

    • seconds_sum / seconds_count = ํ‰๊ท  ์‹คํ–‰์‹œ๊ฐ„

      • increase(my_order_seconds_sum[1m]) / increase(my_order_seconds_count[1m])

Tag, ๋ ˆ์ด๋ธ”

  • ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜๋ˆ ์„œ ํ™•์ธ ๊ฐ€๋Šฅ

  • ์นด๋””๋„๋ฆฌํ‹ฐ(ํŠน์ • ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์˜ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์˜ ๊ฐœ์ˆ˜)๊ฐ€ ๋‚ฎ์œผ๋ฉด์„œ ๊ทธ๋ฃนํ™” ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์œ„์— ์‚ฌ์šฉ

    • ex. ์„ฑ๋ณ„, ์ฃผ๋ฌธ ์ƒํƒœ, ๊ฒฐ์ œ ์ˆ˜๋‹จ[์‹ ์šฉ์นด๋“œ, ํ˜„๊ธˆ] ..

    • ์นด๋””๋„๋ฆฌํ‹ฐ๊ฐ€ ๋†’์œผ๋ฉด ๋ถˆ๊ฐ€ - ex. ์ฃผ๋ฌธ๋ฒˆํ˜ธ, PK ..

๋ชจ๋‹ˆํ„ฐ๋ง ํ™˜๊ฒฝ ๊ตฌ์„ฑ ํŒ

๋ชจ๋‹ˆํ„ฐ๋ง 3๋‹จ๊ณ„

  • ๋Œ€์‹œ๋ณด๋“œ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”์ 

  • ๋กœ๊ทธ

.

๋Œ€์‹œ๋ณด๋“œ

์ „์ฒด๋ฅผ ํ•œ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ๋†’์€ ๋ทฐ

์ œํ’ˆ

  • ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ, ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค, ๊ทธ๋ผํŒŒ๋‚˜ ๋“ฑ

๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์ƒ

  • ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ (CPU, ๋ฉ”๋ชจ๋ฆฌ)

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ (ํ†ฐ์บฃ ์“ฐ๋ ˆ๋“œ ํ’€, DB ์ปค๋„ฅ์…˜ ํ’€, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ˜ธ์ถœ ์ˆ˜)

  • ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”ํŠธ๋ฆญ (์ฃผ๋ฌธ์ˆ˜, ์ทจ์†Œ์ˆ˜)

.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”์ 

์ฃผ๋กœ ๊ฐ๊ฐ์˜ HTTP ์š”์ฒญ์„ ์ถ”์ , ์ผ๋ถ€๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ ๋ถ„์‚ฐ ์ถ”์ 

์ œํ’ˆ

  • ํ•€ํฌ์ธํŠธ(์˜คํ”ˆ์†Œ์Šค) - ์ถ”์ฒœ

  • ์Šค์นด์šฐํŠธ(์˜คํ”ˆ์†Œ์Šค)

  • ์™€ํƒญ(์ƒ์šฉ)

  • ์ œ๋‹ˆํผ(์ƒ์šฉ)

.

๋กœ๊ทธ

  • ๊ฐ€์žฅ ์ž์„ธํ•œ ์ถ”์ , ์›ํ•˜๋Š”๋ฐ๋กœ ์ปค์Šคํ…€ ๊ฐ€๋Šฅ

  • ๊ฐ™์€ HTTP ์š”์ฒญ์„ ๋ฌถ์–ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์ค‘์š”(MDC ์ ์šฉ)

ํŒŒ์ผ๋กœ ์ง์ ‘ ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๊ฒฝ์šฐ

  • ์ผ๋ฐ˜ ๋กœ๊ทธ์™€ ์—๋Ÿฌ ๋กœ๊ทธ๋Š” ํŒŒ์ผ์„ ๊ตฌ๋ถ„ํ•ด์„œ -> ์—๋Ÿฌ ๋กœ๊ทธ๋งŒ ํ™•์ธํ•ด์„œ ๋ฌธ์ œ๋ฅผ ๋ฐ”๋กœ ์ •๋ฆฌ ๊ฐ€๋Šฅ

ํด๋ผ์šฐ๋“œ์— ๋กœ๊ทธ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ

  • ๊ฒ€์ƒ‰์ด ์ž˜ ๋˜๋„๋ก ๊ตฌ๋ถ„


์ฐธ๊ณ ..

  • ๋ชจ๋‹ˆํ„ฐ๋ง์€ ๊ฐ๊ฐ ์šฉ๋„๊ฐ€ ๋‹ค๋ฅด๋‹ค. ๊ด€์ฐฐ์„ ํ•  ๋•Œ๋Š” ์ „์ฒด์—์„œ ์ ์  ์ข๊ฒŒ

  • ํ•€ํฌ์ธํŠธ ๊ฐ•์ถ”. ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค ๋ถ„์‚ฐ ๋ชจ๋‹ˆํ„ฐ๋ง, ๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ ๋Œ€์‘ ๊ฐ€๋Šฅ

์•Œ๋žŒ

  • ๋ชจ๋‹ˆํ„ฐ๋ง ํˆด์—์„œ ์ผ์ • ์ด์ƒ ์ˆ˜์น˜๊ฐ€ ๋„˜์–ด๊ฐ€๋ฉด, ์Šฌ๋ž™, ๋ฌธ์ž ๋“ฑ ์—ฐ๋™

์•Œ๋žŒ์€ 2๊ฐ€์ง€ ์ข…๋ฅ˜(๊ฒฝ๊ณ , ์‹ฌ๊ฐ)๋กœ ๊ผญ ๊ตฌ๋ถ„ํ•ด์„œ ๊ด€๋ฆฌ

  • ๊ฒฝ๊ณ ๋Š” ํ•˜๋ฃจ 1๋ฒˆ ์ •๋„ ์‚ฌ๋žŒ์ด ์ง์ ‘ ํ™•์ธํ•ด๋„ ๋˜๋Š” ์ˆ˜์ค€ (์‚ฌ๋žŒ์ด ๋“ค์–ด๊ฐ€์„œ ํ™•์ธ)

  • ์‹ฌ๊ฐ์€ ์ฆ‰์‹œ ํ™•์ธ ํ•„์š”. ์Šฌ๋ž™ ์•Œ๋ฆผ, ๋ฌธ์ž, ์ „ํ™”

ex. ๊ฒฝ๊ณ , ์‹ฌ๊ฐ ์•Œ๋ฆผ ๊ธฐ์ค€

  • ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰ 70% ๊ฒฝ๊ณ 

  • ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰ 80% ์‹ฌ๊ฐ

  • CPU ์‚ฌ์šฉ๋Ÿ‰ 40% ๊ฒฝ๊ณ 

  • CPU ์‚ฌ์šฉ๋Ÿ‰ 50% ์‹ฌ๊ฐ

๊ฒฝ๊ณ ์™€ ์‹ฌ๊ฐ์„ ์ž˜ ๋‚˜๋ˆ„์–ด์„œ ์—…๋ฌด์™€ ์‚ถ์— ๋ฐฉํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋„๋ก ํ•˜์ž.

Last updated