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 파일 생성
#!/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에서의 문제점
로그 서버 준비
분석 프로그램
적용 결과
Recent Posts
Archive Posts
Tags