# [Spring] ThreadLocal๋กœ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ
Study Repository

[Spring] ThreadLocal๋กœ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ

by rlaehddnd0422
์ด ์ „ ํฌ์ŠคํŒ…์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋™๊ธฐํ™”๋กœ ํ•˜๋‚˜์˜ HTTP ์š”์ฒญ์— ๋Œ€ํ•ด์„œ ๊ณ ์œ ์˜ TraceId๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ณ ์ณ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๋™๊ธฐํ™”์—๋Š” ์„ฑ๊ณตํ–ˆ์ง€๋งŒ, ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  1.  ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— TraceId ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๊ป„๋„๋Ÿฌ์›€(ํ™•์žฅ, ์œ ์ง€๋ณด์ˆ˜์— ๋Œ€ํ•œ ๋ถˆํŽธํ•จ)์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  2. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฐ ๊ณ„์ธต์— try/catch๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์–ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊นŒ์ง€ ๋–จ์–ด์กŒ์–ด์š”.
  3. ์ด ์™ธ์—๋„ ์ฒซ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ begin์„ ํ˜ธ์ถœํ•˜๊ณ , ์ด์–ด๋ฐ›์€ ๊ณ„์ธต์—์„œ๋Š” beginSync๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์— ์ฝ”๋“œ์˜ ํ™•์žฅ๊นŒ์ง€ ์ด๋ฃจ์–ด์ ธ ์ข‹์€ ์ฝ”๋“œ๋ผ๊ณ  ๋ณด๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ๋‹ค๋ฅธ๋ฐฉ๋ฒ•์„ ๋„์ž…ํ•ด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ ๋งํ•˜์ž๋ฉด  ThreadLocal์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
 
ํ•˜์ง€๋งŒ ์ฒ˜์Œ๋ถ€ํ„ฐ ThreadLocal์„ ๋„์ž…ํ•˜์ง€ ์•Š๊ณ ,

  1. TraceId๋ฅผ ํด๋ž˜์Šค ๋‚ด์— ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ์— ๋‹ด์•„์„œ ์‚ฌ์šฉํ•˜๋Š” ํ•„๋“œ ๋กœ๊ทธ ์ถ”์ ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ณ , 
  2. ์ด ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ™•์ธํ•ด๋ณด๊ณ ,
  3. ThreadLocal์„ ์ ์šฉ์‹œ์ผœ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๋‘ ๊ฐ€์ง€(Thread๋ฅผ ์‚ฌ์šฉํ•œ ๋กœ๊ทธ ์ถ”์ ๊ธฐ, ThreadLocal์„ ์‚ฌ์šฉํ•œ ๋กœ๊ทธ ์ถ”์ ๊ธฐ) ๋กœ๊ทธ ์ถ”์ ๊ธฐ๋ฅผ ๋„์ž…ํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ, ๋จผ์ € ํ”„๋กœํ† ํƒ€์ž…์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ถ€ํ„ฐ ์ž‘์„ฑํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.

public interface LogTrace {

    TraceStatus begin(String msg);
    void end(TraceStatus status);
    void exception(TraceStatus status, Exception e);
}
  • ์ด ์ „ ๋กœ๊ทธ์ถ”์ ๊ธฐ์™€ ๋‹ค๋ฅด๊ฒŒ, beginSync์™€ begin์„ ๊ตฌ๋ถ„์ง“์ง€ ์•Š๊ณ  begin ๋‚ด๋ถ€์—์„œ ์ฒซ ํ˜ธ์ถœ์ธ์ง€ ๊ฒ€์‚ฌํ•  ์˜ˆ์ •

์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ์— ๋™๊ธฐํ™” - FieldLogTrace

@Slf4j
public class FieldLogTrace implements LogTrace {

    private static final String START_PREFIX = "-->";
    private static final String COMPLETE_PREFIX = "<--";
    private static final String EX_PREFIX = "<X-";

    private TraceId traceIdHolder; // ์ถ”๊ฐ€

์ด ์ „ ๋กœ๊ทธ ์ถ”์ ๊ธฐ์™€ ๋‹ฌ๋ฆฌ TraceId๋ฅผ ๋‹ด์„ traceHolder๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๊ฒŒ ๋˜๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธธ ํ•„์š”๊ฐ€ ์—†์–ด์ง‘๋‹ˆ๋‹ค.
์•„๋ž˜์—์„œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ธด ํ•˜๊ฒ ์ง€๋งŒ, ๋จผ์ € ์„ค๋ช…ํ•˜์ž๋ฉด ์ด๋ ‡์Šต๋‹ˆ๋‹ค.

  • ๋กœ๊ทธ ์ถ”์ ๊ธฐ์˜ ์‹œ์ž‘์ธ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด TraceId๋ฅผ ์ƒ์„ฑ,
  • ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ traceHolder์—์„œ createNextId()๋กœ ๋™๊ธฐํ™”๋œ TraceId๋ฅผ ์‚ฌ์šฉ

FieldLogTrace.begin 

@Override
public TraceStatus begin(String message) {
    syncTraceId();
    TraceId traceId = traceIdHolder;
    Long startTimeMills = currentTimeMillis();
    log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message);
    return new TraceStatus(traceId, startTimeMills, message);
}

private void syncTraceId() {
    if (traceIdHolder == null) {
        traceIdHolder = new TraceId();
    } else {
        traceIdHolder = traceIdHolder.createNextId();
    }
}

์œ„์—์„œ ํ–ˆ๋˜ ์„ค๋ช… ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ synTraceId()์ž…๋‹ˆ๋‹ค.
 
syncTraceId

  • ๋กœ๊ทธ ์ถ”์ ๊ธฐ์˜ ์‹œ์ž‘์ธ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด TraceId๋ฅผ ์ƒ์„ฑ,
  • ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ traceHolder์—์„œ createNextId()๋กœ ๋™๊ธฐํ™”๋œ TraceId๋ฅผ ์‚ฌ์šฉ

์—ฌ๊ธฐ์„œ ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ ๋™๊ธฐํ™”๋œ TraceId๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋™๊ธฐํ™” ๋ฌธ์ œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œํ™•์žฅ ( begin(), beginSync() ๊ตฌ๋ถ„ ) ๊นŒ์ง€ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
 

FieldLogTrace - end, exception

public void end(TraceStatus status) {
    complete(status, null);
}

public void exception(TraceStatus status, Exception e) {
    complete(status, e);
}

์ด์ „๊ณผ ๋™์ผํ•˜์ง€๋งŒ complete ์ดํ›„ ์ฒ˜๋ฆฌ๊ฐ€ ์กฐ๊ธˆ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

private void complete(TraceStatus status, Exception e) {
    Long stopTimeMs = currentTimeMillis();
    long resultTimeMs = stopTimeMs - status.getStartTimeMs();
    TraceId traceId = status.getTraceId();

    if (e == null) {
        log.info("[{}] {}{} time={}ms", traceId.getId(),
                addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(),
                resultTimeMs);
    } else {
        log.info("[{}] {}{} time={}ms ex={}", traceId.getId(),
                addSpace(EX_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs,
                e.toString());
    }

    releaseTraceId();
}

private void releaseTraceId() {
    if (traceIdHolder.isFirstLevel()) {
        traceIdHolder = null; // 1 -> destroy
    } else {
        traceIdHolder = traceIdHolder.createPreviousId(); // 1 -> 2 -> 3(complete) -> 2 -> 1
    }
}

releaseTraceId()๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
 
releaseTraceId()

  • ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์š”์ฒญ์ด ๋๋‚˜๊ฒŒ ๋˜๋ฉด ์ด ์ „ ๊ณ„์ธต์—๊ฒŒ traceHolder์— ํ˜„์žฌ TraceId์˜ ์ด์ „ ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ( level์„ ํ•˜๋‚˜ ๊ฐ์†Œ ) 
  • ๋งŒ์•ฝ ์ตœ์ดˆ ํ˜ธ์ถœ(level=0)์ด๋ฉด ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” traceId๋ฅผ ์ œ๊ฑฐ 
  • syncTraceId()์˜ ์—ญ๋กœ์ง

 
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด ํŠธ๋žœ์žญ์…˜ ID๋„ ์ผ์น˜, level์„ ํ†ตํ•œ ๊นŠ์ด ํ‘œํ˜„๋„ ์ž˜ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋กœ์ง์— ๋„์ž… , ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ™•์ธ

์šฐ์„  ์œ„์—์„œ ๋งŒ๋“  FieldLogTrace๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ค์‹œ๋‹ค. 

์™œ ์ˆ˜๋™์œผ๋กœ ๋“ฑ๋กํ–ˆ์„๊นŒ ?
: ์ด ์ถ”์ ๊ธฐ ๋ง๊ณ ๋„ ์ถ”ํ›„์— ThreadLocal์„ ์‚ฌ์šฉํ•œ ๋กœ๊ทธ ์ถ”์ ๊ธฐ๋„ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ธ๋ฐ ๊ฐˆ์•„ ๋ผ์šฐ๊ธฐ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ.
/ ํ”„๋กœํ† ํƒ€์ž…์ด ์„ ์–ธ๋˜๊ณ  ๊ตฌํ˜„์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ˆ˜๋™ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค.
@Configuration
public class LogTraceConfig {
    @Bean
    public LogTrace logTrace() {
        return new ThreadLocalLogTrace();
    }
}

 
Controller, Service, Repository ์ชฝ์€ ์ด ์ „ ๋กœ๊ทธ ์ถ”์ ๊ธฐ (ver2)์—์„œ ์ถ”์ ๊ธฐ๋งŒ ๊ฐˆ์•„๋ผ์›Œ์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ฝ”๋“œ๋ฅผ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.

// private final HelloTraceV2 trace; 
private final LogTrace trace;

 
์ด์ œ HTTP ์š”์ฒญ์„ ํ†ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
 
http://localhost:8080/v3/request?itemId=3 

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

ํŠธ๋žœ์žญ์…˜ ID๋Š” ๋™์ผํ•œ๋ฐ Level๋„ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋Š”๋ฐ ๋ญ๊ฐ€ ๋ฌธ์ œ์ผ๊นŒ์š”.
 
์ด ๋ฌธ์ œ๋Š” ๋™์‹œ์„ฑ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. 

๋™์‹œ์„ฑ ๋ฌธ์ œ

  • ์‹ฑ๊ธ€ํ†ค ๋นˆ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋กœ, ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ์‹ฑ๊ธ€ํ†ค ๋นˆ์— ๋™์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์ด์ฒ˜๋Ÿผ 1)์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, 2)ํ˜ธ์ถœ์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๋„์ค‘ ๋‹ค๋ฅธ ํ˜ธ์ถœ์ด ์š”์ฒญ๋  ๋•Œ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ๊ฐ’์„ ์ฐธ์กฐํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋Ÿฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ์— ์ ‘๊ทผํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋ž˜ํ”ฝ์ด ์ ์€ ์ƒํ™ฉ์—์„œ๋Š” ํ™•๋ฅ ์ƒ ์ž˜ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๊ณ , ํŠธ๋ž˜ํ”ฝ์ด ์ ์  ๋งŽ์•„์งˆ ์ˆ˜ ๋ก ์ž์ฃผ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ํŠนํžˆ ์Šคํ”„๋ง ๋นˆ ์ฒ˜๋Ÿผ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉฐ ์‚ฌ์šฉํ•  ๋•Œ ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 


ThreadLocal ๋„์ž…ํ•˜์—ฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ 

๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ํ•„๋“œ( ์ฃผ๋กœ ์‹ฑ๊ธ€ํ†ค์—์„œ ์ž์ฃผ ๋ฐœ์ƒ )๋‚˜ static ๊ฐ™์€ ๊ณต์šฉ ํ•„๋“œ์— ์ ‘๊ทผํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๊ฐ’์„ ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ, ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. 
์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์˜ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ThreadLocal์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
 

ThreadLocal์ด๋ž€?

  • ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.
  • ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ์“ฐ๋ ˆ๋“œ๋งˆ๋‹ค ๋ณ„๋„์˜ ๋‚ด๋ถ€ ์ €์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ ํ•„๋“œ์— ์ ‘๊ทผํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ThreadLocal ์‚ฌ์šฉ๋ฒ•

  • ๊ฐ’ ์ €์žฅ : ThreadLocal.set()
  • ๊ฐ’ ์กฐํšŒ : ThreadLocal.get()
  • ๊ฐ’ ์ œ๊ฑฐ : ThreadLocal.remove() ( ์ฃผ์˜ : ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ์ง์ „ ๋ฐ˜๋“œ์‹œ ํ˜ธ์ถœ๋˜์–ด์•ผ ํ•จ ! )

ThreadLocalLogTrace ์ƒ์„ฑ

@Slf4j
public class ThreadLocalLogTrace implements LogTrace{

    private static final String START_PREFIX = "-->";
    private static final String COMPLETE_PREFIX = "<--";
    private static final String EX_PREFIX = "<X-";

    private ThreadLocal<TraceId> traceIdHolder = new ThreadLocal<>(); // traceId ๋™๊ธฐํ™”, ๋™์‹œ์„ฑ ์ด์Šˆ X
  • ํ•„๋“œ ๋กœ๊ทธ ์ถ”์ ๊ธฐ์—์„œ ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, ThreadLocal์„ ๋„์ž…ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • ์ฐธ๊ณ ๋กœ ThreadLocal์„ ThreadLocal<T> ์ด๋ฏ€๋กœ ์–ด๋–ค ํƒ€์ž…์ด๋˜์ง€ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 
๊ทธ ์™ธ ๋ณ€๊ฒฝ์ 

@Override
public TraceStatus begin(String message) {
    syncTraceId();
    TraceId traceId = traceIdHolder.get();
private void syncTraceId() {
    TraceId traceId = traceIdHolder.get();
    if (traceId == null) {
        traceIdHolder.set(new TraceId());
    } else {
        traceIdHolder.set(traceId.createNextId());
    }
}
private void releaseTraceId() {
    TraceId traceId = traceIdHolder.get();
    if (traceId.isFirstLevel()) {
        traceIdHolder.remove();
    } else {
        traceIdHolder.set(traceId.createPreviousId());
    }
}

์กฐํšŒํ•  ๋•Œ์—๋Š” get(), ์ €์žฅํ•  ๋•Œ์—๋Š” set()์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์€ ์•„๊นŒ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์“ฐ๋ ˆ๋“œ ์ข…๋ฃŒ ์‹œ์ (traceId.isFirstLevel) ์—๋Š” remove()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์— ์ €์žฅ๋œ ๊ฐ’์„ ์ œ๊ฑฐํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
 
ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๋ฉด

ํŠธ๋žœ์žญ์…˜ ์•„์ด๋”” ๊ตฌ๋ถ„ X

์œ„ ๊ฒฐ๊ณผ์˜ ํŠธ๋žœ์žญ์…˜ ์•„์ด๋””๋ฅผ ๊ตฌ๋ถ„์ง€์–ด์„œ ํ™•์ธํ•ด๋ณด๋ฉด ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
 

ThreadLocal ์‚ฌ์šฉ ์‹œ ์“ฐ๋ ˆ๋“œ ์ข…๋ฃŒ ์‹œ์ ์—  remove()๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ์ด์œ 

์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์˜ ๊ฐ’์„ ์‚ฌ์šฉ ํ›„ ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋ƒฅ ๋‘๋ฉด WAS(ํ†ฐ์บฃ)์ฒ˜๋Ÿผ ์“ฐ๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CASE)

  1. A๋ผ๋Š” ์œ ์ €๊ฐ€ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์—์„œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ’์„ ์ €์žฅํ•œ ์ดํ›„ remove()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ
  2. B๋ผ๋Š” ์œ ์ €๊ฐ€ ๊ฐ™์€ ์š”์ฒญ(๊ฐ’ ์กฐํšŒ๋ผ๊ณ  ๊ฐ€์ •)์„ ํ•จ.
  3. B ์œ ์ €๊ฐ€ ์œ ์ €๊ฐ€ A๊ฐ€ ์‚ฌ์šฉํ–ˆ๋˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ• ๋‹น๋ฐ›์•˜์Œ.
  4. B๋Š” A๊ฐ€ ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์— ์ง€์šฐ์ง€ ์•Š๊ณ  ๋‚จ๊ฒจ๋‘” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ฒŒ ๋จ.
์ฐธ๊ณ ๋กœ ์“ฐ๋ ˆ๋“œ๋Š” ์ข…๋ฃŒ์‹œ์ ์— ์“ฐ๋ ˆ๋“œ ํ’€์— ๋‹ค์‹œ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

 
์ด ๋•Œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ์ด์ „๊ณผ ๋™์ผํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌ๋ฉด ThreadLocal์„ ๋„์ž…ํ•œ๊ฒŒ ๋ง์งฑ ๋„๋ฃจ๋ฌต
 
์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฐ˜๋“œ์‹œ ๊ผญ ์ข…๋ฃŒ์‹œ์ ์— remove()๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.
 
<์ฐธ๊ณ  ์ž๋ฃŒ>

์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ณ ๊ธ‰ํŽธ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์Šคํ”„๋ง์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋“ค์„ ๊นŠ์ด์žˆ๊ฒŒ ํ•™์Šตํ•˜๊ณ , ์Šคํ”„๋ง์„ ์ž์‹ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., ํ•ต์‹ฌ ๋””์ž์ธ ํŒจํ„ด, ์“ฐ๋ ˆ๋“œ ๋กœ์ปฌ, ์Šคํ”„๋ง AOP์Šคํ”„๋ง์˜ 3๊ฐ€์ง€ ํ•ต์‹ฌ ๊ณ ๊ธ‰ ๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ ๐Ÿ“ข ์ˆ˜๊ฐ•

www.inflearn.com

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ