안녕하세요, 기린입니다.
이번에 간단하게 시스템 로그를 수집 후 모니터링하는 시스템을 구축해보았는데요. 조사한 내용 중에 좋은 글이 있어 공유하고자 합니다.
0. 모니터링 시스템 구조
대부분의 기업에서 많이 쓰는 모니터링 시스템 구조입니다. Beats로 로그를 수집해 Kafka로 보내고 Logstash가 Kafka의 로그를 가져가 Elasticsearch에 저장. Kibana로 저장된 데이터를 시각화 해주는 구조입니다.
저도 이게 당연한 구조인 줄 알았는데요. Logstash를 알아보다 보니 굳이 Kafka를 써야할까? 라는 의문이 들었습니다.
Logstash가 Kafka가 수행하는 메시지 브로커의 역할을 수행할 수 있게 하는 옵션을 가지고 있기 때문이었습니다.
(참고) Kafka는 대용량의 실시간 로그처리에 특화된 MQ(Message Queue)입니다.
1. Logstash
Logstash는 실시간 파이프라인 기능을 가진 데이터 수집 엔진입니다.
입력(Inputs) 기능에서 다양한 데이터 저장소로부터 데이터를 입력 받고 필터(Filters) 기능을 통해 데이터를 확장, 변경, 필터링 및 삭제 등의 처리를 통해 데이터를 원하는 형식으로 가공합니다.
그 후 출력(Outputs) 기능을 통해 다양한 데이터 저장소(Elasticsearch, AWS S3 등)로 데이터를 전송하게 됩니다.
(1) Buffer
Logstash는 입력과 필터/출력 사이의 과정에서 버퍼를 지원하기 위해 in-memory bouned queue를 사용합니다. 이 in-memory 사이즈는 고정되어 있고 별도 설정이 불가능합니다. in-memory 특성상 Logstash 인스턴스에 문제가 생기면 버퍼하고 있던 데이터는 유실됩니다. 그래서 Logstash에서는 비정상적인 종료로 데이터가 유실되는 것을 막기위해 디스크에 버퍼된 데이터를 저장하는 PQ(persistent queue) 기능을 제공합니다.
즉, 버퍼 기능을 위해 Kafka와 같은 추가적인 Queue Layer를 구성하지 않아도 PQ 기능으로 대체할 수 있습니다.
그래도 Kafka-Logstash 조합은 많이 사용되는 구조입니다. PQ를 제공하고 있음에도 Kafka를 조합하는 이유를 알기 위해 PQ에 대해 좀 더 알아보겠습니다.
2. Persistent Queue
앞서 말했듯, PQ는 in-memory에 저장한 데이터의 유실을 방지하기 위해 설계되었습니다.
(1) PQ의 기능
- At-Least-Once 지원
PQ는 in-memory를 사용하여 발생하는 데이터 유실을 방지하기 위해 설계되었다. 데이터 유실을 방지하기 위해 최소 한번은 전달에 실패할 경우 Logstash를 다시 시작해 전달되지 않은 데이터를 다시 전달한다. 데이터 손실을 방지하는 것이 목표이므로 중복이 발생할 수 있고, 중복은 출력 결과를 받는 컴포넌트에서 해결해야 한다.
- Spooling
스풀링은 입력장치와 출력장치의 처리속도 차이를 보완하기 위한 방법으로, 하드디스크를 일시적인 저장소로 사용하는 것을 말한다.
Logstash의 경우 PQ 앞으로는 입력을 받고, 뒤로는 필터링 및 내보내기를 한다. 입력받는 속도가 더 빠른 경우 Spooling이 필요하다.
(2) PQ가 사용되는 Logstash 구조
PQ는 입력과 필터/출력 사이에서 동작하며 아직 처리되지 않은 이벤트에 대해서 버퍼 처리(=Kafka가 가장 잘하는 일)를 합니다.
이후 출력 플러그인을 통해 데이터가 출력된 것을 감지하면 이벤트 처리가 완료되었음을 기록합니다.
(3) PQ 성능 관련
앞서 언급했듯이 in-memory의 특성을 보완하기 위해 저장소로 디스크를 사용하고 있습니다. 그래서 PQ를 사용하면 어쩔 수 없이 성능에 영향이 생깁니다.
- Logstash 5.4 version에서 in-memory와 PQ의 성능 벤치마크 결과 (약 10% 성능 차이 확인)
기본적으로 PQ는 OS 수준 충돌 시 잠재적인 데이터 손실을 줄이기 위해 1024(default)개의 수신된 입력 이벤트 마다 데이터를 디스크에 강제로 쓰는데, 만약 1024개의 이벤트가 도달되지 않은 채로 Logstash가 종료되면 디스크에 쓰지 못하기 때문에 데이터 유실이 발생합니다.
위 문제를 해결하기 위해서는 이벤트가 발생할 때마다 디스크에 입력할 수 있도록 설정을 변경해줘야 합니다. 가장 좋은 건 1024값을 1로 변경해 이벤트가 올때마다 디스크에 쓰면 되지만, 이렇게 하면 I/O 성능이 감소하는 문제가 있습니다.
결론적으로 PQ를 버퍼 용도로 사용하기 위해서는 입력 데이터와 PQ 구성 사이에 균형을 반드시 확인해야 한다는 점입니다. 그리고 확인이 가능하다는 것은 입력 데이터 크기와 속도를 어느정도 예상할 수 있어야 한다는 뜻입니다.
예상할 수 없다면? Message Queue를 써야겠습니다.
3. 정리 (Logstash와 Kafka의 기능적 차이)
(1) Logstash
- 입력을 받고 필터링 후 결과를 DB로 보내는 역할 수행
- 모든 역할을 수행할 수 있지만, 다양한 환경에서 모든 일을 전부 잘하기는 어려움
- Single instance
- 여러 인스턴스를 구동 시키더라도 서로의 상태를 알 수는 없음
(2) Kafka
- 메세지 브로커의 역할을 잘 수행할 수 있고 데이터를 통합하는 공간으로도 사용될 수 있음
- Cluster로 묶이고 작업에 함께 사용되어지도록 할 수 있다.
- 노드(프로세스)를 자동으로 다룰 수 있음
- 분산 시스템으로 동작하도록 설정하면 중지된 다른 프로세스를 다룰 수 있음
- 클러스터 동작하기 때문에 고가용성을 제공하고 확장성이 뛰어나다. 물론 인스턴스를 scale-out 하는 것이 가능하지만 비용적으로 필요한만큼 scale-out 하는 것보다 저렴
4. 결론
Kafka 없이도 Logstash의 PQ 기능을 통해 최대한 들어오는 데이터를 유실 없이 DB에 전달할 수는 있습니다.
하지만 입력 데이터의 발생 속도 및 크기를 예측할 수 없다면? 데이터 유실을 방지할 Kafka, RabbitMQ와 같은 추가 구성이 필요하겠습니다!
<참조>
'OpenSource' 카테고리의 다른 글
WEB - WAS를 연동해서 쓰는 이유 (1) | 2022.03.18 |
---|---|
Elasticsearch가 왜 느려졌을까? (1) | 2022.02.18 |