๐ Spring boot Actuator ์คํ๋ง ๋ถํธ ์ก์ถ์์ดํฐ API + Spring Cloud๋ฅผ ์ฌ์ฉํ ์์
๊ฐ์ #
Spirng boot ๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ฐ์ดํฐ๋ค์ด ๋ณ๊ฒฝ๋๊ฑฐ๋ yaml ์ด ๋ณ๊ฒฝ๋์์๋ ์๋ฒ๋ฅผ ์ฌ ๊ฐ๋์ํค๋ ๋ฐฉ๋ฒ ์ด์ธ์ ๋ฐ์ดํฐ ์ํ๋ฅผ ๋ถ๋ฌ์ค๋ ๋ฐฉ๋ฒ์ด ์์๊น? ๋ฐ๋ก Spring Actuator๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ์ค๋์ ๊ทธ Spring Actuator์ ๋ํด์ ์์๋ณด๊ฒ ๋ค.
๐ง Spring Actuator #
Spring Actuator๋ ๋ฌด์์ผ๊น?
Spring Actuator๋ ์คํ๋ง ๋ถํธ ํ๋ ์์ํฌ์์ ์ ๊ณต๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก์ ์คํ๋ง ํธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ํฐ๋ง์ด๋ ๋ฉํธ๋ฆญ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ HTTP์ JMX ์๋ ํฌ์ธํธ๋ฅผ ํตํด์ ์ ๊ณตํ๋ค.
๋ฉํธ๋ฆญ์ด๋?
์์คํ , ํ๋ก์ธ์ค, ์ ํ ๋๋ ์๋น์ค์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์ธก์ ํญ๋ชฉ์ด๋ ์งํ๋ค.
Spring Actuator๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ด๋ถ ํ์ธ์ด ๊ฐ๋ฅํ๋ฉฐ, ์ด๋ ์ ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋์ ์ ์ดํ ์ ์๊ฒ ํด์ค๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ํ๊ฒฝ์ ๊ตฌ์ฑ ์์ฑ
- ๋ก๊น ๋ ๋ฒจ
- ์ฌ์ฉ ์ค์ธ ๋ฉ๋ชจ๋ฆฌ
- ์ง์ ๋ ์๋ํฌ์ธํธ๊ฐ ๋ฐ์ ๋ฆฌํ์คํธ ํ์
- ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฑด๊ฐ ์ํ ์ ๋ณด
๐ฅย Spring Actuator API #
์คํ๋ง ์ก์ธ์์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์์กด์ฑ์ ์ถ๊ฐํด์ผํ๋ค.
implementation("org.springframework.boot:spring-boot-starter-actuator")
์คํ๋ง ์ก์ธ์์ดํฐ์ ์คํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋น๋๋๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ก์ธ์์ดํฐ ์๋ํฌ์ธํธ๋ก api๋ฅผ ์ฌ์ฉํ ์ ์๋ค.

๐จ Spring Cloud์ ํจ๊ป ์ฌ์ฉํ๋ ์์ #
spring cloud๋ฅผ ํตํด ๋ค๋ฅธ ์ ์ฅ์์ ์๋ yml๋ฅผ ์ฝ์ด returnํ๋ RestController Client Server์ ConfigServer๋ฅผ ๊ตฌ์ฑํ๊ณ yml์ ๊ฐ์ ์ ๋ฐ์ดํธํ์๋ ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์๋ฒ๋ฅผ ์ฌ์คํํ์ง์๊ณ ๋ฐ๋ก ๊ฐ์ ๋คํํ๋๋ก refresh๋ผ๋ api๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ๋ค.

Config Server #
@SpringBootApplication
@EnableConfigServer
class ConfigServerApplication
fun main(args: Array<String>) {
runApplication<DmsBackendApplication>(*args)
}
server:
port: 8081
spring:
cloud:
config:
server:
git:
uri: https://github.com/๋์ถฉymlํ์ผ์๋๊ณณ # configtest-dev
Client Server #
Controller
@RestController
class TestController(){
@Value("test.value")
private val configStr: String
@GetMapping("/")
fun test() = configStr
}
application.yml
server:
port: 8082
spring:
cloud:
config:
name: configtest-dev
import: optional:configserver:http://localhost8081
configtest-dev
test:
value: dev-test
์ฌ๊ธฐ์ http://localhost:8082๋ก GET ์์ฒญ์ ๋ณด๋ด๋ฉด configtest-dev์ yml ์ ๋ณด ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐ์๋ณผ ์ ์๋ค. test.value = dev-test๋ผ๋ ์ ๋ณด๋ ํจ๊ป ๋ง์ด๋ค.
response: dev-test
์ ์ฌ๊ธฐ์ test.value ์ ๊ฐ์ dev-test-2๋ก ๋ฐ๊ฟ์ ๋ค์ GET์์ฒญ์ ๋ณด๋ด๋ณธ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ์์ ์ ํ๋๋ผ๋ ๋๊ฐ์ด dev-test์ ๊ฒฐ๊ณผ๊ฐ์ด ๋ฐํ์ด๋๋ค. ๋ฐ์ดํฐ ์ํ๊ฐ ๋ก๋ฉ๋์ง ์์์ ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ ๋๋ค.
์ฌ๊ธฐ์ ์คํ๋ง ์ก์ธ์์ดํฐ๋ฅผ ์ฌ์ฉํด refresh ํด๋ณด๊ฒ ๋ค.
application.yml์ ๋ค์๊ณผ๊ฐ์ ์ ๋ณด๋ค์ ์ถ๊ฐํด๋ณด์
<-- .... -->
management:
endpoints:
web:
exposure:
include : refresh # ์ก์ธ์์ดํฐ ๊ธฐ๋ฅ์ค refresh๋ฅผ ์ฌ์ฉํ๋ค๋ ๋ป์ด๋ค * ๋ฅผ ๋ฌ๋ฉด ๋ค ์ฌ์ฉํ๋ค๋ ๋ป
๊ทธ๋ฆฌ๊ณ TestController์ ๋ค์๊ณผ๊ฐ์ ์ด๋ ธํ ์ด์ ์ ๋ฌ์์ค๋ค.
@RestController
@RefreshScope
class TestController(){
@Value("test.value")
private val configStr: String
@GetMapping("/")
fun test() = configStr
}
์ ์ด์ ๋ค์ dev-test๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌ์ํค๊ณ GET์ ๋ณด๋ด๋ณด๋ฉด ๋๊ฐ์ด test.value: dev-test๋ก ์๋ต์ด ์ค๊ฒ๋๋ค.
dev-test-2๋ก ๋ฐ๊พธ๊ณ GET์์ฒญ์ ๋ณด๋ด๋ฉด ๋๊ฐ์ด ๊ฐ์ด ๋ฐ๋์ง ์์ ์ํ๋ก dev-test์๋ต์ด ์ค๊ฒ๋๋๋ฐ ์ฌ๊ธฐ์
http://localhost:8082/refresh๋ก POST ์์ฒญ์ ๋ณด๋ด๊ณ ๋ค์ํ๋ฒ http://localhost:8082์ GET์์ฒญ์ ๋ณด๋ด์ฃผ๋ฉด
dev-test-2๋ผ๋ ๋ฐ์ดํฐ๋ก ๋ฐ์ดํฐ๊ฐ ๋ฆฌํ๋ ์ฌ๋๋๊ฒ์ ํ์ธํ ์ ์๋ค.
response : dev-test-2
์ด๋ ๊ฒ ์คํ๋ง ์ก์ธ์์ดํฐ๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ ๋ฆฌํ๋ ์ฌ๋ฅผ ํด๋ดค๋ค. ๋ฆฌํ๋ ์ฌ ์ด์ธ์๋ ์ฌ๋ฌ ๊ธฐ๋ฅ๋ค์ด ์์ผ๋ ํ๋ฒ ๊ณต๋ถํด๋ณด๊ณ ์ฌ์ฉํด๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค. ํฌ์คํ ์ฝ์ด์ฃผ์ ๋ถ๋ค์๊ฒ ๊ฐ์ฌ์ ๋ง์ ์ ํ๋ฉฐ Spring Cloud์ MSA์ ๋ํด์๋ ๋์ฑ ๊ณต๋ถํ ์์ ์ด๋ค.