# Fluentd

### Fluentd 와 Azure Log Analytics 로 로그 통합관리 아키텍처를 구축한 경험.

서비스를 운영하다 보면 로그는 문제를 해결하는 가장 중요한 단서가 된다.&#x20;

하지만 내가 경험했던 환경은 로그를 "잘 활용하는 구조" 라기 보다, **일단 남기고 버티는 구조** 에 가까웠다.

당시 가장 큰 문제는 **로그 삭제 정책이 없었다는 점** 이었다.&#x20;

로그는 계속 쌓였고, 서버에서는 이를 bzip2 로 압축하면서 버티고 있었다. 평소에는 어떻게든 운영이 가능했지만, LostArk 게임 오픈 이후 유저 유입이 크게 늘면서 로그 적재 속도도 급격히 증가했다. 그 결과 디스크 사용량이 빠르게 차올랐고, 서버가 다운되는 횟수도 늘어났다.

문제를 완화하기 위해 서버를 스케일 아웃했지만, 또 다른 문제가 생겼다.

기존에는 장애가 발생하면 각 서버 4대에 들어가 로그를 확인하고 대응했는데, 서버 수가 10대로 늘어나면서 **장애 시 로그를 찾는 시간 자체가 크게 늘어났다.**

즉, 단순히 저장 공간의 문제만이 아니라 **운영 대응 방식 자체가 한계에 도달한 상태** 였다.

그래서 이 문제를 해결하기 위해 **Fluentd + Azure Log Analytics** 기반의 로그 통합 관리 아키텍처를 도입했다.

#### 기존 방식의 한계

기존 로그 운영 방식은 크게 두 가지 한계를 가지고 있었다.

**1. 로그가 서버에 계속 쌓였다.**

삭제 정책이 없다 보니 디스크 사용량이 계속 증가했고, 압축으로 버티는 방식은 근본적인 해결책이 아니었다.

트래픽이 늘어나자 결국 서버 장애로 이어졌다.

**2. 장애 대응이 서버 수에 비례해 느려졌다**

장애가 나면 운영자가 서버마다 직접 접속해 로그를 확인해야 했다.

서버가 4대일 때는 어떻게든 가능했지만, 10대로 늘어나자 같은 방식으로는 대응 속도를 유지하기 어려웠다.

이 문제를 통해 느낀건, 로그는 단순히 "쌓이는 데이터"가 아니라 **운영 효율과 장애 대응 속도에 직접 영향을 주는 인프라 요소** 라는 점이었다.

***

#### 왜 Fluentd 를 선택했는가

로그 통합 아키텍처를 설계하면서 Fluentd 를 선택한 이유는 세 가지였다.

#### 벤더 종속성을 낮출 수 있었다.

특정 클라우드 전용 에이전트만 사용할 경우, 향후 멀티 클라우드나 온프레미스 환경으로 확장할 때 수집 로직을 다시 설계해야 할 수 잇다.

반면 Fluentd 는 중간 수집 계층으로 두기 좋았고, **클라우드가 바뀌어도 동일한 수집 구조를 유지할 수 있는 유연성** 이 있었다.

#### 다양한 로그를 하낭의 계층에서 표준화할 수 있었다.

애플리케이션 로그, 시스템 로그 등은 포맷이 다를 수 있다.

Fluentd 를 사용하면 이 로그들을 하나의 계층에서 받아 **JSON 형태로 표준화해서 전송** 할 수 있었다.

#### 태그 기반 라우팅이 유용했다.&#x20;

Error, Info, Access 같은 로그 성격에 따라 서로 다른 테이블로 보내거나 특정 로그만 필터링하는 구성이 필요했다.

Fluentd는 이런 로직을 애플리케이션 코드가 아니라 **설정 파일 수준에서 제어** 할 수 있다는 점이 장점이었다.

***

### 아키텍처 구성

내가 구성한 구조는 다음과 같았다.

* **Fluentd** : 로그 수집 및 전송
* **Azure Log Analytics** : 실시간 검색 및 분석
* **Azure Storage** : 장기 보관용 저장소

이 구조를 통해 최근 로그는 빠르게 조회하고, 오래된 로그는 저렴한 저장소에 보관하는 **계층형 저장 전략(Tiered Storage)** 을 가져갈 수 있었다.

***

### 계층형 저장 전략을 적용한 이유

모든 로그를 Log Analytics 에만 넣는 방식은 편리하지만 비용 문제가 있다.

#### Log Analytics

* 검색과 쿼리가 빠름.
* 실시간 모니터링에 적합
* 하지만 보관 비용이 상대적으로 높음.

#### Azure Storage

* 장기 저장 비용이 저렴함.
* 법적 보관, 사후 분석, 백업 목적에 적합

그래서 최근 데이터는 Log Analytics 로 보내고, 전체 로그는 Storage 에도 저장하는 방식으로 분리했다.

이렇게 하면 :&#x20;

* 최근 장애 대응은 빠르게 할 수 있고
* 오래된 로그는 저렴하게 보관할 수 있으며
* 보관 주기가 지난 로그도 필요 시 다 꺼내볼 수 있다.

죽, **운영 효율성과 비용 효율성을 동시에 잡을 수 있었다.**

***

### Fluentd 의 장점

구축하면서 느낀 Fluentd 의 장점은 다음과 같았다.

#### 1. 플러그인 생태계

`fluent-plugin-azure-loganalytics`, `fluent-plugin-auzrestorage` 같은 플러그인을 통해 Azure 와의 연동을 비교적 쉽게 구성할 수 있었다.

#### 2. 버퍼링을 통한 신뢰성

네트워크 지연이나 Azure API 응답 지연이 발생해도, 로그를 버퍼에 저장했다가 나중에 재전송할 수 있었다.

운영에서는 이 기능이 특히 중요했다.

#### 3. 라우팅 유연성

태그 기반으로 로그 흐름을 분기할 수 있어서, 로그 종류에 따라 다른 테이블이나 저장소로 보내는 구성이 편했다.

***

### 단점과 대응

물론 Fluentd 가 무조건 단순한 건 아니었다.&#x20;

#### 설정 복잡도

플러그인이 늘어날수록 설정 파일이 길어지고 관리가 어려워질 수 있다.

이 문제는 설정 파일 분리나 환경별 구성 분리를 통해 유지보수성을 높이는 방식으로 대응할 수 있었다.

#### Ruby 의존성

일부 플러그인은 Ruby Gem 버전 이슈가 발생할 수 있었다.

실제로 이런 문제를 줄이기 위해 Ruby 및 Gem 버전을 통일하고, 안정적인 버전 조합을 유지하는 게 중요했다.

***

### 실제 적용 흐름

실제 서버 적용 시에는 먼저 OS 레벨에서 `nofile` 설정을 확인해 파일 핸들 수를 늘렸고, 이후 Ruby/rbenv/Fluentd/ 플러그인을 설치한 뒤 서비스로 등록해 운영했다.

구성의 핵심은 아래와 같았다.

* `tail` 방식으로 애플리케이션 로그 파일 수집
* `regexp` 파싱으로 필요한 필드 추출
* `tag` 를 기준으로 로그 분류
* `azure-loganalytics` 플러그인으로 Azure Log Analytics 전송

설치와 서비스 등록 과정 자체도 중요했지만, 실제로 더 중요했던 건 **로그를 어떤 기준으로 나누고, 어떤 저장소로 보내며, 운영에서 어떻게 활용할 수 있게 만들 것인가** 였다.

***

### 결과&#x20;

이 구조를 적용한 이후 기대한 효과는 명확했다.

* 서버 로컬 디스크에 로그가 게속 쌓여 장애로 이어지는 문제를 줄일 수 있었다.
* 여러 서버에서 발생하는 로그를 중앙에서 검색하고 분석할 수 있게 되었다.
* 최근 로그는 빠르게 조회하고, 오래된 로그는 저렴하게 장기 보관할 수 있게 되었다.

즉, 단순히 로그를 "모은 것" 이 아니라 **운영 가능한 로그 시스템으로 바꾼 것** 에 의미가 있었다.

***

### 배운 점

이 경험을 통해 얻은 교훈은 세 가지였다.&#x20;

첫째, 로그는 저장 공간의 문제가 아니라 **운영 구조의 문제** 이기도 하다.

둘째, 로그 시스템은 설치보다 **수집, 분석, 보관 전략** 이 더 중요하다.

셋째, 장애 대응 속도를 높이려면 로그를 남기는 것을 넘어서 **중앙에서 활용 가능하게 만들어야 한다.**

결국 Fluentd 도입 경험은 단순 설치 경험이 아니라, **로그 폭증과 장애 대응 비효율 문제를 해결하기 위해 중앙 로그 아키텍처를 설계·적용한 경험** 으로 남았다.

***

### 설치&#x20;

#### 1. Server Nofile nproc 확인

```
sudo cat /etc/security/limits.conf

#@student        hard    nproc           20
#@faculty        soft    nproc           20
#@faculty        hard    nproc           50
#ftp             hard    nproc           0
#@student        -       maxlogins       4
*               soft     nofile         65536
*               hard     nofile         65536
<계정>        soft     nofile         65536
<계정>        hard     nofile         65536

## 현재 유저 및 root 유저의 nofile, nproc 확인 nofile 만 확인해도 된다.
```

안되 있으면 nofile 개수를 65536 으로 설정 후 서버 재시작

```
sudo reboot
```

#### 2. Ruby 설치

```
#필수 yum 설치
sudo yum install git-core zlib zlib-devel gcc-c++ patch readline readline-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison curl sqlite-devel
#rbenv 설치
sudo curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash
```

```
# 환경 변수 설정
sudo vi /etc/profile(전 사용자)
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)" 
#vi 종료 후
source /etc/profile
```

```ini
#설치 가능 버전 확인
rbenv install -l
2.6.10
2.7.3
3.0.1
jruby-9.2.19.0
mruby-3.0.0
rbx-5.0
truffleruby-21.1.0
truffleruby+graalvm-21.1.0
```

```ini
#확인 후 
rbenv install 2.6.10
#global 등록
rbenv global 2.6.10
ruby --version
2.6.10
#ruby bin 경로로 이동
cd /home/<계정>/.rbenv/versions/2.6.10/bin
#nokogiri 설치
sudo ./gem install nokogiri --platform=ruby ## 컴파일된 버전
# nokogiri 가 glibc 1.7 이상이면 설치 안해도 된다. 하지만 1.7 미만이면 컴파일 된 버전을 설치한다.
#fluentd 설치
sudo ./gem install fluentd -v 1.15.0
#fluentd 에서 사용할 plugin 설치
sudo ./gem install fluent-plugin-azurestorage
sudo ./gem install fluent-plugin-azure-loganalytics
```

```ini
#fluentd 실행 스크립트 생성(서비스 등록)
cd /etc/init.d/
sudo vi fluentd
#!/bin/sh   
# chkconfig: 2345 90 90 
# description: init file for fluentd
# processname: fluentd
RETVAL=0 
PNAME=fluentd 
PID=`ps -ef| grep "^.*\/home/happytuk/.rbenv/versions/2.6.10/bin/fluentd --user root --group root --daemon /var/run/fluentd.pid$" | grep -v 'grep' | awk '{print $2}'` 
case "$1" in 
        start)
                echo /home/happytuk/.rbenv/versions/2.6.10/bin/fluentd --user root --group root --daemon /var/run/fluentd.pid
                RETVAL=$?
                echo $RETVAL
      ;;
        stop)
                if [ $PID -gt 0 ];then
                        echo /home/happytuk/.rbenv/versions/2.6.10/bin/fluent-ctl shutdown $PID
                        RETVAL=$?
                elif [ -z $PID ];then
                        echo fluentd is not running
                fi
      ;;
        restart)
                if [ $PID -gt 0 ];then
                        echo /home/happytuk/.rbenv/versions/2.6.10/bin/fluent-ctl restart $PID
                        RETVAL=$?
                elif [ -z $PID ];then
                        echo fluentd is not running
                fi
      ;;
        *)
                echo "Usage: fluentd {start|stop|restart}"
                exit 1
      ;;
    esac
        echo $RETVAL
    exit $RETVAL
#스크립트 실행 권한
sudo chmod +x fluentd
#서비스 등록
sudo chconfig --add fluentd
#실행
sudo service fluentd start
# pid 저장 할 파일 생성
sudo vi /var/run/fluentd.pid
# 권한 변경
sudo chown <계정>:<계정> /var/run/fluentd.pid
# fluentd 로그 파일 생성할 폴더 생성 및 권한 변경
sudo mkdir /var/log/fluentd
sudo chown -R <계정>:<계정> /var/log/fluentd
```

```ini
#config 파일 작성할 폴더 생성(없으면)
cd /etc/
sudo mkdir fluent
sudo vi fluent.conf
#log analytics config
<source>
  @type tail
  <parse>
  @type regexp
  expression /^\[(?<timestamp>\d{4}\-\d{2}\-\d{2} \d{2}\:\d{2}\:\d{2})\] \[(?<host_client_ip>.*?)\] \[(?<param>.*?)\] \[(?<header>.*?)\]$/
 </parse>
  path /<api 관련 path>/*/*/%Y-%m-%d.txt
  pos_file /<pos 파일 저장경로>/log_file.pos
  tag request.*
</source>
<match response.**>
    @type azure-loganalytics
    customer_id <customer_id>
    shared_key <shared_key>
    log_type QAAccessLog
    add_time_field true
    time_field_name testtime
    time_format %FT%T%z
    localtime true
    add_tag_field true
    tag_field_name api
</match>
<match request.**>
    @type azure-loganalytics
    customer_id <customer_id>
    shared_key <shared_key>
    log_type QAAccessLog
    add_time_field true
    time_field_name testtime
    time_format %FT%T%z
    localtime true
    add_tag_field true
    tag_field_name api
</match>
# 저장 후 실행
sudo service fluentd start
# 잘 실행 되는지 log file tail
tail -f /var/log/fluentd/fluentd.log
#에러 없이 뜨는지 확인 후 종료
```

```ini
fluentd의 conf 파일 작성 법은 공식홈페이지에서 확인하면된다.
<source> 작성 법
https://docs.fluentd.org/input
<match> 작성 법
https://docs.fluentd.org/output
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wjddustkd45.gitbook.io/organizeme/company-org/fluentd.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
