Fluentd는 로그데이터 수집기 이다. 보통 로그를 수집하는 데 사용하지만 다양한 데이터 소스로부터 데이터를 받아 올 수 있다. Fluentd로 전달된 데이터는 tag,time,record(json)로 구성된 이벤트로 처리되며, 원하는 형태로 가공되어 당양한 목적지(Elasticsearch,S3등)로 전달 될 수 있다.
Fluentd는 C와 Ruby로 개발 됐다. 더 적은 메모리를 사용해야 하는 환경에서는 제공하는 Fluentd-bit라는 경량화 버전과 함께 사용 할 수 있다. 데이터 유실을 막기 위해 메모리와 파일 기반의 버퍼 시스템을 갖고 있으며, Failover를 위한 HA 구성도 가능하다.
이벤트 | Event
Fluentd가 읽어들인 데이터는 tag, time, record 로 구성된 이벤트(Event) 로 처리된다.
Fluentd의 특징 중에 가장 핵심은 태그(Tag) 이다. 태그는 이벤트가 흘러가면서 적절한 Filter, Parser 그리고 Output 플러그인으로 이동할 수 있는 기준이 된다.
아래 예시의 경우 input_tail 플러그인으로 전달된 이벤트에는 dev.sample라는 태그가 붙게 된다.
ex)
# tag 사용 예시
<source>
@type tail
tag dev.sample
path /var/log/sample.log
</source>
<match dev.sample>
@type stdout
<match>
먼저 Fluentd를 어떻게 쓸 수 있는지 알아보는 것이 이해에 도움이 될 것 같다.
어플리케이션 로그를 한곳으로 모으기 (예: Python 로그, PHP 로그)
서비스 로그 모니터링 (예: Elasticsearch와 Kibana)
데이터 분석을 위한 hdfs로 적재하기
AWS S3로 데이터 저장
Stream 데이터 처리
Fluentd는 원하는 기능들을 플러그인 방식으로 설정 파일에 추가함으로써 사용할 수 있다.
전체적인 동작 흐름은 Input -> Filter -> Buffer -> Output 단계로 동작하며, 세부적으로 7개의 플러그인(Input, Parser, Filter, Fomatter, Storage, Buffer, Output)을 목적대로 자유롭게 활용할 수 있다.
Fluentd를 설치하고, 작성한 설정 파일을 환경변수 FLUENT_CONF에 명시하거나 -c 실행 파라미터 에 전달하면 된다.
# export FLUENT_CONF="/etc/fluent/fluent.conf"
fluentd -c /etc/fluent/fluent.conf
Input 플러그인
다양한 데이터 소스로부터 로그 데이터를 받거나 가져온다.
대표적인 in_tail 플러그인은 파일을 tail 해서 데이터를 읽어 들인다. 단 파일의 시작부터 읽지 않으며, 로테이팅 되어 새로운 파일이 생성된 경우에만 처음부터 읽게 된다.
그리고 해당 파일의 inode를 추적하기 때문에 pos_file 파라미터를 사용할 경우 fluentd가 재실행 되었을 때 파일의 마지막에 읽은 부분부터 다시 처리하게 된다.
doc
in_forward
forward라는 프로토콜을 사용해 TCP로 데이터를 수신할 수 있다. 보통 다른 Fluentd 노드로부터 데이터를 전달받기 위해 사용한다.
forward로 전달되는 데이터는 JSON이나 Messagepack 형식으로 되어 있다. fluentd 인스턴스를 멀티 프로세스로 실행 했을때는 각각의 프로세스가 동일한 forward 포트를 공유하게 된다.
doc
Parser 플러그인
전달 받은 데이터를 파싱하기 위해 parse 섹션을 정의해서 사용한다.
parse 섹션은 Input 플러그인(source), Output 플러그인(match), Filter 플러그인(filter) 안에서 정의하며, @type 파라미터로 사용할 Parser 플러그인 이름을 지정한다.
기본적으로 내장된 Parser 플러그인은 regexp, apache2, nginx, syslog, csv, tsv, json, none 등이 있다.
정규표현식으로 데이터를 파싱할 수 있는 Parser이다.
정규표현식 패턴은 expression 파라미터에 명시하며, 반드시 최소 1개 이상의 캡쳐 그룹과 time 캡쳐 그룹이 필요하다.
time 캡쳐 그룹의 키 이름은 time_key 파라미터로 변경할 수 있다.
시간과 관련된 추가 파라미터로는 시간 포맷을 지정할 수 있는 time_format과 타임존을 설정하는 timezone 파리미터가 있다.
<parse>
@type regexp
expression /^(?<remote_addr>[^ ]+) "(?<http_x_forwarded_for>([^ ]+(, )?)+)" (?<http_x_client>[^ ]+) \[(?<timestamp>(0?[1-9]|[12][0-9]|3[01])/[a-zA-Z]+/\d\d\d\d:(00|0[0-9]|1[0-9]|2[0-3]):([0-9]|[0-5][0-9]):([0-9]|[0-5][0-9]) \+[0-9]+)\] "(?<request_method>\S+) (?<request_uri>[^"]+) (?<server_protocol>[^"]+)" (?<status_code>\d{3}) (?<body_byte_sent>\d+) "(?<http_referer>[^"]*)" "(?<http_user_agent>.+)" (?<request_time>[^ ]+)$/
time_key timestamp
time_format %d/%b/%Y:%H:%M:%S %z
timezone +09:00
</parse>
Buffering과 Flushing에 대해서는 3가지 모드를 제공한다.
Non-Buffered mode: 데이터를 buffer에 담지않고, 즉시 내보낸다.
Synchronous Buffered mode: stage 라는 buffer chunk에 담고, 이 chunk를 queue 에 쌓아서 처리한다.
Asynchronous Buffered mode: Synchronous buffered mode와 동일하게 stage 와 queue 가 있지만 동기 방식으로 chunk를 만들지 않는다.
Output 플러그인은 buffer chunk에 key를 지정할 수 있으며, key와 동일한 이름을 갖는 이벤트를 분리해서 chunk에 담도록 설정할 수 있다.
Fluentd를 이용해서 로그 수집 아키텍쳐를 구성하는 방법을 대략적으로 알아보았는데, 그렇다면 Fluentd 자체의 구조는 어떻게 되어 있을까?
Input,Parser,Engine,Filter,Buffer,Ouput,Formatter 7개의 컴포넌트로 구성이 된다. 7개의 컴포넌트중 Engine을 제외한 나머지 6개는 플러그인 형태로 제공이 되서 사용자가 설정이 가능하다.
일반적인 데이타 흐름은 Input → Engine → Output 의 흐름으로 이루어 지고, Parser, Buffer, Filter, Formatter 등은 설정에 따라서 선택적으로 추가 또는 삭제할 수 있다.