flume command-line arguments

flume을 실행할 때 명령어 옵션을 줄 수 있는데, 이 옵션에 대한 내용을 문서에서 찾기가 쉽지 않아 별도로 메모해둡니다.
실제 서비스에서 flume을 적용할 때, 보안상 문제가 될 수 있으니 node의 HTTP 서버 설정(-s 옵션 적용)은 반드시 꺼두시기 바랍니다.

master
c – Load config from file
f – Use fresh (empty) flume configs
i – Server id (an integer from 0 up)

node
c – Load initial config from cmdline arg
n – Set node name
s – Do not start local flume status server on node
1 – Make flume node one shot (if closes or errors, exits)
m – Have flume hard exit if in likely GC thrash situation
h – Print help information
v – Print version information

그리고 node와는 달리 master는 HTTP 서버를 끌 수 없습니다.

flume을 master로 작동할 때, main() 함수에서는 다음과 같이 FlumeMaster 인스턴스를 생성하는데,


FlumeMaster config = new FlumeMaster();

FlumeMaster의 기본 생성자 정의는 다음과 같이 정의되어 있고, doHttp를 무조건 true로 호출하게 되어 있습니다.


public FlumeMaster() {
 this(FlumeConfiguration.get(), true);
 }

public FlumeMaster(FlumeConfiguration cfg, boolean doHttp) {
 this.cfg = cfg;
 ...
 this.doHttp = doHttp;

Advertisements

Flume을 사용하여 Apache Log를 HBase에 저장하기 – 테스트

Flume을 사용해서 아파치 로그를 HBase에 저장하는 시도를 해보았습니다. 별도 개발없이 공개된 소스만으로 얼마나 할 수 있는지를 살펴보는 게 주목적이었습니다.

로그 수집을 위한 오픈소스 솔루션으로는 Chukwa나 Scribe 같은 것이 있고 많은 곳에서 유용하게 사용되고 있지만, 개인적으로는 Flume의 아키텍처가 간단하고 좀 더 유연해서 맘에 들더군요. Flume과 Chukwa나 Scribe와의 가장 큰 차이점이라면 수집과 관련된 노드(Agent/Collector 등)를 자유롭게 구성할 수 있다는 것입니다. Chukwa는 시스템의 구성도 제한될 뿐더러 Chukwa를 운영하기 위한 Hadoop이 별도로 필요하고, Scribe는 일단 추가 구현을 해야하는 부분이 많고 기존 자바 환경과 같이 운용하기에는 여러모로 부담이 있었습니다. 이에 비해 Flume은 Source/Sink라는 간단한 모델을 차용하여 요구사항에 따라 제각기 역할의 노드로 이루어진 네트워크 구성을 할 수 있다는 장점이 있습니다.  Flume은 커뮤니티도 잘 형성되어 있을 뿐 아니라 Cloudera에서 계속 지원을 하고 있기도 하죠.

로그를 저장하는 방식으로는 파일로 저장하는 방법도 있지만, 저장보다는 분석이 주목적이기 때문에 RAW 형태의 파일보다는 조금 더 정형화된 구조를 선택하는 것이 좋다고 생각했습니다. 또한 실제 서비스의 아파치 로그를 저장하려면 꽤 많은 용량이 필요하기에 저장소 확장성도 어느 정도 확보가 되어야 하기에 몇 가지 noSQL 솔루션을 검토했습니다.
나름의 거버넌스 결과에 따르면 대용량/선형확장성 측면에서는 Cassandra와 HBase가 우선 후보 대상입니다. 데이터 Write 측면에서는 Cassandra가 더 적합할 수도 있지만, 우선 HBase를 시도한 이유는 다음과 같습니다.

  1. Hadoop 맵리듀스 사용
  2. 요구사항 중 Read Consistency가 필요한 상황이 있음

Flume – HBase 구성

구성은 아래와 같은 환경에서 진행하였습니다.

  • 10개의 Apache Web Server, 각 서버당 1개의 Agent (10개의 물리장비)
  • Collector 노드 1개/Master 노드 1개(1개의 물리장비)

Agent 세팅

각 Apache Web Server에 설치된 Agent 역할의 Flume 세팅은 다음과 같이 했습니다. Agent 노드는 Apache의 AccessLog를 읽어서 collector로 전송해주는 역할을 합니다.

agentX: tailDir("/logs/apachelog/access_.*", true) | agentSink("collector"), 35863)

/logs/apachelog 디렉토리에 있는 파일 중 access_로 시작하는 파일을 tail 하면서, 한 줄 단위의 변경사항을 collectormaster 노드로 전송하라는 의미입니다. 만약 tailDir()의 두 번째 인자를 false로 주면 Flume이 실행될 때마다 파일을 처음부터 읽어들이게 됩니다. Flume을 셧다운시키거나 재시작하는 경우도 종종 있으므로 로그가 처음부터 다시 전송되는 것을 방지하기 위해 두 번째 인자를 true로 하였습니다.

Collector 세팅

Collector는 Agent로부터 전송된 로그를 수신하고, HBase에 저장하는 역할을 합니다.

hbase sink & attr2hbase sink

현재 Flume의 배포판(CDH3u1 기준)에는 hbase 와 attr2hbase 두 가지 sink가 지원됩니다.
기본으로 활성화되어 있지는 않기에 이 두 sink를 사용하려면 flume-site.xml에서 추가 설정이 필요합니다.

...
<property>
<name>flume.plugin.classes</name>
<value>com.cloudera.flume.hbase.HBaseSink,com.cloudera.flume.hbase.Attr2HBaseEventSink</value>
</property>
...

hbase와 attr2hbase는 모두 hbase의 configuration을 사용합니다. Flume의 classpath에 hbase config 파일의 위치를 지정해주는 것이 좋습니다. 두 sink의 차이에 대해 자세한 내용은 이곳을 참고하시기 바랍니다.
저는 split, regex 등의 decorator를 통해 얻은 결과를 다루는게 attr2hbase가 좀 더 편했기에 attr2hbase를 사용했습니다만, 사용성에 따라 어느 것을 선택해도 크게 문제는 없으리라 봅니다. 그리고 필요하다면 별도의 hbase sink를 구현하는 것도 나쁘지 않을 듯 합니다. hbase/attr2hbase 소스를 살펴보시면 아시겠지만 심플하게 구현이 되어 있습니다.

Apache Log Format

아파치 로그는 httpd.conf의 설정에 따라 조금씩 다르겠습니다만, 제가 테스트한 환경은 다음과 같은 형식의 로그를 사용합니다.

12.34.56.789 - - [03/Sep/2011:23:59:49 +0900] "GET /index.html HTTP/1.1" 200 412 8387 "http://yourdomain.com/main.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0;)"

빠른 프로토타이핑을 위해 우선 정규식으로 해당 로그를 처리하기로 하고, 로그의 주요 항목(IP, URL, DateTime, ContentSize, Browser 등)을 컬럼으로 추출해냅니다. 또한 로그원본 확보를 위해 원본은 별도의 컬럼(logbody)으로 추출합니다.

Collector 형식

Agent로부터 전송된 아파치 로그 문자열을 split, regexAll 등의 decorator를 사용하여 가공을 합니다.
attr2hbase는 특정 prefix를 가진 attribute를 hbase에 저장하도록 되어 있습니다.
만약 prefix값이 “2hb_”라면, “2hb_name” 이라는 attribute의 값은 hbase의 “name”이라는 컬럼에 저장이 됩니다. 그리고 row key는 이름이  “2hb_”인 attribute의 값이 됩니다.

  • split(“^$”, 0, “2hb_logbody”)
    로그원본 문자열 전체를 2hb_logbody라는 attribute에 저장하기 위해 약간의 꼼수를 사용한 것입니다.
  • regexAll(“^([\\d.]+) (\\S+) …. “, name1, name2, name3, … )
    아파치 로그의 각 항목을 정규식을 사용해서 추출합니다.
  • format(“%{nanos}:”) split(“:”, 0, “2hb_”)
    nano초 값을 row key로 사용하려고 하는데, 이것도 약간의 꼼수가 사용되었습니다.
    value() decorator가 EL을 지원하지 않기 때문에 value(“2hb_”, “%{nanos}”)와 같은 방식을 사용할 수 없습니다.
    따라서 우선 전체 문자열을 “%{nano}:” 바꾼 후 “:”으로 split 한 값을 얻어내어 “2hb_”에 저장합니다.
  • attr2hbase( “accesslog”, “prop”, “”, “2hb_”, “1000”, “false” );
    accesslog 테이블의 prop 컬럼패밀리에 attribute 들을 저장합니다. prefix는 “2hb_” 입니다.

Collector 노드의 설정 형식은 다음과 같습니다.

collector: collectorSource(35863) | split("^$",0,"2hb_logbody")
 regexAll("^([\\d.]+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(.+?)\" (\\d{3}) (\\d+) (\\d+) \"([^\"]+)\" \"([^\"]+)\"", "2hb_ip", "2hb_a1", "2hb_b1", "2hb_date", "2hb_url", "2hb_status", "2hb_contentsize", "2hb_c1", "2hb_browser")
 format("%{nanos}:")
 split(":", 0, "2hb_")
 attr2hbase( "accesslog", "prop", "", "2hb_", "1000", "false" );

Flume master에서 각 agent와 collector에 설정 명령을 내리고 나서 설정에 이상이 없다면 아파치 로그가 HBase에 쌓이게 됩니다.

더 고민해봐야 할 것들

위와 같이 세팅하고 며칠동안 아파치 로그를 수집해보니 어느 정도는 예상했던 문제들이 더욱 뚜렷하게 드러나더군요.

  1. 높은 CPU 사용률
    아파치 서버 한 대당 tailDir()이 약 800개의 파일을 모니터링하고 있는데, 이는 CPU에 상당히 부담을 주고 있습니다. 서버 한 대당  평균 메모리 사용률이 꾸준히 30~60% 사이를 유지하는 편입니다. 사실 이 정도면 실제 서비스에서는 심각한 수준입니다. 또한 서비스의 트리팩이 증가하여 서버의 부하가 높아지면 로그 Agent는 시스템의 리소스에 따라 로그 처리 작업을 줄이거나 중지할 필요가 있습니다. 로그량이 증가한다고 해서 같이 처리량을 올리면 이는 곧 시스템 다운으로 이어질 가능성이 있죠.
    따라서 실제 서비스에서는 모니터링 대상 파일 개수를 줄이고 지연처리/비동기 처리 방식을 적용할 필요가 있습니다.
  2. 설정의 복잡함
    Flume에서 다양한 종류의 decorator와 sink를 제공하고는 있지만 하나씩 뜯어보면 아직 개선할 점이 많습니다. 또한 이 테스트에서 보이듯이 간단한 정규식 처리를 하는 데에도 collector 노드의 설정이 꽤 복잡해집니다. 다중 tier로 Flume 노드들이 배치되면 데이터 흐름을 따라가는 것도 쉽지는 않을 것이기에 대응이 필요하다는 생각은 듭니다.
    다행히 Flume은 decorator/sink 확장을 제공하므로 운용 환경에 맞게 임의의 decorator/sink를 구현하는 것도 좋으리라 봅니다. 아래와 같이 아파치로그에 특화된 source를 별도로 구현하는 것도 괜찮겠네요.

    flumenode: sourceApache("/log/access_.*", AccessLogFormat) | console("avrojson")
    

참고자료

Using Flume to Collect Apache 2 Web Server Logs
http://www.cloudera.com/blog/2010/09/using-flume-to-collect-apache-2-web-server-logs/

Flume User Guide
http://archive.cloudera.com/cdh/3/flume/UserGuide/index.html

Flume and HBase Integration
http://blog.sematext.com/2011/07/28/flume-and-hbase-integration/