2023. 5. 22. 16:07ใ์ธํ๋ฐ/์คํ๋ง ๋ถํธ - ํต์ฌ ์๋ฆฌ์ ํ์ฉ
์ด์ ๊ธ์ ๋ณด๋ฉด 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๋ค์ด ์๋์ผ๋ก ์ ์ฉ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.