์นด์šดํ„ฐ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง (์Šคํ”„๋ง, ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค, ๊ทธ๋ผํŒŒ๋‚˜)

2023. 5. 22. 16:07ใ†์ธํ”„๋Ÿฐ/์Šคํ”„๋ง ๋ถ€ํŠธ - ํ•ต์‹ฌ ์›๋ฆฌ์™€ ํ™œ์šฉ

728x90

 

์Šคํ”„๋ง & ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค & ๊ทธ๋ผํŒŒ๋‚˜ (๊ทธ๋ผํŒŒ๋‚˜ ์„ค์น˜, ์—ฐ๋™, ์‚ฌ์šฉ ๋ฐฉ๋ฒ•) (tistory.com)

 

์Šคํ”„๋ง & ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค & ๊ทธ๋ผํŒŒ๋‚˜ (๊ทธ๋ผํŒŒ๋‚˜ ์„ค์น˜, ์—ฐ๋™, ์‚ฌ์šฉ ๋ฐฉ๋ฒ•)

์Šคํ”„๋ง & ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค (์„ค์น˜, ์„ค์ •, ๊ธฐ๋ณธ ๊ธฐ๋Šฅ) (tistory.com) ์Šคํ”„๋ง & ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค (์„ค์น˜, ์„ค์ •, ๊ธฐ๋ณธ ๊ธฐ๋Šฅ) ์Šคํ”„๋ง ๋ชจ๋‹ˆํ„ฐ๋ง (์•ก์ธ„์—์ดํ„ฐ, ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ, ๋ฉ”ํŠธ๋ฆญ, ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค, ๊ทธ๋ผํŒŒ๋‚˜) (tistory.c

hyejin.tistory.com

 

์ด์ „ ๊ธ€์„ ๋ณด๋ฉด cpu ์‚ฌ์šฉ๋Ÿ‰, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, db ์ปค๋„ฅ์…˜ ํ’€ ๋“ฑ ๊ฐ™์€ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ์ˆ  ๋ฉ”ํŠธ๋ฆญ๋“ค์€ ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด ์žˆ์–ด์„œ ์ด ๋ฉ”ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•ด์„œ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. 

 

๊ทธ๋Ÿฐ๋ฐ cpu ์‚ฌ์šฉ๋Ÿ‰, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋“ฑ์„ ๋„˜์–ด์„œ ๋น„์ง€๋‹ˆ์Šค์— ํŠนํ™”๋œ ๋ถ€๋ถ„(์ฃผ๋ฌธ ์ˆ˜, ์ทจ์†Œ ์ˆ˜ ๋“ฑ..)์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด? 

์ด๋Ÿฐ ๋ถ€๋ถ„๋“ค์€ cpu ์‚ฌ์šฉ๋Ÿ‰์ด๋‚˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์œผ๋กœ๋Š” ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ๋น„์ง€๋‹ˆ์Šค ๋ฉ”ํŠธ๋ฆญ์€ ์ง์ ‘ ๋“ฑ๋กํ•˜๊ณ  ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. 

 

 

0๏ธโƒฃ ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ 

* ์ฃผ๋ฌธ ์ˆ˜, ์ทจ์†Œ ์ˆ˜ 

: ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ•˜๋ฉด ์ฃผ๋ฌธ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ , ์ƒํ’ˆ์„ ์ทจ์†Œํ•˜๋ฉด ์ฃผ๋ฌธ ์ˆ˜๋Š” ์œ ์ง€๋˜๊ณ , ์ทจ์†Œ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค. 

 

* ์žฌ๊ณ ์ˆ˜๋Ÿ‰ 

: ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ•˜๋ฉด ์žฌ๊ณ  ์ˆ˜๋Ÿ‰์ด ๊ฐ์†Œํ•˜๊ณ , ์ƒํ’ˆ์„ ์ทจ์†Œํ•˜๋ฉด ์žฌ๊ณ  ์ˆ˜๋Ÿ‰์ด ์ฆ๊ฐ€ํ•œ๋‹ค. 

 

* ์ฃผ๋ฌธ ์ˆ˜, ์ทจ์†Œ ์ˆ˜๋Š” ๊ณ„์† ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ์นด์šดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 

  ์žฌ๊ณ  ์ˆ˜๋Ÿ‰์€ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐ์†Œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒŒ์ด์ง€๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 

 

 

OrderService

public interface OrderService
{
   void order();
   
   void cancel();
   
   // AtomicInteger : ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” Integer
   AtomicInteger getStock();
}

๊ฐ„๋‹จํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ฃผ๋ฌธ, ์ทจ์†Œ, ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

OrderServiceV0 

@Slf4j
public class OrderServiceV0 implements OrderService
{
   
   private AtomicInteger stock = new AtomicInteger(100);
   
   @Override
   public void order()
   {
      log.info("์ฃผ๋ฌธ");
      stock.decrementAndGet();
   }
   
   @Override
   public void cancel()
   {
      log.info("์ทจ์†Œ");
      stock.incrementAndGet();
   }
   
   @Override
   public AtomicInteger getStock()
   {
      return stock;
   }
}

์žฌ๊ณ  ์ดˆ๊ธฐ ์ˆ˜๋Ÿ‰์„ 100์œผ๋กœ ์„ค์ •ํ•œ๋‹ค. 

 

 

OrderConfigV0

@Configuration
public class OrderConfigV0
{
   @Bean
   OrderService orderService()
   {
      return new OrderServiceV0();
   }
}

OrderService๋ฅผ ์ง์ ‘ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.  

 

 

OrderController

@Slf4j
@RestController
public class OrderController
{
   public final OrderService orderService;
   
   public OrderController(OrderService orderService)
   {
      this.orderService = orderService;
   }
   
   @GetMapping("/order")
   public String order()
   {
      log.info("order");
      orderService.order();
      return "order";
   }
   
   @GetMapping("/cancel")
   public String cancel()
   {
      log.info("cancel");
      orderService.cancel();
      return "cancel";
   }
   
   @GetMapping("/stock")
   public int stock()
   {
      log.info("stock");
      return orderService.getStock().get();
   }
   
}

 

ActuatorApplication

@Import(OrderConfigV0.class)
@SpringBootApplication(scanBasePackages = "hello.controller")
public class ActuatorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }
}

OrderServiceVx(V0, V1... ์ด๋Ÿฐ์‹์œผ๋กœ ๋Š˜์–ด๋‚  ์˜ˆ์ •) ๊ฐ€ ๋ชจ๋‘ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์œ ๋Œ€์ƒ์ด ๋˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์˜ ๋Œ€์ƒ์€ hello.controller๋กœ ์ œํ•œํ•˜๊ณ , import๋ฅผ OrderConfigV0์œผ๋กœ ์„ค์ • ํŒŒ์ผ์„ ๋“ฑ๋กํ•œ๋‹ค. 

 

 

(์—ฌ๊ธฐ๊นŒ์ง€๋Š” ๋ฉ”ํŠธ๋ฆญ๊ณผ ๊ด€๋ จ์—†๋Š” ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ์ด๋‹ค.)

 

 

 

1๏ธโƒฃ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก 1 - ์นด์šดํ„ฐ 

์ฃผ๋ฌธ์ˆ˜์™€ ์ทจ์†Œ์ˆ˜๋Š” ๊ณ„์† ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์นด์šดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ๋ฐ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฉ”ํŠธ๋ฆญ์„ ์ง์ ‘ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

MeterRegistry

: ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํ•ต์‹ฌ ์ปดํฌ๋„ŒํŠธ๋กœ ์Šคํ”„๋ง์„ ํ†ตํ•ด์„œ ์ฃผ์ž…๋ฐ›๊ณ  ์ด๊ณณ์— ์นด์šดํ„ฐ, ๊ฒŒ์ด์ง€ ๋“ฑ์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

Counter ์นด์šดํ„ฐ 

: ๋‹จ์กฐ๋กญ๊ฒŒ ์ฆ๊ฐ€ํ•˜๋Š” ๋‹จ์ผ ๋ˆ„์  ์ธก์ •ํ•ญ๋ชฉ -> ๋ˆ„์ ์ด๋ฏ€๋กœ ์ „์ฒด ๊ฐ’์„ ํฌํ•จํ•œ๋‹ค.  

์นด์šดํ„ฐ๋Š” ๊ฐ’์„ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. 

ex) HTTP ์š”์ฒญ์ˆ˜ 

 

 

OrderServiceV1 

@Slf4j
public class OrderServiceV1 implements OrderService
{
   private final MeterRegistry meterRegistry;
   private AtomicInteger stock = new AtomicInteger(100);
   
   public OrderServiceV1(MeterRegistry meterRegistry)
   {
      this.meterRegistry = meterRegistry;
   }
   
   @Override
   public void order()
   {
      log.info("์ฃผ๋ฌธ");
      stock.decrementAndGet();
      
      Counter.builder("my.order")
            .tag("class", this.getClass().getName())
            .tag("method", "order")
            .description("order")
            .register(meterRegistry).increment();
   }
   
   @Override
   public void cancel()
   {
      log.info("์ทจ์†Œ");
      stock.incrementAndGet();
      
      Counter.builder("my.order")
            .tag("class", this.getClass().getName())
            .tag("method", "cancel")
            .description("cancel")
            .register(meterRegistry).increment();
   }
   
   @Override
   public AtomicInteger getStock()
   {
      return stock;
   }
}

Counter.builder(name) ์„ ํ†ตํ•ด์„œ ์นด์šดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  name์—๋Š” ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ค€๋‹ค. 

tag๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ”„๋กœ๋ฉ”ํ…Œ์šฐ์Šค์—์„œ ํ•„ํ„ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ ˆ์ด๋ธ”๋กœ ์‚ฌ์šฉํ•œ๋‹ค. -> ์ฃผ๋ฌธ๊ณผ ์ทจ์†Œ์˜ ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„์€ ๊ฐ™๊ณ , tag์„ ํ†ตํ•ด์„œ ๊ตฌ๋ถ„ํ•˜๋„๋ก ์„ค์ • 

register(meterRegistry) ๋งŒ๋“  ์นด์šดํ„ฐ๋ฅผ ์ด์ œ MeterRegistry์— ๋“ฑ๋กํ•ด์ฃผ๋ฉด ์‹ค์ œ ๋™์ž‘ํ•œ๋‹ค. 

increment() ๋ฅผ ํ•˜๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋งˆ๋‹ค ์นด์šดํ„ฐ ๊ฐ’์ด ํ•˜๋‚˜ ์ฆ๊ฐ€ํ•œ๋‹ค. 

 

 

OrderConfigV1

@Configuration
public class OrderConfigV1
{
   @Bean
   OrderService orderService(MeterRegistry meterRegistry)
   {
      return new OrderServiceV1(meterRegistry);
   }
}

 

ActuatorApplication

@Import(OrderConfigV1.class)
@SpringBootApplication(scanBasePackages = "hello.controller")
public class ActuatorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }
    
}

 

 

* ์‹คํ–‰

http://localhost:8080/order

http://localhost:8080/cancel 

 

์ฃผ๋ฌธ๊ณผ ์ทจ์†Œ๋ฅผ ์‹คํ–‰ํ•œ ๋‹ค์Œ์— ๋ฉ”ํŠธ๋ฆญ์„ ํ™•์ธํ•ด๋ณด๋ฉด 

http://localhost:8080/actuator/metrics/my.order 

my.order ๊ฒ€์ƒ‰ 

 

http://localhost:8080/actuator/prometheus

my_order ๊ฒ€์ƒ‰ 

 

์ฃผ๋ฌธ์ˆ˜, ์ทจ์†Œ์ˆ˜ ๋ฉ”ํŠธ๋ฆญ์ด ๋“ฑ๋ก๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

http://localhost:8080/actuator/metrics/my.order?tag=method:order

์ด๋Ÿฐ์‹์œผ๋กœ ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ํŠน์ • ๋ฉ”์„œ๋“œ๋งŒ ํ•„ํ„ฐํ•ด์„œ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

* ๊ทธ๋ผํŒŒ๋‚˜ ๋“ฑ๋ก : ์ฃผ๋ฌธ์ˆ˜, ์ทจ์†Œ์ˆ˜

(/order, /cancel ๋ช‡๋ฒˆ ํ˜ธ์ถœํ•œ ๋‹ค์Œ, ํ™•์ธ ๊ฐ€๋Šฅ) 

 

์นด์šดํ„ฐ๋Š” ์ €๋ฒˆ๊ธ€์—์„œ๋„ ๋ฐฐ์› ๋“ฏ์ด ๊ณ„์† ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ ๊ฐ’๋งŒ ์ฟผ๋ฆฌํ•˜๋ฉด ๊ณ„์† ์ฆ๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋Š” ๊ทธ๋ž˜ํ”„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

๋”ฐ๋ผ์„œ ์–ธ์ œ ์–ผ๋งˆ๋‚˜ ์ฆ๊ฐ€ํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” increase(), rate() ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. 

 

 

 

2๏ธโƒฃ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก 2 - @Counted 

์œ„์—์„œ ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก ํ•˜๋Š” ๊ฑธ ๋ณด๋ฉด ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๋„ ๋งŽ๊ณ , ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์— ๋ณด๋ฉด ๋ฉ”ํŠธ๋ฆญ ๋“ฑ๋ก ์ฝ”๋“œ๊ฐ€ ๋” ๋งŽ์ด ์ฐจ์ง€ํ•˜๊ณ  ์žˆ๋‹ค. 

์ด๋Ÿด๋•Œ ๋ฐ”๋กœ AOP ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค..!!! 

์ง์ ‘ AOP๋ฅผ ๋งŒ๋“ค๊ณ  ๋“ฑ๋กํ•ด์„œ ์ ์šฉํ•ด๋„ ๋˜์ง€๋งŒ ๋งˆ์ดํฌ๋กœ๋ฏธํ„ฐ๋Š” ์ด๋ฏธ AOP ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋ชจ๋‘ ๊ฐ–์ถฐ๋†จ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ใ…Žใ…Ž 

 

 

OrderServiceV2

@Slf4j
public class OrderServiceV2 implements OrderService
{
   private AtomicInteger stock = new AtomicInteger(100);
   
   @Counted("my.order")
   @Override
   public void order()
   {
      log.info("์ฃผ๋ฌธ");
      stock.decrementAndGet();
   }
   
   @Counted("my.order")
   @Override
   public void cancel()
   {
      log.info("์ทจ์†Œ");
      stock.incrementAndGet();
      
   }
   
   @Override
   public AtomicInteger getStock()
   {
      return stock;
   }
}

@Counted ์• ๋…ธํ…Œ์ด์…˜์„ ์ธก์ •์„ ์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ์— ์ ์šฉํ•˜๋ฉด ๋œ๋‹ค. 

์˜ˆ์ œ์—์„œ๋Š” ์ฃผ๋ฌธ๊ณผ ์ทจ์†Œ ๋ฉ”์„œ๋“œ์— ์ง€์ •ํ•ด์คฌ๊ณ , ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„ "my.order"๋ฅผ ์ง€์ •ํ•ด์คฌ๋‹ค. 

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด tag์— method ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฅ˜ํ•ด์„œ ์ ์šฉํ•œ๋‹ค. 

 

 

OrderConfigV2

@Configuration
public class OrderConfigV2
{
   @Bean
   public OrderService orderService()
   {
      return new OrderServiceV2();
   }
   
   // CountedAspect๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š์œผ๋ฉด AOP๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค!
   @Bean
   public CountedAspect countedAspect(MeterRegistry meterRegistry)
   {
      return new CountedAspect(meterRegistry);
   }
}

โ— ์ฃผ์˜ํ•  ์ ์€ CountedAspect ๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š์œผ๋ฉด AOP๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š์œผ๋‹ˆ ๋ฐ˜๋“œ์‹œ ๋“ฑ๋กํ•˜์ž! 

 

 

ActuatorApplication 

@Import(OrderConfigV2.class)
@SpringBootApplication(scanBasePackages = "hello.controller")
public class ActuatorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActuatorApplication.class, args);
    }

}

 

 

* ์‹คํ–‰

http://localhost:8080/order

http://localhost:8080/cancel

์ฃผ๋ฌธ๊ณผ ์ทจ์†Œ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์‹คํ–‰ํ•ด์ฃผ์ž...(์ตœ์†Œ 1๋ฒˆ ์ด์ƒ์€ ์‹คํ–‰๋˜์–ด์•ผ ๋ฉ”ํŠธ๋ฆญํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค..!) 

 

http://localhost:8080/actuator/metrics/my.order

@Counted๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํƒœ๊ทธ ๊ฐ™์€ ๊ฑธ ์ ์šฉํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ๋„ result, exception, method, class์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ tag๋“ค์ด ์ž๋™์œผ๋กœ ์ ์šฉ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90