일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- golang
- RDS
- logging
- elasticsearch
- context7
- blank import
- sqs fifo queue
- 티스토리챌린지
- AWS
- 디자인패턴
- database/sql
- MSA
- 관측 가능성
- GIT
- go-sql-driver
- Kubernetes
- GoF
- Infra
- Intellij
- 구조체
- AI
- goland
- javascript
- typescript
- esbuild
- 오블완
- 통합 로깅 시스템
- go
- 캡슐화
- replication lag
- Today
- Total
Fall in IT.
MSA 환경에서 로그를 기반으로 Observability 확보하기 본문
전통적인 모놀리식(Monolithic) 아키텍처에서 마이크로소프트 아키텍처(MSA)로의 전환은 이제 거스를 수 없는 흐름이 되었다. MSA는 서비스의 독립적인 개발과 배포를 가능하게 하여 조직의 생산성을 극대화하는 강력한 장점을 가지고 있다. 하지만 서비스가 잘게 쪼개지고, 하나의 요청이 여러 서비스 간의 복잡한 네트워크 호출로 이어지면서 새로운 문제가 발생했다. 바로 시스템의 동작을 이해하고 추적하기가 극도로 어려워졌다는 점이다.
과거 모놀리식 환경에서는 CPU, Memory 사용률과 같은 시스템 매트릭과 로그 파일만 잘 확인해도 장애의 원인을 비교적 쉽게 파악할 수 있었다. 그러나 MSA 환경에서는 문제가 발생했을 때, 수많은 서비스 중 어느 곳에서 문제가 시작되었고, 그 여파가 어디까지 미쳤는지 파악하는데 많은 시간을 소요하게 된다. 이러한 문제를 해결하기 위해 등장한 개념이 바로 관측 가능성(Observability)이다.
본 글에서는 MSA 환경에서 발생하는 문제 상황을 정의하고, 이를 해결하기 위해 어떻게 로그 기반의 Observability를 확보했는지 그 여정을 공유하고자 한다.
Monitoring을 넘어 Observability로
Observability는 제어 이론의 대가인 루돌프 칼만(Rudolf E. Kalman)이 제시한 개념으로, “시스템의 외부 출력만으로 내부 상태를 얼마나 잘 추론할 수 있는가”를 의미한다.
이는 전통적인 모니터링과는 다소 차이가 있다.
- 모니터링(Monitoring): 무엇이(What), 언제(When) 문제가 발생했는지 알려주는 데 중점을 둔다. 이는 우리가 예측 가능한 문제에 대해 미리 정의된 지표를 감시하는 방식이다.
- 관측 가능성(Observability): 무엇이(What), 언제(When) 뿐만 아니라 어떻게(How), 왜(Why) 문제가 발생했는지 답할 수 있는 시스템을 지향한다. 이를 통해 예측하지 못했던 미지의 문제까지도 분석하고 이해할 수 있게 된다.
이러한 Observability를 구성하는 핵심 3요소는 아래와 같다.
- Metrics: 수치화된 시간 기반 지표
- Logs: 이벤트, 상태 변화, 디버깅 정보
- Traces: 요청의 흐름을 서비스 단위로 추적
이제부터 필자가 Logs를 중심으로 어떻게 분산된 시스템의 가시성을 확보했는지 설명해보겠다.
문제 상황: “어디서 발생한 장애지?”
럭스로보의 ‘모디팩토리’ 서비스는 부품 선정부터 발주까지 지원하는 올인원 회로 제작 서비스로, MSA 환경으로 구축되었다. 개발 초기, 각 서비스의 인터페이스를 처음 연동하는 과정에서 수많은 버그가 발생했다. 서비스 간 호출이 복잡하게 얽혀있어 특정 기능이 실패했을 때, 어느 서비스의 문제로 장애가 발생한 것인지 파악하기 어려웠고 데이터의 흐름을 추적하는 데 많은 시간이 소요되었다. 이는 곧 개발 생산성의 저하로 이어졌다.
이 문제를 해결하기 위해, 우리는 비즈니스 요청 단위로 로그 기록을 일괄적으로 조회하고 분석할 수 있는 구조를 만들기로 했다.
해결 전략: 로그 기반 Observability 확보를 위한 3단계
분산된 로그로부터 의미있는 컨텍스트를 찾아내기 위해 다음의 세 가지 전략을 수립했다.
- 로그 표준화 (Log Standardization)
- 분산 트레이싱 연계 (Distributed Tracing Integration)
- 중앙 집중식 로그 수집 (Centralized Log Collection)
1단계: 로그 표준화와 분산 트레이싱 연계
예를들어, MSA 환경에서 사용자의 거래 내역 조회 요청은 비즈니스 관점에서는 하나의 요청이지만, 기술적으로는 App 서버, User 서버, Payment 서버를 거치는 여러 개의 개별 요청으로 이루어진다. 각 서비스가 자신만의 로그를 남긴다면, 이들을 하나의 흐름으로 묶어서 분석하기는 불가능하다.
이를 해결하기 위해 모든 서비스에 걸쳐 로그 포맷을 통일하는 ‘로그 표준화’를 진행했다. 로그에는 timestamp, service_name, log_level 등과 함께, 가장 중요한 식별자인 trace_id 필드를 추가했다. 이 trace_id 필드는 하나의 비즈니스 요청이 시작될 때 발급되어, 해당 요청이 끝날 때까지 모든 하위 서비스로 전파된다. trace_id의 전파는 HTTP 헤더를 통해 이루어진다.
럭스로보에서는 게이트웨이 서버의 미들웨어 단계에서 trace_id를 발급하고, 이 ID를 HTTP 헤더에 담아 각 서비스로 전달하는 방식을 채택했다. (클라이언트에서 발급해도 무방하다.) 이를 통해 여러 서비스에서 흩어져 기록되는 로그들을 trace_id 하나로 묶어 요청의 전체 흐름을 재구성할 수 있게 되었다.
2단계: 중앙 집중식 로그 시스템 구축
로그를 표준화하고 trace_id를 심었다고 해도, 각 서버에 흩어져 있다면 무용지물이다. 분산된 로그를 한곳에 모아 분석하기 위한 ‘중앙 집중식 로그 시스템’이 반드시 필요하다.
우리는 Kubernetes 클러스터 환경에서 실행되는 Go 기반의 마이크로서비스들의 로그를 수집하기 위해서 다음과 같은 아키텍처를 구상했다.
- Log Producer: Go 로그 라이브러리
- Log Storage: Elasticsearch
- Log Visualization: Kibana
초기에는 구조를 단순하게 가져가기 위해 Fluentd 같은 별도의 로그 수집기를 두지 않고, Go 애플리케이션에서 직접 Elasticsearch로 로그를 전송하는 방식을 선택했다. 이 방식은 구조가 단순하고 연동이 빠르다는 장점이 있지만, 로그 버퍼링 기능이 없고 다른 언어의 서비스를 추가할 때 별도의 구현이 필요하다는 단점도 존재한다.
결과: “신속한 디버깅을 통한 명확한 커뮤니케이션”
추적이 가능한 통합 로깅 시스템 구축 이후, 디버깅이 수월해졌고 그 덕분에 명확한 커뮤니케이션이 가능해졌다.
- 신속한 장애 분석 및 디버깅 개발자들은 장애 발생 시 trace_id를 기반으로 관련된 모든 서비스의 로그를 Kibana에서 한 번에 조회하여 문제의 원인을 신속하게 파악할 수 있게 되었다. 이로 인해 디버깅에 소요되던 시간이 단축되었다.
- 명확한 커뮤니케이션 관리자 및 기획자 또한 장애 상황에서 문제의 원인이 되는 서비스와 담당자를 빠르게 식별할 수 있게 되었다. 이는 불필요한 커뮤니케이션 비용을 절감하고, 신속한 의사결정을 가능하게 했다.
- 개발 생산성 향상 특히 신규 개발 및 인터페이스 연동 과정에서 발생하는 문제들을 빠르게 해결할 수 있게 되면서, 프로젝트의 리드 타임이 단축되고 팀의 전반적인 개발 생산성이 향상되었다.
현대의 복잡한 분산 시스템 환경에서 Observability는 선택이 아닌 필수이다. 로그 표준화, 분산 추적 연계, 중앙 집중식 수집이라는 세 가지 전략을 통해 우리는 복잡한 MSA 환경의 내부 동작을 이해하고 예측 불가능한 문제에 대응할 수 있는 기반을 만들었다.
물론 현재의 구조가 완벽하지는 않다. 앞으로 서비스의 수가 더욱 증가하고 다양한 언어 스택이 도입된다면, OpenTelemetry와 같은 표준화된 도구를 도입하여 확장성을 확보하는 방향으로 시스템을 발전시켜 나가야할 것이다.
'시스템구축' 카테고리의 다른 글
SQS FIFO Queue로 구성한 부품 매칭 시스템 구조와 설계 이유 (1) | 2025.07.04 |
---|---|
MSA에서 메서드 분리에서 유스케이스 분리를 고민하는 시점 (0) | 2025.06.21 |
Istio AuthorizationPolicy로 특정 도메인에 대한 IP 접근 제어 설정하기 (0) | 2025.05.08 |
JWT 토큰을 이용한 인증방식 개선: HTTP 헤더에서 쿠키 기반 인증 방식으로 (0) | 2025.02.15 |
쿠버네티스 패키지(kube-prometheus-stack) 관리 이슈 (0) | 2024.12.04 |