로직과의 사투/Operational Issues

로깅 룰 구축기 (1)

1. 시행 개요

MSA (Micro Service Architecture)

  • 현재 담당하는 업무는 각각 독립된 역할을 하는 여러 서비스 (약 40여개의 서비스 존재)들로 구성되어 있다. Interface, Core 처리, Gateway 등 각 역할에 맞는 서비스들이 존재하며 유기적으로 연결되어 있다.

  • 각 서비스는 작고 독립적이며 느슨하게 결합되어 있다. 때문에 서비스 각 독립적으로 배포할 수 있다는 장점이 있다.

  • 단점으로는 서비스 간 통신이 필요하다는 점이다. 이로 인해 복잡해질 수 있으며, 상호작용 테스트가 어렵다. 또한 통합 유지관리가 어렵다는 단점이 존재한다.

  • 위의 관점에서 보았을 때 현 업무는 통합 관리가 정상적으로 이뤄지지 않고 있다. 각 Transaction 이 유기적으로 어떻게 연결되는 지 업무를 오래 담당하던 사람이 아니면 파악하기 힘들다.

  • 또한, 로깅룰 마저 각 프로세스 별로 상이하게 작성되어 있어 Transaction 추적이 용이하지 않다.

이중화

  • 담당 업무는 각기의 서버 롤에 맞게 IDC 내에 이중화가 되어 있다.

  • 서버 롤은 인터넷망, 전용선망, 내부망, 배치존 등이 존재하며 모두 Round Robin을 통해 L4이중화 되어 있다.

  • 이는 위 MSA 아키텍쳐와 맞물려 운영 복잡도를 기하급수적으로 증가 시킨다.

  • 일례로 기본이 되는 트랜잭션은 아래와 같은 프로세스를 통해 트랜잭션이 처리된다.

  • some_interface -> some_core -> some_gw

  • 위 트랜잭션 사이클을 모두 확인하기 위해서는 interface 프로세스가 존재하는 대외망 서버를 01, 02 번 모두 확인하고, 내부망 어디에서 처리되었는 지 내부망 서버 01, 02를 확인해야한다. 마지막으로 타 기관 연동 확인을 위해 대외망 서버 01, 02 다시 확인해야 한다.

  • 위 프로세스에서 병렬처리가 추가되거나 또 다른 기관과의 통신이 추가되면 복잡도는 더 올라가고, 추적은 쉽지 않게 된다.

  • 서비스가 많은만큼 경우의 수 또한 증가하는 것이다.

2. 개선

Trace Id 와 Span Id
- Trace Id : 전체 작업에 할당된 ID이다. 한 Transaction을 추적하는 데 사용. 작업에 작은 단위들이 존재한다면, 각각의 작은 단위들은 공통의 TraceId 를 부여받는다.
- Span Id : 각각의 작은 단위들이 가지고 있는 ID. 모두 서로 다른 ID를 가지고 있기 때문에 서로 다른 작업단위들을 구분해주는 역할을 한다.
- 위 TraceId와 SpanID를 로깅하고, 각각의 통신에서 Header를 통해 주고 받으며 Transaction을 추적할 수 있게 수정.

c.f. 위의 TraceId와 SpanId 는 Spring Cloud Sleuth를 사용하면 손쉽게 구성할 수 있다. 단, 현재 회사가 ISMS 인증으로 인해 온라인 라이브러리 다운로드가 쉽지 않은 점, 존재하는 각 모듈들의 스프링 부트 버전이 제 각각 상이한 점으로 인해 직접 구축하는 것이 낫다고 판단해 직접 개발.

2. 기존 로그

2023-07-03 17:47:42.605 [71898] INFO Logger.log(29) - 10.222.241.5 |REQ|TCP 전문 내용 ...|

구성 : YYYY-MM-DD HH:MI:SS.SSS [thread name] 로그레벨 로깅 클래스 - .. 로깅 내용

3. TO-BE log

2023-07-03 17:47:42.605 [71898, f62969423d8a42cc, 6t123789d8a42cc] INFO Logger.log(29) - 10.222.241.5 |REQ|전문내용|

구성 : YYYY-MM-DD HH:MI:SS.SSS [thread name, trace id, span id] 로그레벨 로깅 클래스 - .. 로깅 내용

4. 구성 방법

a. 알아야 될 기술
  • MDC(Mapped Diagnostic Context) : JAVA Map 형식으로 클라이언트의 특징적인 데이터를 저장하기 위한 메커니즘으로 slf4j, logback, log4j2 등 현재 담당 업무에서 사용 중인 log 라이브러리에 모두 적용 가능.
MDC.put("traceId", UUID.randomUUID().toString().replace("-", "").substring(0, 16));
MDC.clear();
  • logback.xml, log4j2.xml 등.. : 로깅 형식을 적용 하기 위해 pattern 등을 지정하는 로깅 관련 config xml.
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %yellow(%X{traceId}, %X{spanId}) %highlight(%-5level) %cyan(%logger{36}.%M%magenta(\(%line\))) - %msg%n</pattern>
  </encoder>
</appender>
  • Http Header 투입 : TRS 내부 통신은 모두 HTTP로 통신됨으로 Http Header 이용 가능.

    httpHeaders.put("X-B3-TraceId", traceId);
    httpHeaders.put("X-B3-SpanId", spanId);
    httpHeaders.put("X-B3-ParentSpanId", parentSpanId);
  • 참고 : Spring Framwork에서 사용하는 HTTP 관련 라이브러리로 RestTemplate, Jersey, WebClient 등이 존재. 현 업무에선 RestTemplate, Jersey 두 가지 모두 사용되고 있으므로 각 프로젝트의 사용 라이브러리에 맞는 Header 값 세팅 방법 필요.

  • Request Filter : RestTemplate, Jersey 두 가지 모두 가능한 방식으로 Controller 단에 도착하기 전 먼저 시행되는 RequestFilter 를 구현 가능. -> RequestFilter에서 MDC 세팅 등 필요.

  • 병렬처리로 인해 신규 스레드 생성하여 실행되는 경우 각 신규 스레드에 모두 span id 부여 필요.