[데이터처리] 로그 데이터 다루기 (1) - 수집 미들웨어 Fluentd 중심
분석 기반을 만든다는 것은 분석에 의한 결과를 지속적으로 만들어 내기 위한 구조를 만드는 것이다. 분석이라는 것은 현황을 확인하고, 비즈니스적인 의사결정을 하는 것이다. 의사결정을 위해서 분석을 하는 것이다. 데이터 분석 기반은 그 의사결정을 장기적으로 지원하기 위해 설계해야 한다.
[수집]: 어떤 데이터를 모을 것인가. 어떤 데이터를 보관할 것인가.
[변환]: 데이터를 어떻게 전처리해서 분석하기 쉬운 형태로 바꿀 것인가.
[보존]: 데이터를 어디에 저장할 것인가.
[분석]: 어떤 기반에 넣어서 데이터를 분석하고 활용할 것인가. 데이터를 넣는 것 뿐만 아니라 분석을 위한 좋은 환경을 만들기 위해서 어떻게 해야할까.
[표시]: 어떻게 데이터를 시각화하고, 결과를 전달할까.
[운영]: 데이터를 분석하기위한 기반을 장기적으로 운영하기 위해서는 어떻게 해야할까. 엔지니어가 아니라도 활용할 수 있는 환경을 만들기 위해서는 어떻게 해야할까.
제품의 조직구성에 따라서 각 요소에 관계하는 멤버는 바뀌게 된다. 관리자가 데이터를 보고 의사결정을 하는 경우가 많다면 분석이나 표시는 관리자가 이용자가 된다. 만약 데이터 전문가가 팀에 있다면 데이터 소스에 접근하기 쉬운 환경을 만들어서 그들이 분석이나 표시 작업을 수월하게 할 수 있다. 또 작은팀이라면 직접 데이터 분석 기반을 구축하고 데이터를 분석해서 지속적인 보고까지 담당할 수도 있다.
데이터의 양, 매트릭스의 다양함, 데이터의 보고서뿐만 아니라 예측/이상 탐지의 이용/활용 방법 등 데이터 분석 기반을 구축할 때는 다양한 사항을 고려할 필요가 있다.
마스터 데이터: 시간이 지나도 바뀌지 않는 데이터. (운영관리용 데이터)
시계열 데이터: 어떤 시간에 발생하는 사건을 기록하는 데이터. (로그 데이터)
설정 데이터: 상황에 따라 애플리케이션의 동작을 변경하기 위해 보존하는 데이터
(1) 마스터 데이터
마스터 데이터는 어떤 것에 대한 기본 정보다. 애플리케이션에서 마스터 데이터는 RDB에 저장할 경우가 많다. 어떤 경우든 데이터 분석을 하는 입장에서 생각할 것은 시계열 데이터를 어떻게 하면 마스터 데이터와 결합할 수 있을 것인가하는 점이다. 상품 기본정보인 마스터 데이터와 로그 데이터를 조합함으로써 좋은 리포트를 만들어 낼수 있다. 상품 카테고리를 상품의 마스터 데이터에 보존해두면 상품 카테고리별로 매출 경향을 내는 것도 가능하다.
(2) 시계열 데이터
시계열 데이터는 보관 방법과 질의 방법을 고려할 필요가 있다. 로그의 양이 적다면 SQL의 window 함수를 사용해서 "1주일사이의 변화를 비교하라"와 같은 작업을 간단하게 작성할 수 있다. 하지만, 로그가 많아지면 단일 데이터베이스에 넣어서 집계쿼리를 실행하는 것이 어렵게 된다. 로그가 많은 경우에는 분산 데이터베이스나 시계열 데이터 전용 데이터베이스에 넣는것이 좋다.
(3) 설정 데이터
설정 데이터는 마스터 데이터와는 구별되는 프로그램이나 사람의 조작으로 설정값을 변경할 수 있다. 설정의 이력을 보존하는 것으로 과거 시점의 설정 데이터와 시계열 데이터를 조합해서 과거의 어느 시점에서의 분석을 가능하게 한다. 데이터 분석 기반을 구축하여 최신의 값 뿐만 아니라, 설정의 이력 데이터도 남길 필요가 있다. 애플리케이션에서는 최근의 설정값만 있으면 충분하지만 "어떤 시점에서의 설정 정보"가 없다면 왜 이런 동작을 하는지 알 수 없기 때문이다. 설정에 따라서는 시계열 데이터에 그 설정값을 포함하는 방법도 생각할 수 있다. 애플리케이션에 따라 유연하게 설계하는 것이 좋다.
SoR: 기록(Record)을 위한 시스템. 입출력의 내용을 문제없이 바르게 처리하기를 기대하는 시스템. 예를 들어 신용카드에 의한 결제나 항공권의 예약시스템의 경우
SoE: 관계강화(Engagement)를 위한 시스템. 고객의 이용을 촉진하기 위한 시스템. 예를 들어 상품을 추천하는 시스템이나 고객에게 검색결과를 보여주는 시스템의 경우
SoR과 SoE는 개념적인 것으로 완전히 구별할 수 있을 것이 아니고, 두 개념이 혼합된 시스템도 있다. 시스템에 요구되는 것이 무엇인가를 생각하는 것이 분석 시스템을 구성할 때 중요하다.
SNS에서 고객의 지인이 있는 것을 내세우고 추천 친구를 보여주는 시스템은 SoE에 축을 두는 시스템이다. 추천 고객을 보여줌으로써 고객의 사이트 이용을 촉진하려는 목적이 있기 때문이다. 그로 인해 고객이 많은 상품을 클랙해서 사이트의 가치를 올릴 수 있다. 데이터 분석 기반과 애플리케이션 자체의 경계는 애매하다.
데이터 분석 기반은 애플리케이션의 출력 데이터를 입력받아서, 어떤 의사결정을 하거나 다시 애플리케이션 자체에서 이용하기 위한 데이터를 출력하는 시스템이다. 데이터 분석자체가 관계를 강화해서 비즈니스의 경쟁우위를 높이는 것이라면, 이는 애플리케이션 그 자체에 가까운 데이터 분석 기반이다.
만약 웹광고 서비스를 운영하고 있다면, 서버에는 광고 표시 로그가 있고, 광고를 클릭한 로그도 출력된다. 로그는 어떤 시점의 사실을 남기는 것이다. 다음과 같은 것을 로그라고 할 수 있다.
- 고객이 상품을 구입했을때의 로그 (어떤 상품을 언제 얼마에 구입했는 가의 이력)
- 실온/습도의 로그 (실내에 있는 온도센서에서 기록한 어떤 시간의 온도와 습도의 로그)
- 음향측정 데이터 (계측용 마이크로폰을 사용해서 수집한 어떤 시점의 음압 레벨)
로그 데이터를 취급할때는 데이터의 신선도에 따라서 2개의 분류가 있다. 분석함에 있어서 이런 데이터의 성질의 차이는 활용방법을 좌우하게 된다.
- hot data: 발생한 직후의 데이터. 발생하고 바로 이용되거나 고빈도로 조회되는 데이터를 말한다.
- cold data: 작성되고 난 뒤 이용될 때까지 일정 시간이 걸리는 데이터
hot data와 cold data
hot data는 준 실시간 분석을 가능케 한다.
- 지금 이 순간에 트래픽에 어떤 변화가 있는가
- 특정 캠페인을 실시한 타이밍에 어떤 상품의 주문이 증가했는가
- 특정 콘텐츠에 갑자기 request가 집중되고 있는데, 어떤 경로에서 들어오고 있는 것인가
이런 변화를 감지하고 싶은 경우에는 hot data를 사용할 필요가 있다. 한편 cold data는 일단 데이터를 스토리지에 저장한 뒤에 이용될 때까지 일정기간 조회되지 않는다.
hot data와 cold data를 구분하는 기준은 모호할 수가 있다. DB에 넣는 데이터가 모두 cold data인가 하면 항상 그렇지는 않다. 액세스가 빈번하게 일어나는 데이터를 hot data라고 할 수 있다. cold data라고 하면 장기적으로 백업을 위한 데이터라고 볼 수도 있다. hot data와 cold data의 사이에는 warm data라고 부르는 것도 있다.
hot data와 cold data는 각각 다루는 방법이 다르다. 로그데이터를 다룰 때는 바로 결과를 알고 싶은 경우와 장기적으로 이용하고 싶은 경우로 나뉜다.
로그라는 것은 어떤 시간에 일어난 사실에 대한 데이터이다. A 웹사이트에서는 고객이 페이지를 보거나, 상품을 구입하면 시시각각 고객의 행동일 일어난다. 생각할 수 있는 로그를 열거하면 다음과 같다.
- 고객의 페이지 열람
- 상품의 클릭
- 카트의 열람
- 고객의 상품구입
로그를 출력할 때는 나중에 어떤 분석을 할것인지 생각하게 된다. 로그를 남기기 시작할때는 "어떤 로그가 있는가"를 정리하고, 일단 전체 데이터를 나중에 사용할 수 있도록 cold data로 저장해 두는 편이 좋다.
- 일단은 전체 로그를 남긴다.
- 얻을 수 있는 매트릭스(지표)를 정리한다.
전체 로그를 Fluentd에서 다룰 수 있도록 해두면 hot data로 사용하기 쉽다. 한번만 Fluentd에 입력하면 그 다음은 필터를 사용해서 임의의 로그만을 추출하는 것이 가능하고, 가공한 뒤에 외부로 보내는 것도 쉽다.
Fluentd를 사용해서 로그 데이터의 형태를 결정함으로써 분석단계로 들어갈 수 있다. 분석단계에서는 고객의 여러가지 활동을 여러면에서 관찰하기 위한 지표를 사용한다. 이것을 매트릭스라고 한다. 여러면에서 활동을 관찰한다는 것은 무슨 의미일까?
A 판매사이트의 경우, 고객의 행동데이터 외에도 다음과 같은 메타데이터가 존재한다.
- 고객별 속성
- 연령, 주소, 성별, 구입횟수, 총 구입금액, 고객 등록일, 등록 경로
- 상품별 속성
- 상품이름, 상품종류, 색, 가격 판매 시작 시기, 재고 수
고객과 상품의 속성의 경우, 행동 로그와는 별개로 데이터베이스에 저장된다. 분석할때는 일단 이런 속성 데이터와 행동 로그를 조합해야 한다. 매트릭스를 만들면 다음과 같이 된다.
- 성별 또는 상품별의 액세스 경향
- 1시간 단위로 남성 고객이 상품1에 액세스한 횟수
- 1시간 단위로 여성 고객이 상품1에 액세스한 횟수
- 1시간 단위로 남성 고객이 상품2에 액세스한 횟수
- 1시간 단위로 여성 고객이 상품2에 액세스한 횟수
이것은 분석에 있어 중요한 지표이므로 기초 지표(fundamental matrix)라고 한다. 조금 더 범용 적인 조건을 적으면 아래와 같다.
(행동의 종류) x (고객의 속성) x (상품의 속성) x (시간단위) x (기본 통계량)
매트릭스는 이 조합의 수함큼 있게 된다. 여기에 들어맞는 여러가지 매트릭스를 만드는 것이 가능하다. 비즈니스 요건에 따라 나오는 매트릭스도 다르다.
(상품의 구매) x (2012년 3월에 등록한 고객) x (브라질산 커피콩) x (5분 단위) x (평균)
hot data와 cold data의 시점으로 봐도 로그 데이터의 구성이 다르다. 예를 들어 5초 간격으로 실시간으로 보고 싶은 경우는 로그 데이터에 고객과 상품의 속성을 넣는 방법이 있다. 그렇지 않은 경우에는 데이터베이스에 저장한 고객의 마스터 데이터를 JOIN해서 매트릭스를 계산할 수 있도록 할 필요가 있다. 다른 데이터소스를 참조하는 처리가 제때 이루어지지 못할 경우도 있으므로 QPS(Queries Per Second)를 고려해서 로그 데이터의 구성을 생각해야 한다.
로그 데이터를 가공하기 위한 프로그램이나 플러그인을 Fluentd용으로 설치한다. 실제 로그 데이터 대부분은 테스트용 데이터와 성질이 다르다. 단일 데이터에서 로그 패턴을 모방하려고 해도, 실제 로그와 다른 경우가 많다. 처음부터 모든 패턴을 망라해서 테스트하는 것은 어렵다.
개발할 때는 실제 환경의 로그 스트림을 일부분만 받아들일 수 있도록 노드를 만드는 것이 좋다. 그렇게 함으로써 실제 환경의 트래픽에 가까운 성질의 로그를 처리하는 프로그램 테스트를 할 수 있다. Fluentd라면 copy 플러그인과 sampling filter 플러그인을 사용한다.
로그를 해석하는 프로그램 대부분은 긴시간 동안 로그를 실시간에 가깝게 처리한다. 그러므로 이런 테스트용 서버에서 어느 정도의 시간을 들여서 테스트하는 것도 유용하다. 특히 Fluentd 플러그인의 경우 메모리 릭(Memory leak)이 발생하면 운영에 직접적인 영향을 끼치게 되므로 실제 환경에 적용하기 전에 테스트 환경에서 시험해보는 것이 중요하다.
샘플 애플리케이션은 Go로 만든 간단한 웹애플리케이션이라고 가정한다. 사용자 등록과 로그인 기능 그리고 글을 작성할 수 있다. 애플리케이션은 Nginx 경유로 액세스할 수 있다. 액세스 로그를 Fluentd에서 수집한다. Nginx의 액세스 로그는 Fluentd의 tail인 풋플러그인을 사용하서 로그 파일로부터 읽는다.
또한, 애플리케이션에서는 Elasticsearch를 이용해서 글의 검색기능을 구현하고, 그 검색의 로그도 Fluentd를 경우해서 Elasticsearch에 저장하게 된다. 검색 로그의 Fluentd 전송은 fluent/flutent-logger-golang을 사용한다. 글을 등록하는 타이밍에 Elasticsearch에서도 글을 인덱싱하기 때문에 즉시 검색 가능하다. 실제 운영하는 애플리케이션의 경우 Elasticsearch를 넣은 워커나 잡을 만들고 큐에 넣는 경우가 많지만, 데모용 환경에서 그럴 필요는 없다.
Fluentd 설정내용
열람 로그로써 .nginx 액세스 로그를 파일에서 읽어서 Elasticsearch에 보내기
검색 로그를 웹애플리케이션의 Go 클라이언트에서 받아서 Elasticsearch에 보내기
(1) in_tail: Nginx 로그 파일을 Fluentd에서 읽기
파일에서 fluentd에서 데이터를 읽기 위해서는 in_tail 플러그인을 이용한다. 아래는 fluent.conf에서 nginx 액세스 로그를 읽는 부분에 관한 <source> 디렉티브 설정이다.
<source>
@type tail
path /ver/log/nginx/access.log
pos_file /tmp/access.log.pos
format nginx
tag nginx.access
</source>
source 디렉티브에는 Fluentd에 어떤 데이터를 읽을 것인가를 기술한다. 여기에는 다음과 같이 설정한다.
/var/log/nginx/acess.log의 로그를 in_tail 플러그인으로 읽는다.
로그의 형식은 nginx이다.
이 로그를 식별하기 위한 태그는 nginx.access
Fluentd의 in_tail 플러그인은 표준으로 몇가지 로그형식을 지원하고 있다. nginx 로그 형식은 표준을 사용하고 있고 Fluentd가 로그에 포함된 필드와 값을 해석한다. 예를 들어 리모트 IP 주소, 호스트, HTTP 상태 코드와 같은 액세스 로그에 포함된 정보를 파싱해서 추출하는 수고를 덜 수있다.
표준으로 대응하지않는 로그 형식이더라도 정규 표현을 사용해서 파싱하는 방법을 설정하면 Fluentd는 각 필드를 해석할 수 있다.
tag는 Fluentd 내부에서 "어떤 로그인지"를 판별하기 위해서 이용한다. <match> 디렉티브에서는 이 tag를 사용해서 전송 설정을 하게 된다.
pos_file의 설정은 "어떤 로그 파일을 Fluentd가 어디까지 읽었는지를 기록하는 파일 위치의 패스를 결정한다. 예를 들어 Fluentd 데몬을 재기동하더라도 /var/log/nginx/access.log" 파일의 가장 앞부분부터 읽는 것이 아니라 pos 파일에 보존된 위치부터 읽을 수 있도록 해준다. in_tail 플러그인을 사용할 경우에는 pos_file의 설정을 하는 것이 권장된다.
(2) out_elasticsearch: Nginx 액세스 로그를 Elasticsearch로 보내기
다음으로 읽은 Nginx 액세스 로그를 Elasticsearch로 전송하기 위한 설정을 한다. Fluentd에서 전송하기 위한 설정은 <match> 디렉티브에서 설정한다. <match> 디렉티브는 처리 대상이 되는 로그의 tag를 지정하고 어떻게 그 로그를 처리할 것인가를 기술한다. 여기에서 처리의 대상이라는 것은 앞서 설정한 nginx.access 태그가 붙어있는 로그이다.
<match nginx.acess>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix nginx
type_name acesslogs
</match>
Fluentd에서 Elasticsearch로 전송하는 부분은 fluent-plugin-elasticsearch를 사용하고 있다. fluent-plugin-elasticsearch의 주요 설정은 host, logstash_format, logstash_prefix, type_name이다.
in_tail의 Nginx 액세스 로그의 읽기 설정과 out_elasticsearch 설정을 하면 Fluentd의 Nginx 액세스 로그의 전송 설정이 완료된다. 브라우저에서 http://localhost를 열고 샘플 애플리케이션에 액세스하면 이미 Fluentd를 경우해서 Elasticsearch에 Nginx 액세스 로그가 전송되어 있다.
in_forward를 이용해서 fluentd로 로그 전송
샘플 애플리케이션에는 검색 기능이 있다. 브라우저에서 http://localhost/search?q=test를 열어보면 test 문자열이 들어간 글을 검색할 수 있다고 가정한다.
검색 기능을 이용하면 애플리케이션에서 Fluentd에 검색 로그를 전송한다. 이것은 액세스 로그와는 별도로 검색 행위에 대해서 알기 쉽도록 집약하는 것을 목적으로 하는 로그이다. 나중에 인기 단어의 분석이나 고객별 흥미를 분석하기 위해서 검색 행위를 로그로 남겨두는 것도 좋다.
검색 로그는 파일에 출력하는 것이 아니라, 애플리케이션에서 직접 Fluentd에 HTTP 요청을 보낸다. 이 경우에는 Fluentd의 in_forward 플러그인을 이용한다. 다음은 in_forward의 설정이다.
<source>
@type forward
port 24224
</source>
호스트명은 elasticsearch, 포트는 9200인 Elasticsearch, 즉 Elasticsearch 컨테이너에 로그를 전송하는 설정이다. 이것으로 Nginx의 액세스 로그와 같은 방식으로 검색 로그도 out_elasticsearch 플러그인을 이용해서 Elasticsearch에 전송한다.
<match blog.search>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix search
type_name searchlogs
</match>
비즈니스 성공을 위해서는 live한 로그의 수집과 그 데이터의 분석이 중요한 요소가 된다. 관측한 수치를 가지고, 그 "추이", "경향", "변화"를 복합적, 종합적으로 평가하고, 현황분석과 다음 정책에 대한 지침을 만들 수 있도록 해야 진가를 발휘하는 것이다. 그러기 위해서는 앞으로의 서비스 개선으로 이어지는 요소로서 로그를 버리지 않고 가능한 한 장기적으로 저장해 둘 필요가 있다.
분석이 필요하게 되었을대 각 서버에서 로그를 모으거나, 로그 파일을 파싱처리하기 시작하면 활용하기까지 장애물이 많다. 그 분석 대상의 데이터가 구조화되어, 복잡한 프로그램을 작성하지 않고, SQL 등으로 바로 분석할 수 있을 상태가 이상적이다.
AARRR 모델
"서비스 개선으로 이어지는 요소로서의 로그"를 검토할때는 참고할 수 있는 사고방식으로 "AARRR"이 있다. AARRR 모델은 서비스 이용에서 유저 행동의 단계를 5단계의 요소로 나누어서 단계별로 기표를 만드로 개선 정책을 세우기 쉽도록하는 프레임워크이다. 분석결과를 보고 다음 행동을 선택하는, 데이터 주도 경영을 지향하는 기업에게 꼭 필요한 사고방식이다. AARRR 각각의 요소에 드는 비용과 성과 그리고 필요한 컨버전율, 컨버전 비용의 분석이라는 프레임워크는 유용하다.
(1) Acquisition: 유저획득
SEO(검색엔진 최적화, 검색엔진에서 검색결과의 상위에 나올 수 있도록 하는 작업)나 성과보수형 광고, 소셜이나 TV, 웹 등에서 광고를 목적으로 하는 정책에서 얼마나 첫방문이 늘었는지를 측정한 지표이다. 이것은 투입한 코스트를 방문 유저로 나누어서 비율로 측정한다.
(2) Activation: 활성화
처음으로 이용한 유저가 어느 정도 활성화하였는가를 측정하는 지표이다. 예를 들어 일정시간 이상을 이용하거나 주요 기능의 이용 실적 외에 마케팅 메일이나 블로그 방문, 회원등록 등, 간단한 방문 이상의 행동에 대해서 각각의 서비스 성질을 감안하여 독자적으로 활성화의 정의를 정하는게 좋다. 이것은 활성화한 유저(액티브 유저) 수를 방문 유저 수로 나누어서 비율을 측정한다.
(3) Retention: 지속
반복 이용을 독촉하는 메일이나 스마트폰 알림통지, 리타게팅 광고 등에서 어느 정도의 활성화 유저를 획득했는지를 계측하는 지표이다. 그 외에도 질문사이트의 베스트 답변상이나 SNS의 "좋아요" 등 지속적인 이용에 대해서 동기를 부여하기 위한 정책의 지표도 포함된다. 이것은 정책별로 비활성화 유저가 재방문해서 재활성화 유저가 되기가지의 전환율로 측정한다.
(4) Referral: 소개
기존 유저가 다른 누군가에게 서비스를 소개해서 얼마나 신규 유저를 얻을 수 있는지 측정하는 지표이다. 예를 들어 서비스 안에 있는 친구를 소개하는 기능을 사용해서 소개나 SNS에 확산하거나 블로그에 글을 쓰거나 하는 것이 해당된다. 이것은 소개 기능의 이용율과 그로부터 실제로 얻게되는 신규 유저의 전환율로 측정된다.
(5) Revenue: 수익화
유저가 서비스 안에서 어느 정도 수익에 공헌했는지 어느 정도 과금을 했는지를 측정하는 지표이다. 예를 들어 freeminum 모델로 서비스를 제공하고, 유저끼리의 대화에 사용하는 스탬프에 임의로 과금하는 경우가 있다. 이것은 금액에 상관없이 수익에 이른 비율과 ARPU(Average revenue per user: 유저당 평균 매출. 한 사람의 유저가 특정기간 동안 발생시키는 평균 매출액)라고 하는 유저당 평균 금액으로 측정한다.
AARRR 모델을 사용함으로써 서비스의 어떤 부분에 어떤 숙제가 있는지 명확해지고, 현재 사오항에서 개선점과 마케팅의 전략을 세우기 쉽게 된다.
이런 계측을 하는데 있어서 꼭 필요한 기술이 로그 수집이다. 하지만, 데이터양이 무제한으로 증가하는 로그를 수집하고 분석에 이용할수 있는 형태로 정리하는 구조를 처음부터 만들려고 하면 매우 힘든 작업이 될것이다. 현대적으로 효율적인 로그 수집을 실현하기 위해서 미들웨어를 활용할 것을 권장한다.
현대적인 로그 수집에서 당연히 있어야 하는 것은 다음이다.
- 빈번하게 변화하는 데이터 구조에도 유연하게 대응할 수 있다.
- 단시간에 집계할 수 있고, PDCA(Plan-Do-Check-Act, 계획/실행/평가/개선의 4단계를 반복하는 사이클) 사이ㅏ클을 빠르게 돌릴 수 있다.
- 액세스 증가에 따라 데이터 양이 급증하더라도 서버 수와 처리량을 늘려서 스케일링이 가능하다.
로그 수집 방법은 1일 1회 ~ 수회의 정기 배치 또는 rsync나 scp 커맨드로 다수의 애플리케이션 서버에서 로그 해석 서버로 비구조화된 형태의 다양한 포맷의 로그와 메시지 데이터를 전송해왔다. 이 방법으로는 위와 같은 요구사항을 만족할수가 없었고, 여러가지 문제점을 가지게 된다.
(1) 로그의 추출과 집계
앱별로 접속하는 사용자 유형을 분석하기 위해 남기는 로그에서 필요한 정보를 뽑아내기 위해서 awk 커맨드 등으로 정규표현이나 문자열 처리로 대응하느 경우가 있다. 정규표현 등으로 파싱하거나 추출이 필요한 비구조화 형식으로 로그를 출력하면 구조를 변경할 때 관계가 있는 모든 곳을 동시에 변경하기가 어렵기 때문에 의도치 않게 문제가 발생하기 쉽다. 게다가 데이터 포맷 중에는 CSV, TSV, XML보다도 사람의 눈으로 가시성과 후처리의 범용성에 뛰어난 JSON 형식이 일반적이다. 여기서 의미하는 한 행에 하나의 JSON 오브젝트를 저장하는 로그 형식을 JSON Lines(JSONL) 형식이라고 부른다.
콘솔작업시에 tail 커맨드에서 JSONL 형식의 로그를 감시하는 경우에는 jq 커맨드를 사용하면 편리하다. 또한 jq 커맨드에서 문자열 중에 이스케이프 문자열도 실제 개행으로 변화해서 출력하고 싶을때는 -r 옵션을 사용하면 된다.
Apache와 Nginx 등 플레이스홀더를 사용해서 로그 출력포맷을 설정하는 미들웨어는 LabeledTSV 형식이 적용되어 있다. 이것은 LTSV 형식이라고도 하며, 값의 이름인 라벨과 값을 하나의 콜론으로 구분하고, 각각의 요소들은 탭으로 구분하는 데이터 포맷이다. LTSV 형식은 JSON 형식에 비해서 자유도 떨어지지만, 단순한 형식이기 때문에 복잡한 정규식은 사용하지 않아도 된다.
이와 같이 범용성과 유연성이 높은 형식으로 로그를 남기는 것으로 로그를 활용할 준비가 된것이다.
(2) 로그 출력의 동기 처리
애플리케이션에서 직접 로그 파일을 남길 때는 배타처리와 동기처리가 필요하다. 배타처리라는 것은 파일에 동시에 쓰기를 하면 깨진 문자열이 남는 것을 방지하기 위해서 파일락을 FLOCK 등으로 락을 점유하여 중복쓰기를 방지하는 것을 말한다. 멀티스레드나 멀티프로세스 프로그램에서 하나의 파일에 로그를 출력하는 경우에는 쓰기 순서가 바뀌지 않도록 동기처리도 필요하다. 사용하는 언어나 방법에 따라서 파일에 쓰기를 할때 파일시스템의 락을 취득하기 위해, 락해제를 기다리는 시간이 자주 발생해서 그 애플리케이션 자체의 응답속도에 악영향을 끼치는 경우도 있다.
(3) 로그 로테이트 처리
일반적인 미들웨어에서 로그 로테이트를 하기 위해서 보통 HUP(Hang Up) 시그널을 사용한다. 이것은 로그 파일에 쓰기를 일단 중지하고, 새로운 파일에 쓰기를 시작하도록 하는 처리이다. 이러한 사소한 처리를 애플리케이션에서 하는 것은 로그를 남기는 것만으로 상당한 구현이 필요하게 된다. 간단하게 구현하려면 적절한 배타처리가 된다는 보증도 없고, 락기능을 담보하는 테스트코드도 작성하기 힘들다. 따라서 로그출력 부분은 애플리케이션보다는 미들웨어에 맡기는 편이 좋다.
(4) 비실시간 로그 처리
일괄작업으로 로그의 수집 처리를 할 경우에는 갱신을 추적할 필요없이 갱신이 끝난 로그만을 처리대상으로 하면 간단하다. 로그 로테이트는 보통 하루에 한번하게 되는데, 그게 끝난 다음 로그의 수집 처리를 시작하면 활용할 수 있을때까지 하루 이상의 시간이 걸리는 문제가 있다. 그것을 단축하기 위해서 빈번히 로그 로테이트 처리를 하면 미들웨어의 성능이 나빠질 수 있다. 로그 로테이트 처리를 하는 스크립트에 따라 애플리케이션의 재기동에 가까운 리로드나 HUP 시그널이 보내질 수도 있게 된다. 미들웨어에 따라서는 CPU 처리 비용이 높은 프로세스의 재생성과 명령코드 캐시와 바이트코드의 재생성에 의한 응답 성능저하 등, 응답이 늦어지는 악영향이 나올 수도 있다. 이런 장애를 막기 위해서 특히 초당 처리량이 많은 고부하 서비스에서는 액세스가 비교적 적은 아침 4시쯤에 Crontab으로 로그 로테이트 처리를 하는 편이 좋다. 로그 로테이트의 간격을 짧게 하는 요구는 결국 나중에는 실시간으로 로그 수집을 하는 미들웨어의 도입으로 이어지게 된다.
(5) 로그 전송 시의 네트워크 부하
어느 정도 쌓인 로그를 전송하는 타이밍에 네트워크의 부하가 발생하여 사이트의 응답이 느려지거나 하는 장애가 발생할 수 있다. 이것을 해결하기 위해서 다음과 같은 트래픽 흐름의 평준화 작업을 할 수 있긴 하지만, 유지관리면에서 좋은방법이라고 하기는 어렵다.
- 미세하게 sleep 처리를 넣어서 네트워크 점유시간을 짧게 유지한다.
- 네트워크 통신 속도에 제한하는 커맨드를 같이 사용한다.
- 실행 스케줄을 장비별로 미묘하게 다르게 한다.
인프라 쪽에서 대응하려면 네트워크 스위치에서 QoS(Quality of Service) 제어, 버스트(사용량이 허용치를 초과해서 문제가 생기는 상황)될 때의 통신량에 맞춰서 서버 네트워크의 인터페이스를 증설하거나 링크 속도를 10Gbps로 올리거나 하는 작업 등 여러 가지 해결 방법이 있다. 그래도 이것은 확실히 로그 수집 미들웨어를 사용해서 소프트웨어적으로 해결해야하는 문제다.
위에서 이야기한 경우와 같은 여러가지 문제 상황을 해결하기 위해 주로 구조화 로그 수집, 메시지 수집 미들웨어가 개발/공개되어 있다. 효율적으로 운용하기 위해서도 다음과 같은 미들웨어를 활용하는 것이 일반적인 시대가 되었다.
제품명 | 사용언어 | 개발시작 | 개발사 |
Scribe | C++ | 2008년 | |
Flume | Java | 2010년 | Apache Project |
Fluentd | C + Ruby | 2011년 | TreasureData Inc. |
Logstash | JRuby | 2011년 | elasticsearch Inc. |
로그 수집 미들웨어에는 공통적으로 다음과 같은 특징이 있다.
(1) 해석가능할 정도의 짧은 소요시간
지금까지 큰 사이즈의 로그 데이터를 배치처리로 해석서버로 전송하는 구조에서는 데이터양이 늘어나면 늘어날수록 전송에 걸리는 시간이 점점 늘어나 성능이 나빠지게 되었다. 예를 들어 하루치의 로그 데이터가 100GB인 경우, 200Mbps의 속도로 전송한다 하더라도 약 70분. 게다가 하루에 한번 로그 로테이션하고, 전날의 로그를 처리하는 설정이라면 반영될때까지 약 25시간의 지연이 발생하게 된다. 하지만, 로그 수집 제품의 특징인 비동기통신을 활용하면 시계열 데이터 처리에 어울러 거의 실시간으로 로그를 수집해서 활용할 수 있게 된다.
실시간으로 신선한 데이터를 다루는 것은 장점이 많다. 스트리밍 데이터 처리와 시계열 데이터 처리를 조합하면 다음과 같은 용도로 강력한 도구가 된다.
- 데이터 스트림 처리의 데이터 수집 대기 시간을 줄임으로써 신선하고, 정밀한 집계
- 유저의 신선하고 상세한 행동 로그를 가지고 높은 정밀도의 추천과 매칭
- 마케팅 정책의 압도적으로 빠른 효과 측정(TV 광고나 광고메일, 웹 광고 등)
- 시스템 리소스의 실시간 트러블 모니터링으로 문제의 빠른 해결
- 센서 데이터를 활용한 스트림 컴퓨팅(에너지 최적화, 재난방지 등)
- 차량의 위치 정보와 사람의 행동, 도로별 정체 상황을 분석한 교통제어
- 신용카드 등의 웹사이트에서의 부정이용의 검출
- 소셜데이터의 수집 등을 통한 주식 알고리즘 트레이딩
- 행동 로그를 가지고 관객의 위약 예측을 통해 위약 예방 마케팅의 실시
(2) 우수한 리소스 사용
로그 수집 미들웨어의 특징인 비동기 통신, 즉 데이터스트림에 의한 순차송신방식은 쇼트패킷이 아니라 롱패킷방식으로 우수한 네트워크 전송방식이다. 만약 하루의 로그데이터를 앞에서와 같은 방식으로 100GB라고 가정하면 전송은 평균 9.4Mbps의 대역사용으로 처리할 수 있다.
또한 1건의 레코드를 하나의 파일로 버퍼링하면 잦은 파일액세스가 발생하므로, 복수의 레코드를 묶어서 chunk라는 묶음으로 버퍼링해서 비동기로 사우이서버에 전송한다. 그러면, 로그전송량이 급증하더라도 랜덤액세스가 잘 일어나지 않고 비교적 큰 블럭액세스가 되기때문에 디스크I/O 처리를 점유함으로 인한 응답속도저하를 방지할 수 있다. 이런 장점에서 부하가 줄어들고, 시스템의 응답성능을 어느정도 확보할 수 있다.
(3) 비동기화 처리에 의한 빠른 처리
웹애플리케이션 뿐만 아니라, 직렬 동기 처리가 늘어나면 그만큼 응답에 걸리는 처리 시간이 늘어나게 된다. 만약 RDBMS와 로컬 파일에 Exclusive Lock을 걸고 트랜잭션 처리를 하면 확실성은 늘어나지만, 쓰기에 대한 성능이 점점 한계가 온다.
그러므로, 이런 로그 수집 미들웨어를 이용해서 TV나 메일링리스트, 시기적 요인 등에 의해 액세스 집중으로 초당 레코드 건수가 급증하더라도 큐잉(실시간으로 처리할 필요가 없는 작업을 백그라운드에서 비동기 처리하기위한 구조)으로 대응할 수 있고, 유저의 응답시간에 거의 영향을 주지 않고 로그 수집을 할 수 있게 된다. 다만, 여기에는 스피드와 정합성의 트레이드오프가 있어서, 로그의 누락없이 확실히 한번에 전송하는 트랜잭션을 엄밀하게 처리하지는 않는다는 전제하에 구현되어 있다.
(4) 통신의 예외 처리 / 재시도 처리
다른 서버와 통신할 때 네트워크 상에서 발생하는 문제를 피하기는 어렵다. 로그 수집 미들웨어를 이용하는 것으로 다음과 같은 직접 구현하기 까다로운 예외처리와 재시도처리를 맡길 수 있다.
- 통신중에 네트워크가 순단(간헐적으로 끊기는 현상)하는 경우
- TCP층에서 서버에 도달해서 소켓 버퍼에 들어와 ACK 응답이 오지만 애플리케이션층에서 문제가 발생해서 소실하는 경우
- TCP층에서는 문제가 없었지만, 애플리케이션에서 도착한 ACK 응답이 소실되었을때
- 폭주에 의해서 응답이 없고, 상대 서버에 바로 보낼 수 없는 경우.
로그 수집은 수단이지 목적이 아니다. 수집한 데이터를 활용해서 어떤 가치가 있는지 제품의 제작자에게 보이거나 이용자에게 어떤 가치를 제공할 수 있는지 개발자 뿐만 아니라 조직 전체에 도입 후의 비전을 공유하고, 매일 그 비전에 목적성을 두는 것이 중요하다.
출처: https://12bme.tistory.com/475?category=737765 [길은 가면, 뒤에 있다.]
'Big Data > 빅데이터' 카테고리의 다른 글
[엘라스틱서치] Elasticsearch in action 정리(4) - 유사도 검색 (0) | 2020.08.03 |
---|---|
[엘라스틱서치] Elasticsearch in action 정리(3) - 데이터 분석 (0) | 2020.08.03 |
[엘라스틱서치] Elasticsearch in action 정리(2) - 데이터 검색 (0) | 2020.08.03 |
[데이터처리] 로그데이터 다루기(2) - 수집 미들웨어 Fluentd란? (0) | 2020.08.03 |
[엘라스틱서치] Elasticsearch in action 정리(1) (0) | 2020.08.03 |
[대용량데이터] 대용량 처리 컨셉 오버뷰 (0) | 2020.08.03 |
[ELK] 엘라스틱서치 배우기 - 검색API (0) | 2020.08.03 |
[ELK] 엘라스틱서치 배우기 (0) | 2020.08.03 |