Linux 운영체제(:12)에서 C++과 RRD(:12), SQLite(:12)를 이용해서 구현해볼 생각이다.
RRD는 시간을 축으로 하는 통계정보의 저장을 위해서 사용될건데, joinc(:12)의 각 페이지의 방문통계를 저장하는 툴을 만들어볼 생각이다. 페이지가 대략 2800개 정도가 되니, 2800개의 RRD 파일을 생성하게 될 것이다.
C++은 최근 단시간의 통계정보를 만드는 프로그램을 만들 것이다. 예를들어 RRD의 최소 저장단위가 5분이라면, 각 페이지별로 5분동안의 카운트 정보를 만들어야 할 것이다. 이 프로그램은 5분동안의 카운트정보를 만든다음에, 각 페이지에 대응되는 RRD 파일에 값을 insert 할 것이다. C(:12) 대신 C++을 선택한 이유는 거의 순전히 STL(:12)을 사용하기 위함이다.
SQLite는 TOPN 기반의 RRD의 구현을 위해서 사용한다. 구현할 서비스는 최근 일,주,월,년 간 인기 방문 페이지 통계서비스다.
우선 만들기 쉬운 페이지별 통계 시스템을 만들고, 그 뒤에 TOPN 기반의 방문페이지 통계 시스템을 만들 것이다. TOPN기반의 방문페이지 통계 시스템은 따로 문서를 만들계획이다.
페이지별 통계 시스템
통계 자료는 apache(:12) 웹로그로 할 것이다. 그러므로 우선, 실시간으로 웹로그를 처리하는 프로그램을 만들어야 한다. 이 프로그램은 지정된 웹로그 파일을 주시하고 있다가 새로운 로그가 들어오면, 적당히 파싱한다음 페이지 이름에 대해서 counting을 할 것이다.
로그 서버 준비
apache로그 자체를 분석하는 방법도 있지만, 이런 저런 잡다한 정보들이 많아서 분석하는데 쓸데없는 비용이 많이든다는 문제점을 가진다. 그래서 별도의 로그 서버(:12)를 하나 만들 생각이다. 이 로그서버는 분석에 필요로하는 로그만을 가지게 된다. 이 로그 서버의 이름은 log server이라고 하겠다. 분석해야할 로그를 전송하는 서버는 joinc server다.
전송은 img(:12) 태그(:12)를 이용할 것이다. 로그분석에 필요한 여러가지 정보를 img 태그와 함께 GET(:12) log server로 넘긴다. 그러면 log server는 이 정보를 apache access log에 남긴다.
attachment:logsysgem.png
log server는 cpu와 memory 자원을 소비할 수 있으니, 원격지에 두는게 좋겠으나 여건이 허락하지 않는 관계로 joinc server와 같은 위치에 두기로 했다. 로그양이 많을 거라고 생각되지 않으니, 그닥 문제 없을 것 같기도 하고..
IMG 태그
이미지를 로딩하는 것이기 때문에, 만약 query string를 포함한 이미지이름이 같다면, 캐쉬에 있는 것을 읽어 버린다. 이미지이름을 바꿀수는 없으므로, query string이 항상달라질 수 있도록 해야 한다. 여기에서는 페이지를 읽는 시간을 query string의 값이 달라지도록 했다.
이제, 위키페이지가 저장되어 있는 디렉토리의 파일을 읽고, 그 파일이름을 인자로 해서 makerrd.sh를 실행시키는 간단한 perl(:12) 스크립트를 만들었다.
#!/usr/bin/perl -w
$dirname = $ARGV[0];
opendir(DIR, $dirname) || die "Error in opening dir $dirname";
while($filename = readdir(DIR))
{
if(!($filename =~ /^\./))
{
system("./makerrd.sh $filename");
}
}
close(DIR);
RRD Update에서의 문제점
RRD툴은 heatbeat 시간내에 데이터가 들어오지 않을 경우, 값을 nan으로 설정을 한다. 값이 nan으로 설정될 경우에는 측정된 값이 없는 것으로 판단하여, 통계데이터로 간주가 되지 않는다.
이것은 문제가 될 수 있다. 왜냐하면, 이 경우에 nan은 측정값이 없다라는 의미가 아닌, 0으로 측정되었다라는 의미로 받아들여야 하기 때문이다. 간단히 생각해서 다음과 같은 데이터가 있을 때
1231412400: 1.1000000000e+01
1231416000: 1.1000000000e+01
1231419600: nan
1231423200: nan
1231426800: nan
1231416000: 1.1000000000e+01
우리가 원하는 평균값은 (1.1+1.1+1.1)/6 이지만, 실제로는 (1.1+1.1+1.1)/3이 되어 버린다.
RRD툴은 이러한 방법을 자동적으로 해결해주지 않는 것 같다. 어쩔 수 없이 update하는 시점에, last update 시점을 찾아낸 다음에 update와 lastupdate 사이에 있는 모든 값을 0으로 만드는 방법을 사용하기로 했다. 즉 위의 예의 경우, 1231416000: 1.1000000000e+01 을 update 해야 하는 시점에 last update가 1231416000: 1.1000000000e+01 이니, 그 사이에 있는 값들을 전부 0으로 설정해준다. 최종적으로 아래와 같은 데이터가 쌓이게 될 것이다.
C++로 만들 것이다. log server가 남기는 access 로그를 지켜보다가. 새로운 log가 발생하면, 분석해서 counting을 한다. 그러다가 1시간 지나면, 이 값을 RRD 테이블에 쓴다. 분석프로그램은 tail 함수를 약간 수정해서 제작했다.
대략 돌아가는게 확인되어서, 현재 joninc 로그를 분석은 하고 있지만 코드가 지저분한 관계로 아직은 공개하지 않을 생각이다. 좀 더 다듬어서 공개해볼까 생각한다. 이미 바로 사용할 수 있는 tail 함수도 있으니, 코드를 만드는 건 그닥 어렵지 않을 것이라고 생각된다.
적용 결과
아래 데이터는 Average 이므로, 출력값을 조절해줘야 할 것이다. 통계가 있는 페이지는 아래의 그래프가 뜨도록 했다. 어느정도 통계자료를 만들면, 주/월/년 자료를 만들어볼 생각이다. 그리고 위의 코드도 좀더 다듬을 계획이다. 그래프는 google:::chart(:12)를 이용해서 생성했다.
Contents
구현 환경
페이지별 통계 시스템
로그 서버 준비
IMG 태그
RRD 파일 생성
RRD Update에서의 문제점
로그 서버 준비
분석 프로그램
적용 결과
Recent Posts
Archive Posts
Tags