시계열 데이터를 저장하는 DB를 데이터 소스로 연계하여 고급스러운 대시보드를 쉽게 만들 수 있다.
데이터 소스로 Graphite, InfluxDB, OpenTSDB 와 연계할 수 있으며 멀티로도 연계 가능하다.
말이 필요 없이 최고!
시계열 데이터 저장에 특화된 DB와 그래프 관련 API를 제공하는 서버로 구성되어 있다.
데이터 수집은 사용자가 비교적 쉽게 만들 수 있고 다양한 연계 툴을 활용할 수도 있다.
분산 아키텍처로 유연하게 확장 가능하여 수집 데이터가 많은 대규모 인프라에도 활용 가능하다.
자체 대시보드 기능도 제공하지만 모니터링 툴로 활용하기엔 아쉬운 점이 있다.
Python 으로 개발되었고 의존관계 모듈이 많아 설치가 까다롭다.
Metric 수집 및 전송 (자체 제작 또는 연계 툴 활용)
Render Graph (다양한 연계 툴)
Carbon
Cache
Whisper
(DB)
Graphite
Web
(API)
3개의 Component 로 구성되어 있다.
1. Carbon : 데이터를 수신하는 데몬으로 백그라운드로 항상 실행 상태 유지
2. Whisper : 시계열로 정렬된 데이터 저장에 특화된 경량 DB (RRD와 유사)
3. Graphite Web : 그래프를 그리는데 필요한 API 제공 및 자체 대시보드 기능을 위한 Django 웹 서버
Metric 수집 및 전송 (자체 제작 또는 연계 툴 활용)
Render Graph (다양한 연계 툴)
Carbon
Cache
Whisper
(DB)
Graphite
Web
(API)
Metric 수집 및 전송
(자체 제작)
Render Graph
Architecture
Carbon
Cache
(수신기)
Whisper
(DB)
Graphite
Web
(API)
graphite_gather_dstat.sh
graphite_gather_mariadb.sh
graphite_gather_oracle.sh
통합관제
(Alert)
준비중..
Graphite Installation – 1. dependency
# python 이 없을 시 설치
$ sudo yum install python
# dependency 확인
$ wget https://launchpad.net/graphite/0.9/0.9.10/+download/check-dependencies.py
$ python check-dependencies.py
[FATAL] Unable to import the 'whisper' module, please download this package from the Graphite project page and install it.
[FATAL] Unable to import the 'django' module, do you have Django installed for python 2.6.6?
[FATAL] Unable to import the 'tagging' module, do you have django-tagging installed for python 2.6.6?
[WARNING] Unable to import the 'mod_python' module, do you have mod_python installed for python 2.6.6?
mod_python is one of the most common ways to run graphite-web under apache.
Without mod_python you will still be able to use the built in development server; which is not
recommended for production use.
wsgi or other approaches for production scale use are also possible without mod_python
[WARNING]
Unable to import the 'txamqp' module, this is required if you want to use AMQP.
Note that txamqp requires python 2.5 or greater.
3 necessary dependencies not met. Graphite will not function until these dependencies are fulfilled.
2 optional dependencies not met. Please consider the warning messages before proceeding.
# dependency 모듈 설치
$ yum install Django
$ yum install Django-tagging
$ yum install mod_python
$ yum install python-memcached
$ yum install python-ldap
$ yum install Twisted
$ easy_install txamqp
$ easy_install whisper
# 아래와 같이 메시지가 나오면 OK
$ python check-dependencies.py
All necessary dependencies are met.
All optional dependencies are met.
설치 환경은 Oracle Enterprise Linux 6 입니다.
Graphite Installation – 2. Download and Installation
# 다운로드
$ cd /root/programs
$ git clone https://github.com/graphite-project/graphite-web.git
$ git clone https://github.com/graphite-project/carbon.git
$ git clone https://github.com/graphite-project/whisper.git
$ ls -al
합계 2152
drwxr-xr-x 5 root root 4096 2015-08-20 15:50 .
dr-xr-x---. 13 root root 4096 2015-08-20 14:33 ..
drwxr-xr-x 10 root root 4096 2015-08-20 15:53 carbon
-rw-r--r-- 1 root root 42201 2012-06-01 05:38 carbon-0.9.10.tar.gz
-rw-r--r-- 1 root root 5196 2012-05-03 23:14 check-dependencies.py
drwxr-xr-x 12 root root 4096 2015-08-20 15:54 graphite-web
-rw-r--r-- 1 root root 2117421 2012-06-01 05:38 graphite-web-0.9.10.tar.gz
drwxr-xr-x 5 root root 4096 2015-08-20 15:50 whisper
-rw-r--r-- 1 root root 10661 2012-06-01 05:37 whisper-0.9.10.tar.gz
# Default 경로 (/opt/graphite) 설치
$ cd carbon
$ python setup.py install
$ cd ..
$
$ cd graphite-web
$ python setup.py install
$ cd ..
$
$ cd whisper
$ python setup.py install
$ cd ..
# Custom 경로 설치
$ cd carbon
$ python setup.py install --prefix=/srv/graphite --install-lib=/srv/graphite/lib
$ cd ..
$
$ cd graphite-web
$ python setup.py install --prefix=/srv/graphite --install-lib=/srv/graphite/webapp
$ cd ..
정신 건강을 위해 DEFAULT 경로에
설치하는 것을 권고합니다.
Graphite Installation – 3. Graphite-web's local_settings.py
# 설치경로에 아래와 같이 파일들이 생성된다.
$ ls –l /opt/graphite
합계 28
drwxrwxrwx 2 root root 4096 2015-04-03 20:27 bin
drwxrwxrwx 2 root root 4096 2015-04-24 15:30 conf
drwxrwxrwx 2 root root 4096 2015-05-12 22:57 examples
drwxrwxrwx 4 root root 4096 2015-04-03 20:27 lib
drwxrwxrwx 7 root root 4096 2015-05-06 21:05 storage
drwxrwxrwx 4 root root 4096 2015-04-03 20:28 webapp
$ cd /opt/graphite/webapp/graphite
$ cp local_settings.py.example local_settings.py
$ vi local_settings.py
# local_settings.py 파일을 열어서 DEBUG=True 를 주석 해제 한다.
# 기본경로로 설치 하지 않았을 경우 아래 설정의 주석 해제 후 설치한 경로를 지정한다.
GRAPHITE_ROOT = '/opt/graphite'
STATIC_ROOT='/opt/graphite/static'
CONF_DIR = '/opt/graphite/conf'
STORAGE_DIR = '/opt/graphite/storage'
STATIC_ROOT = '/opt/graphite/static'
Graphite Installation – 4. Configuring The Webapp
# 다운로드한 설치파일에서 manage.py 를 설치경로에 복사
$ cp /root/programs/graphite-web/webapp/manage.py /opt/graphite/webapp/graphite/
$ cd /opt/graphite/webapp/graphite
# manage.py 파일을 열어서 붉은색으로 표시한 부분을 추가한다.
$ vi manage.py
$ python manage.py collectstatic
/opt/graphite/webapp/graphite/settings.py:233: UserWarning: SECRET_KEY is set to an unsafe default. This should be set in
local_settings.py for better security
warn('SECRET_KEY is set to an unsafe default. This should be set in local_settings.py for better security')
You have requested to collect static files at the destination
location as specified in your settings.
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: yes
# /opt/graphite 밑에 static 경로가 생긴 것을 확인할 수 있다.
#!/usr/bin/env python
import os
import sys
sys.path.append('/opt/graphite/webapp')
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "graphite.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
Graphite Installation – 4. Configuring The Webapp
# 아파치 홈 경로의 httpd.conf 에 가상호스트 설정을 한다. (기본경로는 /etc/httpd/conf/httpd.conf)
# /opt/graphite/examples/example-graphite-vhost.conf 의 내용을 copy 하여 httpd.conf 에 추가한다.
# 기본경로 설치가 아닌 경우 /opt/graphite 부분을 지정한 경로로 모두 바꿔 주어야 한다.
# 아파치 설정에 오류가 없는지 확인
$ /etc/init.d/httpd configtest
httpd: Syntax error on line 192 of /etc/httpd/conf/httpd.conf: Cannot load /etc/httpd/modules/mod_wsgi.so into server:
/etc/httpd/modules/mod_wsgi.so: cannot open shared object file: No such file or directory
# mod_wsgi.so 모듈이 없어서 에러나면 설치하고 다시 확인한다.
$ yum install mod_wsgi
$ /etc/init.d/httpd configtest
Syntax OK
# 아파치 재시작 시 에러가 날 경우 tail -f /opt/graphite/storage/log/webapp/error.log 보면서 트러블슈팅 한다.
$ /etc/init.d/httpd reload
# 파일 접근 오류가 나면 /home/graphite 경로가 아파치 데몬 실행 유저가 접근할 수 있는 권한이 있는지 확인한다.
$ chmod -R 777 /opt/graphite/
<IfModule !wsgi_module.c>
LoadModule wsgi_module modules/mod_wsgi.so
</IfModule>
WSGISocketPrefix run/wsgi
<VirtualHost *:80>
ServerName graphite.melon.com
DocumentRoot "/opt/graphite/webapp"
ErrorLog /opt/graphite/storage/log/webapp/error.log
CustomLog /opt/graphite/storage/log/webapp/access.log common
WSGIDaemonProcess graphite processes=5 threads=5 display-name='%{GROUP}' inactivity-timeout=120
WSGIProcessGroup graphite
WSGIApplicationGroup %{GLOBAL}
WSGIImportScript /opt/graphite/conf/graphite.wsgi process-group=graphite application-group=%{GLOBAL}
WSGIScriptAlias / /opt/graphite/conf/graphite.wsgi
Alias /static/ /opt/graphite/static/
Alias /media/ "@DJANGO_ROOT@/contrib/admin/media/"
</VirtualHost>
Graphite Installation – 4. Configuring The Webapp
# 기본경로 설치가 아닌 경우 붉은색 부분을 수정한다.
$ cd /opt/graphite/conf
$ cp graphite.wsgi.example graphite.wsgi
$ vi graphite.wsgi
import sys
sys.path.append('/opt/graphite/webapp')
from graphite.wsgi import application
# Django database 구성
$ cd /opt/graphite/webapp/graphite
$ python manage.py syncdb
Creating tables ...
Creating table account_profile
Creating table account_variable
Creating table account_view
Creating table account_window
Creating table account_mygraph
Creating table dashboard_dashboard_owners
Creating table dashboard_dashboard
Creating table dashboard_template_owners
Creating table dashboard_template
Creating table events_event
Creating table url_shortener_link
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table django_session
Creating table django_admin_log
Creating table django_content_type
Creating table tagging_tag
Creating table tagging_taggeditem
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'root'):
E-mail address: smyoo@iloen.com
Password:
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)
$ chown nobody:nobody /opt/graphite/storage/graphite.db
# 접속할 PC의 hosts 설정을 하고 접속한다.
# 파일에 다음 추가하고 접속한다.
192.168.238.11 graphite.melon.com
# <예외사항>
# Exception Value: No module named pyparsing
# 누락된 모듈을 설치하면 된다.
$ yum install pyparsing
# Exception Value: attempt to write a readonly database
# Django가 사용하는 sqlite db에 아파치 실행 유저가 쓰기 권한이 없어서 발생하는 에러
이므로 쓰기 권한을 부여한다.
$ chmod 777 /home/graphite/storage/graphite.db
Configuring Carbon – carbon.conf
$ cd /home/graphite/conf
$ cp carbon.conf.example carbon.conf
# <carbon.conf>
#[cache] 섹션이 carbon-cache 관련 설정인데 메트릭을 수신하는 port 가 2003 인 것을 확인한다.
# LOG_LISTENER_CONN_SUCCESS 는 False 로 설정하여 불필요한 로그로 디스크가 낭비되는 것을 방지한다.
# 설정하지 않으면 /opt/graphite/storage/log/carbon-cache/carbon-cache-a/listener.log 에 아래와 같은 로그가 메트릭 수
신할 때마다 남는다.
LINE_RECEIVER_PORT = 2003
UDP_RECEIVER_PORT = 2003
PICKLE_RECEIVER_PORT = 2004
CACHE_QUERY_PORT = 7002
LOG_LISTENER_CONN_SUCCESS = False
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20612 closed cleanly
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20613 established
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20613 closed cleanly
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20614 established
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20614 closed cleanly
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20615 established
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20615 closed cleanly
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20616 established
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20616 closed cleanly
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20619 established
15/04/2015 14:56:01 :: MetricLineReceiver connection with 192.168.238.100:20619 closed cleanly
LOG_LISTENER_CONN_SUCCESS = False
Configuring Carbon - storage-schemas.conf
$ cd /home/graphite/conf
$ cp storage-schemas.conf.example storage-schemas.conf
# <storage-schemas.conf>
# storage-schemas.conf 는 데이터 보관 주기 설정으로 신경 쓸 필요가 있다.
# 1. 섹션은 위에서 부터 아래로 적용된다.
# 2. 변경된 설정은 이미 생성된 whisper data file (.wsp) 에는 적용되지 않는다. 적용하려면 whisper-resize.py 를 이용한다.
# carbon-cache(메트릭 수신기) 데몬 실행.
# carbon.conf 에 설정된 대로 2003, 2004 포트로 데이터를 수신한다.
$ cd /opt/graphite/bin
$ ./carbon-cache.py start
Starting carbon-cache (instance a)
$ ps -ef | grep carbon
root 13222 1 0 11:50 ? 00:00:00 /usr/bin/python ./carbon-cache.py start
root 14068 8773 0 11:50 pts/2 00:00:00 grep carbon
[carbon]
pattern = ^carbon. 메트릭 계층 구조가 carbon. 으로 시작하는 것들 (메트릭 계층 구조 설계가 중요하다.)
retentions = 60:90d 메트릭 포인트가 60초 간격으로 수집되는 것을 90일 동안 저장
[default]
pattern = .*
retentions = 5s:30d,10s:1y,60s:5y
Getting Your Data Into Graphite
Graphite message format – Plaintext protocol 방식 (2003 Port)
<metric path> <metric value> <metric timestamp>
nc (netcat) 명령어를 이용하여 전송
echo “depth1.depth2.depth3.metric_name 55 `date +%s`” | nc GRAPHITE_SERVER 2003
Graphite message format – Pickle protocol 방식 (2004 Port)
[(path, (timestamp, value)), ...] 와 같이 여러 개의 값을 한번에 전송 가능
Python 개발을 할 줄 안다면 유용
MariaDB(MySQL) 모니터링 지표 수집 (5.5기준)
$ cd /root/graphite_gather/
$ cat .env.ini
export SLEEP_TIME=57 ## (수집주기는 1분)
export MYSQL_HOME=/home/mysql/MariaDB
# mystat.txt 파일에 현재 상태 값을 나타내는 status 항목 저장
$ cat mystat.txt
Threads_cached
Threads_connected
Threads_running
# mystat_com.txt 는 누적 값을 나타내는 항목 저장
$ cat mystat_com.txt
Com_delete
Com_insert
Com_select
Com_update
$ vi graphite_gather_mariadb.sh
# 백그라운드로 수행
$ nohup graphite_gather_mariadb.sh &
$ ps -ef | grep graphite_
root 22329 21891 0 13:53 pts/3 00:00:00 grep graphite_
root 45282 1 0 May14 ? 08:41:32 /bin/sh ./graphite_gather_dstat.sh
root 62776 1 1 May06 ? 1-18:05:38 /bin/sh ./graphite_gather_mariadb.sh
#!/bin/sh
. /root/graphite_gather/.env.ini
hostname=`hostname`
while(true)
do
mystat=
mystat_com=
while read line; do mystat=$mystat'|'$line; done < /root/graphite_gather/mystat.txt
$MYSQL_HOME/bin/mysqladmin -uroot -p`cat /home/mysql/.mysqlpw.ini` -S /tmp/mysql.sock extended-status | grep -E `echo ${mystat:1}` | tail -`cat /root/graphite_gather/mystat.txt | wc -l` | awk '{print $2 " "
$4}' > /root/graphite_gather/mystat_result
while read line; do mystat_com=$mystat_com'|'$line; done < /root/graphite_gather/mystat_com.txt
$MYSQL_HOME/bin/mysqladmin -uroot -p`cat /home/mysql/.mysqlpw.ini` -S /tmp/mysql.sock extended-status -r -i 1 -c 2 | grep -E `echo ${mystat_com:1}` | tail -`cat /root/graphite_gather/mystat_com.txt | wc -l` |
awk '{print $2 " " $4}' >> /root/graphite_gather/mystat_result
while read line; do echo "real.${hostname:0:${#hostname}-1}.${hostname:${#hostname}-1:1}.dbstat.$line `date +%s`" | nc graphite 2003; done < /root/graphite_gather/mystat_result
#while read line; do echo "real.${hostname:0:${#hostname}-1}.${hostname:${#hostname}-1:1}.dbstat.$line `date +%s`"; done < /root/graphite_gather/mystat_result
sleep $SLEEP_TIME
done
Oracle 모니터링 지표 수집 (11.2.0.4 기준)
# 사전작업 (임시 저장용 테이블 생성)
SQL> create table mondba.sysstat as select * from v$sysstat where 1=0;
SQL> alter table mondba.sysstat add no number not null;
SQL> insert into mondba.sysstat select a.*, 1 from v$sysstat a;
SQL> commit;
$ vi graphite_gather_oracle.sql
set heading off
set feedback off
set time off timing off
set pages 0
col value for 9999999999999999999999999999
insert into mondba.sysstat1 select a.*, (select max(no)+1 from mondba.sysstat1) from v$sysstat a;
select replace(replace(replace(name,' ','_'),'(',''),')','')||' '||to_char(value)
from (
select pool as name, sum(bytes) as value from v$sgastat where pool is not null group by pool
union all
select name, bytes as value from v$sgastat where pool is null
union all
select lower(status)||'_session' as name, count(*) as value from v$session group by status
union all
select 'data_size' as name, sum(bytes) as value from dba_data_files
union all
select 'free_size' as name, sum(bytes) as value from dba_free_space
union all
select b.name, sum(a.value) as value from v$sesstat a, v$statname b where a.statistic#=b.statistic# and b.name in ('session pga memory', 'opened cursors current', 'session uga memory') group by b.name
union all
select now.name, now.value-bef.value as value
from
(select name, value from mondba.sysstat1 where no=(select max(no) from mondba.sysstat1)) now,
(select name, value from mondba.sysstat1 where no=(select max(no)-1 from mondba.sysstat1)) bef
where now.name=bef.name
and now.name in ('user calls', 'execute count', 'user commits', 'user rollbacks',
'consistent changes', 'session logical reads', 'db block gets', 'db block changes',
/**************************
* 원하는 통계 지표 추가 *
**************************/
'cell physical IO bytes saved by storage index',
'cell physical IO interconnect bytes'
)
);
delete from mondba.sysstat1 where no=(select max(no)-2 from mondba.sysstat1);
commit;
모니터링 대상 서버가 많은 대규모 인프라에 적용 시 InfluxDB도 적극 검토해 보자.
이미 graphite 로 구축된 상태라면 InfluxDB와 결합하여 Clustering 구성도 가능하다.
시계열 데이터 저장용 DATABASE
GO 언어로 개발 된 최신 오픈소스 프로젝트 (대량 트래픽 처리에 우수)
Dependency가 없어 설치가 간단함
SQL-like query language
Clustering 지원