Architecture/ELK

Elastic Stack 아주 조금만 알아보자 - LogStash 실습 1

KOOCCI 2019. 12. 13. 23:49

인구분석 실습

인구 분석 데이터를 가져와, Kibana까지 이어지는 흐름을 한번 만들어 보자.

 

데이터의 위치는 다음과 같다. (인프런 강의 내용)

https://github.com/minsuk-heo/BigData/blob/master/ch06/populationbycountry19802010millions.csv

 

minsuk-heo/BigData

Contribute to minsuk-heo/BigData development by creating an account on GitHub.

github.com

위 데이터는 1980년부터 2010년까지 이어진 나라별 인구분포를 모아둔 데이터이다.

 

일단 LogStash를 실행하기전에 ElasticSearch와 Kibana가 정상적으로 구동중인지 먼저 확인하자.

ps -ef | grep elasticsearch
ps -ef | grep kibana

두가지로 프로세스가 돌고 있는지 확인하자.

 

Config

그럼 이제 logStash의 Config 를 한번 정의해보도록 하자.

input {
  file {
    path => "/home/minsuk/Documents/git-repo/BigData/ch06/populationbycountry19802010millions.csv"
    start_position => "beginning"  
    sincedb_path => "/dev/null"  
  }
}
filter {
  csv {
      separator => ","
      columns => ["Country","1980","1981","1982","1983","1984","1985","1986","1987","1988","1989","1990","1991","1992","1993","1994","1995","1996","1997","1998","1999","2000","2001","2002","2003","2004","2005","2006","2007","2008","2009","2010"]
  }
  mutate {convert => ["1980", "float"]}
  mutate {convert => ["1981", "float"]}
  mutate {convert => ["1982", "float"]}
  mutate {convert => ["1983", "float"]}
  mutate {convert => ["1984", "float"]}
  mutate {convert => ["1985", "float"]}
  mutate {convert => ["1986", "float"]}
  mutate {convert => ["1987", "float"]}
  mutate {convert => ["1988", "float"]}
  mutate {convert => ["1989", "float"]}
  mutate {convert => ["1990", "float"]}
  mutate {convert => ["1991", "float"]}
  mutate {convert => ["1992", "float"]}
  mutate {convert => ["1993", "float"]}
  mutate {convert => ["1994", "float"]}
  mutate {convert => ["1995", "float"]}
  mutate {convert => ["1996", "float"]}
  mutate {convert => ["1997", "float"]}
  mutate {convert => ["1998", "float"]}
  mutate {convert => ["1999", "float"]}
  mutate {convert => ["2000", "float"]}
  mutate {convert => ["2001", "float"]}
  mutate {convert => ["2002", "float"]}
  mutate {convert => ["2003", "float"]}
  mutate {convert => ["2004", "float"]}
  mutate {convert => ["2005", "float"]}
  mutate {convert => ["2006", "float"]}
  mutate {convert => ["2007", "float"]}
  mutate {convert => ["2008", "float"]}
  mutate {convert => ["2009", "float"]}
  mutate {convert => ["2010", "float"]}
}
output {  
    elasticsearch {
        hosts => "localhost"
        index => "population"
    }
    stdout {}
}

Input (입력)

inputfile 로 되어있고, 그에 따라 path를 정의해두었다.

start_position은 파일의 어디부터 읽을지 정하며, sincedb_path를 통해 LogStash를 다시 시작해도 읽을 수 있는 설정을 해두었다.

 

위 설정과 관련해서 조금 더 정리해보도록 하겠다. 해당 내용은 LogStash의 Offset 관리를 설명해주며, 제대로 파악을 안한다면 로그 유실의 위험이 있으니 확실히 알고 넘어가는 것이 좋다.

 

1. start_position

 

start_position은 중요하면서도 헷갈리는 내용이다.

LogStash를 시작할 때 file의 어디부터 읽을 지 결정하며 2가지를 지원한다.

 

  1.  beginning
  2. end (default)

이것은 파일을 최초로 읽을 때만 적용된다. 즉, beginning으로 설정했을 때 LogStash를 여러번 restart하면 항상 같은 내용일 것이라 착각할 수 있지만, 실제로 출력은 그렇지 않다.

 

위 내용은 이후 알아볼 sincedb와 연결되는데, sincedb에 offset 정보가 있으면(최초가 아니면) 해당 offset부터 파일을 읽게 되며, 없다면 beginning, end 설정 방식으로 동작한다.

 

defaultend인 이유는 기본 동작으로 file을 live stream으로 취급하여 끝(end)부터 시작하려고 하기 때문이다.

 

2. sincedb

위  start_position과 이어서, sincedb의 경우, file을 사용했을 때, 해당 파일 offset을 저장하는 용도이다.

4개의 column으로 되어 있으며, 구성은 다음과 같다.

The inode number (or equivalent).
The major device number of the file system (or equivalent).
The minor device number of the file system (or equivalent).
The current byte offset within the file.
inode
inode는 유닉스 계통 파일 시스템에서 주로 사용하는 자료구조로, 파일, 디렉토리 등 파일 시스템에 관한 정보를 가지고 있다.
[참조] http://egloos.zum.com/depiness/v/911126
22253332 1 3 14323

즉 위와 같이 저장되어 있다는 말은, 22253332번파일은 현재14323번 offset까지 처리가 되었다는 것을 의미한다.

이 때, LogStash를 재시작하면 beginning이나 end에 상관없이 해당 offset에서 재시작이 된다.

 

그렇다면, 위에서 로그 유실은 어떤 상황에서 나오게 될까?

 

먼저 LogStash 설정 상 수정이 가능한 2가지 변수를 알아두자.

  • stat_interval
    • 파일이 갱신되었는지 확인하는 주기. (Default: 1sec)
  • discover_interval
    • file pattern에 맞는 file이 생성되었는지 확인하는 주기.

위 두 변수가 있는 이유는 파일이 갱신되는 것과, 파일 생성이 다르다는 것이다.

 

Rotate Log File의 경우에 이전 파일(생성이 완료된 파일)은 inode가 변하지 않았으니, LogStash는 신규 파일이 없는 것으로 파악한다. 단, Rotate가 되어 새 파일이 생성되었을 때는 해당 파일이 인지가 되었을 때부터 신규파일로써 읽기 시작하게 된다.

 

이를 표로 정리하면 다음과 같다.

 

path => "/var/log/syslog*"
시간 이벤트 행동
t 초 stat_interval 경과 (파일 갱신 확인) /var/log/syslog에서 sincedb에 기록된 offset 이후의 내용을 읽음.
t + 1 초 N/A /var/log/syslog에 신규 로그가 쌓임.
t + 2 초 Log Rotate /var/log/syslog/var/log/syslog.1로 rename됨 (inode가 변하지 않았으므로, LogStash 입장에서는 신규 파일이 아니다)
t + 3 초 Log Rotate /var/log/syslog 재생성 (신규 파일이 생성된 것)
t + 4 초 N/A /var/log/syslog에 신규 로그가 쌓이기 시작
t + 5 초 stat_interval 경과 (파일 갱신 확인) /var/log/syslog.1의 sincedb에 기록된 offset 이후부터 읽기 시작함. 즉, t + 1초부터 쌓인 로그는 유실없이 처리됨.
t + 6 초 discover_interval 경과 (신규 갱신 확인) /var/log/syslog가 새로 생긴 것을 인지한 뒤 start_position부터 읽기 시작함.

즉, t + 6초부터 신규파일인 /var/log/syslog이 새로운 offset과 함께 시작하게 된다.

(Log Rotate에는 move방식copy & truncate 방식이 있는데, LogStash는 둘 다 정상 작동된다)

 

만약 start_position이 end라면 새파일이 생성되고 그것을 인지하는 사이의 시간인, (t + 4) ~ (t + 6) 사이의 로그는 유실이 되는 것이다.

 

따라서, start_position은 beginning을 하는 것이 기본적으로 좋다.

 

기타 설정 및 내용도 몇가지 더 있으니 한번 알아보자.

 

sincedb_write_interval

LogStash가 처리 중인 offset을 얼마의 주기로 sincedb에 기록할지 지정하는 설정이다. (default 15sec)

해당 설정은 중복 유입과 관련되어 있으니 중요하다.

 

예를 들어 t초 sincedb에 offset 1000을 기록 후, (t+14)초에 offset 2000까지 읽은 뒤, Logstash가 죽었다고 하자. sincedb에는 1000이 적혀 있으므로 Logstash를 restart하는 경우 1001~2000까지는 중복 처리된다.

 

추가로, 파일이 복수개로 match될 때는 시간 순으로 출력되지 않는 점을 주의 하자. (단일 일때는 시간순)

 

[참조] http://jason-heo.github.io/elasticsearch/2016/02/28/logstash-offset.html

 

그럼 위 실습 내용을 다시 한번 보자.

input {
  file {
    path => "/home/minsuk/Documents/git-repo/BigData/ch06/populationbycountry19802010millions.csv"
    start_position => "beginning"  
    sincedb_path => "/dev/null"  
  }
}

start_position은 beginning으로 설정했고, sincedb_path는 /dev/null 을 설정함으로써, 해당 offset 위치를 저장하지 않도록 하여, 매번 새롭게 파일을 읽도록 하는 것을 말한다.

/dev/null
/dev/null은 항상 비어있는 폴더이며 해당 폴더로 전송하면 데이터는 버려진다.

 

Filter

 

Filter를 보도록 하자.

filter {
  csv {
      separator => ","
      columns => ["Country","1980","1981","1982","1983","1984","1985","1986","1987","1988","1989","1990","1991","1992","1993","1994","1995","1996","1997","1998","1999","2000","2001","2002","2003","2004","2005","2006","2007","2008","2009","2010"]
  }
  mutate {convert => ["1980", "float"]}
  mutate {convert => ["1981", "float"]}
  mutate {convert => ["1982", "float"]}
  mutate {convert => ["1983", "float"]}
  mutate {convert => ["1984", "float"]}
  mutate {convert => ["1985", "float"]}
  mutate {convert => ["1986", "float"]}
  mutate {convert => ["1987", "float"]}
  mutate {convert => ["1988", "float"]}
  mutate {convert => ["1989", "float"]}
  mutate {convert => ["1990", "float"]}
  mutate {convert => ["1991", "float"]}
  mutate {convert => ["1992", "float"]}
  mutate {convert => ["1993", "float"]}
  mutate {convert => ["1994", "float"]}
  mutate {convert => ["1995", "float"]}
  mutate {convert => ["1996", "float"]}
  mutate {convert => ["1997", "float"]}
  mutate {convert => ["1998", "float"]}
  mutate {convert => ["1999", "float"]}
  mutate {convert => ["2000", "float"]}
  mutate {convert => ["2001", "float"]}
  mutate {convert => ["2002", "float"]}
  mutate {convert => ["2003", "float"]}
  mutate {convert => ["2004", "float"]}
  mutate {convert => ["2005", "float"]}
  mutate {convert => ["2006", "float"]}
  mutate {convert => ["2007", "float"]}
  mutate {convert => ["2008", "float"]}
  mutate {convert => ["2009", "float"]}
  mutate {convert => ["2010", "float"]}
}

먼저, csv를 입력받았으므로, 무엇으로 seperator를 할 것인지, column은 어떻게 되어 있는지 명시한다.

또한, 1980년부터, 2010년까지 데이터를 float형으로 바꾸어준다.

 

output (출력)

output {  
    elasticsearch {
        hosts => "localhost"
        index => "population"
    }
    stdout {}
}

출력은 ES와 stdout을 설정한다.

hosts는 ES와 LogStash가 같은 서버에 있으므로 위와 같이 설정하였다.

 

Kibana

그럼 데이터를 logstash에 넣고, Kibana로 확인해보자.

아래 위치로 이동 후,

/usr/share/logstash/bin

다음 명령어를 친다.

./logstash -f <DIR>/logstash_pop.conf

LogStash pop

그럼 실행이 되면서, stdout으로 표현이 될 것이고, Kibana를 보도록 하자.

 

Management 설정은 앞 포스트와 동일하므로 생략한다.

Population

그럼 위 내용이 확인 가능하다.

Discover 확인도 가능하다.

Discover

Toggle을 통해, 1980년, 2010년, 나라이름 3개만 도출하면 다음과 같다.

Toggle

1980년도 SUM으로 나라별 인구수도 Visualization 가능하다.

 

Visualization

 

 


※ Inflearn 강의, Naver D2 블로그 등을 참고해 정리한 내용입니다.

 

1편 > Elastic Stack 아주 조금만 알아보자 - Elastic Stack 이란?

2편 > Elastic Stack 아주 조금만 알아보자 - ElasticSearch 기본 실습

3편 > Elastic Stack 아주 조금만 알아보자 - ElasticSearch Mapping/Search

4편 > Elastic Stack 아주 조금만 알아보자 - ElasticSearch 구조

5편 > Elastic Stack 아주 조금만 알아보자 - Aggregation

6편 > Elastic Stack 아주 조금만 알아보자 - Kibana

7편 > Elastic Stack 아주 조금만 알아보자 - LogStash

8편 >현재 Post