Spring Cloud Sleuth๋ ๋ถ์ฐ ํ๊ฒฝ์์ ์ผ๋ จ์ Request์ ๋ํ ์๊ด๊ด๊ณ๋ฅผ ํ์ํ์ฌ ์๋น์ค ๊ฐ ํธ์ถ์ ๋ํ ์ถ์ ์ ์ง์ํด ์ฃผ๋ ๋ชจ๋์ ๋๋ค. Sleuth๋ RestTemplate, Feign, WebClient์ ๊ฐ์ ์คํ๋ง ์งํ์ HTTP Client ๋ชจ๋์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ Sleuth ์์กด์ฑ์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก๋ ์ค์ ์ด ์๋์ ์ผ๋ก ๋์ํ๊ฒ ๋ฉ๋๋ค. ํ์ง๋ง ๋ค๋ฅธ HTTP Client ๋ชจ๋์ ์ฌ์ฉํ๋ค๋ฉด ํด๋น ์ค์ ์ ์๋์ผ๋ก ์งํ ํ์ ํ๋๋ฐ์. ์ด๋ฒ ํฌ์คํ ์์๋ ์ฝํ๋ฆฐ ๊ธฐ๋ฐ์ Fuel HTTP Client ๋ชจ๋์ Sleuth๋ฅผ ์ฐ๋ํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃจ์ด๋ณด๊ฒ ์ต๋๋ค.
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.2")
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-sleuth")
}
Sleuth ์์กด์ฑ์ ์ถ๊ฐํ๋ ๊ฒ๋ง์ผ๋ก๋ logback ์ค์ ๊ณผ ์ฐ๊ณ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ๋ก๊ทธ์ ๋ฐ๋ก ์ ์ฉ์ด ๋ฉ๋๋ค.
๊ธฐ๋ณธ ์ค์ ์ [application name, Trance ID, Span ID] ํ์์ผ๋ก ์ ์ฉ๋ฉ๋๋ค. Application name์ spring.application.name: xxx
์ค์ ๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ง์ ๋ฉ๋๋ค. ๋ก๊ทธ ํ์์ ๋ฐ๊พธ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ loback ์ค์ ์ ์ง์ ํ์ฌ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํฉ๋๋ค.
์ด๋ฆ | ์ค๋ช |
---|---|
Trace ID | ์ ์ฒด Request์ ๊ณ ์ ํ ๊ฐ |
Span ID | ์ ์ฒด Request์ค ์ผ๋ถ์ ์ผ๋ถ์ ๊ณ ์ ํ ๊ฐ |
Parent Span ID | ์ด์ Request์ Span ID๋ก ์์ฒญ์ ํ๋ฆ์ ํ์ ์ ์ํ ๊ฐ |
- API Gateway์์ Request๋ฅผ ๋ฐ์ Trace ID, Span ID๋ฅผ ๋์ผํ ๊ฐ์ผ๋ก ์์ฑํ๋ฉฐ Parent Span ID๋ null์ผ๋ก ์ง์
- A Service์์๋ Trace ID๋ ๋์ผํ๊ฒ ์ค์ , Span ID๋ Request์ ์ค ์ผ๋ถ๋ก ๊ณ ์ ํ ๊ฐ์ ์ค์ , Parent Span ID๋ ์ด์ Request์ Span ID๋ก ์ง์
- B Service์์๋ Trace ID๋ ๋์ผํ๊ฒ ์ค์ , Span ID๋ ๋์ผํ๊ฒ ์ ์ผํ ๊ฐ, Parent Span ID๋ ๋์ผํ๊ฒ ์ด์ Request์ Span ID๋ก ์ค์
Request์ ์ ์ฒด ํ๋ฆ์ Trace ID๋ฅผ ๊ธฐ์ค์ผ๋ก ํธ๋ํน ํ๋ฉฐ Span ID๋ก๋ ํด๋น Request์ ์ํ๋ ์๋น์ค์ ์ ๋ํฌํ๊ฒ ์๋ณ์ด ๊ฐ๋ฅํฉ๋๋ค. ๋ Parent Span ID๋ฅผ ํตํด์ ํธ์ถ ๊ฐ์ ์๊ด๊ด๊ณ๋ฅผ ํ์ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
RestTemplate, Feign, WebClient์ฒ๋ผ ์คํ๋ง ์งํ์ HTTP Client๋ฅผ ์ฌ์ฉํ๋ฉด Sleuth ์์กด์ฑ์ ์ถ๊ฐํ๋ฉด ์๋์ผ๋ก Sleuth๊ฐ ๋์ํ๊ฒ ๋๋ฉฐ HTTP Header ์ ๋ณด์ Trace ID, Span ID, Parent Span ID๋ฅผ ์๋์ผ๋ก ์ถ๊ฐ๋ฉ๋๋ค. ํ์ง๋ง ๊ทธ ์ธ์ HTTP Client ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํด๋น ์ค์ ์ ์งํํด์ผ ํฉ๋๋ค. ๋ณธ ์์ ๋ Kotlin ๊ธฐ๋ฐ์ HTTP Client ๋ผ์ด๋ธ๋ฌ๋ฆฌ Fuel๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ช ๋๋ฆฌ๊ฒ ์ต๋๋ค.
@Configuration
class FuelConfiguration {
@Bean
fun fuelManager(tracer: Tracer) =
FuelManager.instance.apply {
this.timeoutReadInMillisecond = 120_000 // 2๋ถ // 1
this.timeoutReadInMillisecond = 120_000 // 2๋ถ // 2
this.addRequestInterceptor(tracingRequestInterceptor(tracer = tracer)) // 3
this.addRequestInterceptor(LogRequestInterceptor) // 4
this.addResponseInterceptor(LogResponseInterceptor) // 5
}
// 6
private fun tracingRequestInterceptor(tracer: Tracer) = { next: (Request) -> Request ->
{ request: Request ->
val span = tracer.currentSpan() ?: tracer.nextSpan()
request.header(
"x-b3-traceid" to span.context().traceId(),
"x-b3-spanid" to tracer.nextSpan().context().spanId(),
"x-b3-parentspanid" to tracer.nextSpan().context().parentId().toString()
)
next(request)
}
}
}
- FuelManager์ ํตํด์ ์ค์ ์ ์งํํฉ๋๋ค.
- (1),(2): Timeout ์ค์ ์ ์งํํฉ๋๋ค. ๊ธฐ๋ณธ ์ค์ ์ด 15s์ด๊ธฐ ๋๋ฌธ์ ์กฐ์ ์ด ํ์ํ๋ฉด ์๋น์ค์ ๋ง๋ฐ ์ค์ ์ ์งํํฉ๋๋ค.
- (3): Header ๊ฐ์ฒด์
x-b3-traceid
,x-b3-spanid
,x-b3-parentspanid
์ ๊ฐ์ Tracer ๊ฐ์ฒด ๊ธฐ๋ฐ์ผ๋ก ์ค์ ํฉ๋๋ค. - (4)(5): Request, Response๋ฅผ Logging ์งํํฉ๋๋ค.
@RestController
@RequestMapping("/a-service")
class AServiceApi(
private val tracer: Tracer
) {
@GetMapping
fun a() {
"http://localhost:8686/b-service"
.httpGet()
.header(CONTENT_TYPE to "application/json")
.response()
}
}
Fuel์ ๊ธฐ๋ฐ์ผ๋ก B Service๋ฅผ ํธ์ถํฉ๋๋ค. Fuel์ ๋งค์ฐ ์ง๊ด์ ์ผ๋ก HTTP ํต์ ์ ์งํํ ์ ์์ต๋๋ค. API Gateway -> A Service -> B Service๋ฅผ ํธ์ถํ๋ ๊ตฌ์กฐ์์ A Service์ ๋ก๊ทธ ์ ๋ณด๋ ์๋์ ๊ฐ์ต๋๋ค.
# API Gateway
2022-05-28 18:09:04.159 INFO [gateway-server,757d0493f099b94b,757d0493f099b94b] 11352 --- [ctor-http-nio-4] com.server.gateway.GlobalFilter : =======API Gateway\======
...
# A service Log
2022-05-28 18:09:04.163 INFO [service-a,757d0493f099b94b,7fba8ecffbdbabcd] 9927 --- [nio-8787-exec-5] c.example.msaerrorresponse.AServiceApi : =======a-service======
--> GET http://localhost:8686/b-service
Body : (empty)
Headers : (4)
Content-Type : application/json
x-b3-spanid : 4e8d66a6aa1c1ed6
x-b3-parentspanid : 7fba8ecffbdbabcd
x-b3-traceid : 757d0493f099b94b
<-- 200 http://localhost:8686/b-service
Response :
Length : 0
Body : (empty)
Headers : (4)
Connection : keep-alive
Date : Sat, 28 May 2022 09:09:04 GMT
Content-Length : 0
Keep-Alive : timeout=60
# B service Log
2022-05-28 18:09:04.165 INFO [service-b,757d0493f099b94b,4e8d66a6aa1c1ed6] 9989 --- [nio-8686-exec-3] c.example.msaerrorresponse.BServiceApi : =======b-service======
๋ชจ๋ Request๋ Trace ID: 757d0493f099b94b์ผ๋ก ๊ทธ๋ฃนํ๊ฐ ๊ฐ๋ฅํ๋ฉฐ ๊ฐ ์๋น์ค๋ง๋ค Span ID๋ง๋ค ๊ณ ์ ํ ๊ฐ์ผ๋ก ํธ๋ํน์ด ๊ฐ๋ฅํฉ๋๋ค. ๋ Parent Span ID๋ฅผ ํตํด์ Request์ ์๊ด๊ด๊ณ๋ฅผ ํ์ ํ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ Slueth๋ฅผ ํตํด์ Request์ ์๊ด๊ด๊ณ๋ฅผ ๋ก๊น ์ํ๋ฉด ํด๋น ์ ๋ณด๋ฅผ ํ์ฉํ์ฌ ์๊ฐํ๊ฐ ๊ฐ๋ฅํฉ๋๋ค. ํด๋น ์ด๋ฏธ์ง๋ Elastic Search APM๋ฅผ ์ฌ์ฉํ์ต๋๋ค.