본문으로 바로가기

fluentd 가이드 1

category 카테고리 없음 2021. 4. 14. 23:01

난번에 소개했던 에서 여러 가지 log aggregator들을 소개했었다. 이번에는 그중에서도 특별히 마음에 들었던 fluentd를 더 자세히 소개해 보도록 하겠다.

Semi-structured log

 
http://blog.treasure-data.com/post/13047440992/fluentd-the-missing-log-collector-software

 우선 fluentd의 가장 큰 특징은 log를 time/tag/record형식 의 semi-structured 형식으로 저장한다는 것이다.
 시간은 event가 발생한 시간으로 event를 fluentd로 넘겨줄 때 시간을 같이 넘겨주지 않으면, fluentd에서 받은 시간을 기록하게 된다.
 tag는 이벤트를 만들 때 넘기게 되어 있는데, fluentd에서 사용하는 값이다. 이에 대해서는 config를 어떻게 하는지 설명하면서 설명하도록 하겠다.
 record는 사용자가 저장하려고 했던 값들로 json 형식의 key/value pair로 저장된다.
 semi-structured라고 해도 record가 json 형식으로 저장되기 때문에 원하는 형식대로 저장할 수 있다.

Use case

 fluentd는 config파일을 바꾸는 것만으로도 여러 머신들 간의 설정을 쉽게 바꿀 수 있다.

 
http://blog.treasure-data.com/post/16034997056/enabling-facebooks-log-infrastructure-with-fluentd

 위의 그림은 가장 기본적인 형태로 frontend에 붙어 있는 fluentd에서 보내는 이벤트를 중개 서버(?)에 해당하는 fluentd에서 한번 수집하여 최종 저장소에 보내는 형태이다.

 위의 그림은 특별히 fluentd의 성능을 고려하여 하나의 중개 서버가 너무 무리하는 일 없도록 여러 개의 중개 서버에 나누어서 보내는 방식이다.

 

 
http://docs.fluentd.org/articles/high-availability

 위의 그림은 backup server를 두는 방식이다. fluentd는 내부적으로 버퍼를 가지고 있어 일정 시간 서버에 문제가 생기는 것에 대응할 수 있게 되어 있지만, 기본적으로 로그를 저장하기 위해서 쓰이고, 버퍼가 버틸 수 있는 것 이상으로 서버의 문제가 복구되지 않는다면 로그를 버리도록 설계되어 있다.

 그럴 때를 대비하여 backup server를 둘 수 있다. backup server는 보통 때에는 사용하지 않지만, main server에 로그를 남길 수 없을 때 기록을 남긴다.

 

 
http://stackoverflow.com/questions/10525725/which-nosql-database-should-i-use-for-logging

 backup server를 만들 수도 있지만, out_copy plugin을 이용하여 위의 그림처럼 한 개의 소스에서 다른 fluentd 서버로 보낼 수도 있다.

 

 위의 기능들을 다양하게 조합하면 아래와 같은 복잡한 구조도 가능해진다.

 
http://d.hatena.ne.jp/tagomoris/20121029/1351491111

 

Architecture

 
http://blog.treasure-data.com/post/13047440992/fluentd-the-missing-log-collector-software

 fluentd는 크게 plugin을 붙일 수 있는 3부분과 plugin을 이용하는 engine으로 구성되어 있다. engine은 config를 읽어서 사용할 plugin을 결정하고, 설정하는 역할을 한다. 외부의 input을 받고 output으로 내보내는 역할은 전부 plugin에서 하도록 되어 있다. 그렇기 때문에 fluentd의 동작을 이해하려면 각 plugin들이 어떻게 동작하는지 아는 것이 중요하다.

Input plugin

 Input plugin은 외부로부터 이벤트를 받아오거나 외부의 파일을 읽어서 이벤트를 만들어 주는 역할을 한다.
 fluentd 이외의 다른 log aggregator들이 가장 취약한 부분이 이곳이다. 반대로 말하면 fluentd의 최고 장점이 되는 부분이기도 하다.
 scribe같은 경우는 event를 만들어 보내주는 부분을 완전히 새로 작성해야 한다. flume은 이미 구현된 몇 개의 방법을 이용해서 통신하거나, 새로운 plugin을 작성해야 하는데, flume은 plugin을 만들기 쉽게 되어 있지 않다.
 반면에 fluentd의 경우는 이미 많은 plugin들이 만들어져 있어서 필요한 대부분의 plugin을 찾을 수 있고, 찾지 못하더라도 쉽게 plugin을 만들 수 있다.

Buffer plugin

 buffer가 해주는 중요한 기능이 2가지 있다.

 그 중 하나는 output을 효율적으로 내보내는 것이다. log aggregator는 실시간으로 로그를 모아주지만, 모은 로그를 바로 바로 output으로 보낼 이유는 없다. 그래서 fluentd를 비롯한 대부분의 aggregator는 서버에서 일정량의 로그를 모았다가 처리하도록 해준다.
 fluentd에서는 이 단위를 chunk라고 부른다. chunk는 log의 tag 별로 분류되어 저장된다.
 output plugin은 우선 chunk를 queue에 집어넣지 않고 들어오는 log를 chunk에 적는다. 그러다가 chunk의 크기가 일정 이상 커지거나, chunk가 생긴지 일정 시간 이상 지나면 queue에 들어간다.
 chunk는 tag를 key로 하므로 buffer에 들어가지 않고 있는 chunk가 한 개 이상일 수도 있다. queue의 크기를 일정 이상 키우지 않기 위해 queue에 chunk를 집어넣을 때, queue에서 chunk를 1개 빼서 output으로 내보낸다.

 buffer가 해주는 또 다른 중요한 기능은 서버(중개 node이건 최종 저장소이건)에 문제가 생기더라도 log의 유실을 최소화하는 것이다. 하지만 buffer를 사용한다고 해도 메모리가 무한한 것이 아니므로 서버가 오랫동안 문제 있으면 버려지는 데이터가 생긴다.
 fluentd에는 재시도를 하고 그래도 안 되면 버리는 것을 정책으로 삼는다. 정확히는 output으로 나가야 하는 data가 나가지 못했을 때 일정 시간이 지난 후 다시 시도한다. 그래도 실패한다면, 기다렸던 시간의 2배만큼 더 기다리고 다시 시도하기를 반복한다. 일정 횟수를 기다려도 보내는 것에 실패하면 이 데이터는 다음으로 보내지지 않고 버려진다. 이때 기다리는 시간을 retry_wait, 다시 시도하는 횟수를 retry_limit으로 설정할 수 있다.

 이 경우 외에도 fluentd 자체가 문제가 생겨서 꺼지는 경우도 있다. fluentd는 이를 위해서도 buffer의 plugin으로 원하는 종류를 써서 해결할 수 있다. 기본적으로 fluentd가 buffer에 사용하는 것은 buf_memory라는 plugin으로 chunk를 memory에 기록하는 plugin이다. 하지만 서버가 죽었다 살아날 때도 보장하고 싶다면 buf_file plugin을 이용하면 된다. buf_file plugin을 사용하면 chunk의 내용을 file에 보관해 주기 때문에 서버가 다시 켜질 때 file을 읽어와 buffer를 복구해준다. file에 쓰는 만큼 속도가 느려지지만, 안정성이 증가하기도 하고, 사용할 수 있는 buffer의 크기도 커진다.

Output plugin 위에서 architecture를 설명한 그림에는 input -> buffer -> output 순으로 메시지가 전달되는 것처럼 그렸지만, 사실 정확한 구조는 다음과 같다.

 입력은 input plugin을 통해서 들어와 engine을 거쳐서 buffer plugin을 거치지 않고 output plugin으로 나간다. buffer는 engine에서 사용되는 것이 아니라 output plugin 내부에서 사용된다. 왜냐하면, output의 종류에 따라서 buffer가 필요하지 않은 경우가 있어, buffer의 사용 여부를 output plugin이 결정해야 하기 때문이다.

 

 buffer plugin을 사용하지 않는 output plugin을 non-buffered output plugin이라고 부른다.

 대표적인 예가 out_null out_stdout plugin이다.

 out_null의 경우 들어오는 입력을 전부 버리는 plugin이고, out_stdout은 들어오는 입력을 커맨드창에 띄워주는 plugin이다.

 또 다른 경우는 out_copy다. 이 plugin은 하나의 fluentd로 들어온 event를 2개 이상의 output으로 보낼 때 쓰인다. 따라서 뒤에 다른 output plugin이 있고, 이 output plugin이 적절한 buffer를 사용하기 때문에 자체적으로 buffer를 이용할 이유가 없다.

 

 평범하게 buffer plugin을 사용하는 plugin들은 buffered output plugin이라고 부르는데 이 중 일부는 time sliced output plugin이라고 불린다.

 time sliced output plugin은 buffer를 사용하지만, chunk의 key로 tag가 아닌 시간을 사용한다는 것만이 다르다.

 

Configuration

 마지막으로 fluentd를 실제로 어떻게 설정하는지에 대해 설명하면서 마무리하도록 하겠다.
 fluentd의 config문법은 어렵지 않다. 일단 실제 config파일 예시를 한번 보자.

<source>
type forward
</source>
<source>
type http
port 8888
</source>
<match debug.**>
type stdout
</match>
<match myapp.**>
type copy
<store>
type forward
buffer_type file
buffer_path /var/log/fluent/myapp-forward
retry_limit 50
flush_interval 10s
<server>
host 192.168.0.13
</server>
</store>
<store>
type file
path /var/log/fluent/myapp
</store>
</match>

view rawfluentd.conf hosted with ❤ by GitHub


 위에서 보았듯이 fluentd의 설정은 들과 들로 구성되어 있다.

 source 하나는 하나의 input plugin을 의미하고, 하나의 fluentd에 1개 이상의 source가 있을 수 있다. 위의 예시는 forward plugin과 http plugin을 사용하는 경우다.
 위와 같이 설정되어 있으면, forward를 통해서 받을 수 도 있고 http protocol을 이용해서 8888번 포트로 입력을 받을 수도 있다.

 fluentd는 tag별로 다른 output을 사용할 수 있는데, 그 부분을 설정해 주는 것이 match이다.
 쓰여진 순서대로 tag를 match시켜 그 중 첫 번째로 맞는 match에 맞는 output plugin을 이용한다.

 output plugin 중에서 out_copy와 out_roundrobin는 라는 항목이 필요하다.
 out_copy와 out_roundrobin 둘 다 하나의 log를 둘 이상으로 나눠주는 것이기 때문에 실제 사용할 output plugin을 설정해줘야 하는데 그 설정을 하는 부분이 다.

 이 외의 plugin별로 설정해야 할 값들이 있는데, plugin별로 다르므로 하나하나 설명하기는 어렵고, 이에 관해서는 사용할 plugin들에 관해서 reference를 읽고 설정하는 것이 좋다.

 

아래 그림과 같이 각 서버에, Fluentd를 설치하면, 서버에서 기동되고 있는 서버(또는 애플리케이션)에서 로그를 수집해서 중앙 로그 저장소 (Log Store)로 전송 하는 방식이다.

 

 

 

위의 그림은 가장 기본적인 구조로 Fluentd가 로그 수집 에이전트 역할만을 하는 구조인데, 이에 더해서 다음과 같이 각 서버에서 Fluentd에서 수집한 로그를 다른 Fluentd로 보내서 이 Fluentd가 최종적으로 로그 저장소에 저장하도록 할 수 도 있다.

 

중간에 fluentd를 넣는 이유는, 이 fluentd가 앞에서 들어오는 로그들을 수집해서 로그 저장소에 넣기 전에 로그 트래픽을 Throttling (속도 조절)을 해서 로그 저장소의 용량에 맞게 트래픽을 조정을 할 수 있다.

또는 다음 그림과 같이 로그를 여러개의 저장소에 복제해서 저장하거나 로그의 종류에 따라서 각각 다른 로그 저장소로 라우팅이 가능하다.



출처: https://bcho.tistory.com/1115 [조대협의 블로그]

 

안녕하세요.

김대리입니다.

 

이번엔 EFK (Elasticsearch + Fluentd + Kibana)를 통해서 

데이터를 저장, 수집, 시각화 하는 내용을 쓰려고 한다.

 

그 중 오늘은 Fluentd를 간략히 설명하려고 한다.

 

 

1. Fluentd란?

Opensource Data collector중 하나이다. 

보통 다양한 채널에서 들어오는 데이터들을 통합하기위해 사용된다.

 

  • 홈페지이지: www.fluentd.org
  • 설치가이드: docs.fluentd.org/categories/installation

 

 

이렇게 통합된 데이터 수집이 중요한 이유는

데이터 분석을 하기 전에 이루어지는 

데이터 정제를 더 수월하게 할 수 있기 때문이다.

 

Fluentd는 각각의 데이터를 JSON구조로 일관성 있게 변환함으로 

이후 이루어질 분석을 더 수월하게 해준다.

 

 

2. 설치 환경

이번 EFK 환경 구성은 윈도우10에서 해볼 예정.

 

(윈도우 외에도 리눅스, Mac, Docker 등에서 지원)

 

3. 설치 및 간단한 테스트

 

step (1)

 

td-agent 설치파일 다운로드

 - *.msi형태로 설치만 하면 된다.

 

 

 

설치 하면 fluetd 명령어를 실행 할 수 있는 prompt가 생긴다

 

step (2) 간단한 테스트

 

> fluentd -c etc\td-agent\td-agent.conf

---> td-agent.conf 란 설정을 적용하여 fluentd 서비스 실행

 

 

 

중간에 방화벽 관련 권한확인 창이 뜨면

엑세스 허용~

 

 

fluentd가 정상적으로 실행되었음을 확인한다.

 

 

 

>echo {"message":"hello"} | fluent-cat test.event

---> prompt 창에서 echo를 통해서 stdout으로 발생된 메시지를

 fluentd가 matching하는 간단한 예제

 

 

 

 

여기서 유심히 봐야할 부분은

 

첫번째 실행한 echo는 no patterns matched 라고 메시지가 나온다

현재 td-agnet.conf에 적용된 match pattern은

debug.**로 되어있기 때문이다.

 

그래서 tag를 debug.devent로 주게되면

정상적으로 debug.event라고 

prompt창에 출력되는 것을 확인할 수 있다.

 

이렇게 간단한 예제를 통해서 

시스템에서 발생하는 또는 

서비스가 발생시키는 메시지를 

수집하여 특정 리파지토리

또는 단순 출력 등

 

다양하게 활용 할 수 있다.