의외로 쉬운「시스템 모니터링 툴」제작기
차용민 (마이크로소프트웨어 필자) 06/09/2004
시스템 모니터링이라고 하면 뭔가 복잡하고 어려운 것부터 생각되고 실제로 귀찮은 작업이기도 합니다. 이유있는 문제도 있지만 그렇지 않은 경우도 많습니다. 시스템 에러의 원인을 알 수 없을 때는 참 답답합니다. 그렇다면 그 해결책을 무엇일까요? 스스로 간단한 시스템 모니터링 툴을 만들어 보는 것입니다. SNMP에 대한 기본 지식이 있다면 PHP를 이용해 간단하게 만들 수 있습니다. 리눅스에서 PHP와 SNMP를 이용한 간단한 시스템 모니터링에 대해 알아보겠습니다.
프로그래밍하다 보면 이유 없이 시스템이 다운되는 경우가 있습니다. 물론 이유가 없다는 말은 이유를 알 수 없는 경우입니다. 그렇다고 24시간 서버만 붙잡고 있을 수도 없을 것입니다. 그래서 나온 것이 시스템 모니터링 툴일 것입니다. 시스템 모니터링의 영역은 넓고 방대하지만 여기서 만들어보고자 하는 것은 SNMP를 가지고 직접 시스템의 필요한 부분을 모니터링해 보는 것입니다. 직접 만들어보면 필요한 부분을 원하는 방식으로 모니터링할 수 있습니다. 물론 직접 만드는 것이 복잡하다는 생각이 들 수도 있습니다. 그런 것을 어떻게 만들까 하는 생각이 들 수도 있습니다. 그러나 의외로 쉬운 방법이 있는데, 바로 SNMP의 값을 활용하는 것입니다. SNMP를 이용하면 매우 간단하게 시스템 모니터링에 필요한 값을 가져올 수 있습니다.
그렇다면 어떤 값을 가져올 수 있는지 먼저 알아야 합니다. SNMP로 쉽게 값을 가져올 수 있지만 그렇다고 해서 SNMP가 그리 만만한 것은 아닙니다. 왜냐하면 SNMP로 가져올 수 있는 시스템 모니터링 값 또한 매우 방대하기 때문입니다. 그러나 간단한 모니터링 프로그램을 만들어 보기 위해서 SNMP의 모든 부분을 알 필요는 없을 것입니다. 지금 필요한 부분만 익혀서 사용하면 되고 나중에 필요한 부분이 있으면 차근차근 알아가면 됩니다.
그렇다면 시스템 모니터링에 있어서 가장 필요한 값에는 어떤 것들이 있을까요? 그것은 바로 cpu와 메모리일 것입니다. 그리고 현재 시스템에 어떤 프로세스들이 있는지도 알아야할 것입니다. 이 정도 값만 알 수 있어도 간단하게 원격으로 서버를 모니터링할 수 있습니다. 그렇다면 이런 값들을 가져오기 위해서는 기본적인 프로그램이 설치되어 있어야 합니다. 여기서는 프로그램의 설치되어 있다는 가정 아래 실제로 SNMP 값을 가져오는 부분과 SNMP의 간단한 명령어를 익히게 됩니다. 그리고 PHP에서 SNMP 값을 가져오는 방법과 PHP에서 가져오는 값을 활용해서 모니터링 프로그램을 어떻게 만들어야 하는지도 알아보겠습니다.
SNMP 모니터링을 하기 위해서 필요한 것들
실제로 모니터링 프로그램을 만들기 위해서 필요한 것에는 어떤 것이 있는지 알아보겠습니다. 먼저 모니터링할 서버에 SNMP가 설치되어 있어야 합니다. 윈도우 서버와 리눅스 서버의 SNMP 값은 각각 다릅니다. 여기서 사용하는 것은 리눅스입니다. 리눅스에 일단 net-snmp(http://net-snmp.sourceforge.net/)가 설치되어 있어야 합니다. 설치되어 있지 않다면 이 사이트에서 받아서 설치할 수 있습니다. 그리고 PHP에서 SNMP 함수를 사용할 수 있어야 합니다. 일반적인 웹사이트 서비스를 위해서 PHP가 설치되어 있다면 SNMP 관련 함수를 사용할 수 있도록 설치해 주면 됩니다.
이 두 가지만 갖추어져 있다면 이제 필요한 것은 SNMP 값을 가져오는 것입니다. 그리고 어떤 값을 가져올 지를 미리 정하는 것입니다. 그리고 가장 중요한 것은 SNMP에 대한 기본 지식이 있어야 합니다. 무조건 SNMP 값을 가져다 쓰는 것보다는 SNMP에 대한 기본 지식을 알고 있으면 더 좋을 것입니다. 여기서는 한 대의 서버를 모니터링하는 것이 아니라 여러 대의 서버를 모니터링할 수 있기 때문에 모니터링하는 서버 또한 SNMP가 설치되어 있어야 합니다. SNMP 또한 환경 설정을 따로 할 수 있기 때문에 값을 가져오는 방식이 조금 다를 수 있겠지만 여기서는 기본적인 SNMP 방식으로 설명하겠습니다.
SNMP 기본 명령어 익히기
서버에서 SNMP 값을 가져오는 방법은 SNMP를 설치할 때 같이 설치되는 SNMP 관련 프로그램을 이용해서 가능합니다. 먼저 해당 서버에 SNMP가 설치되어 있는지 확인해야 합니다. 리눅스에서는 해당 서버에 SNMP 데몬이 실행되는 ps 명령으로 먼저 확인해 봅니다.
◆ 리눅스에서 SNMP 데몬이 있는지 확인하기
- ps -aux | grep snmpd
그리고 SNMP 값을 가져오는 데 주로 사용하는 명령어는 snmpwalk입니다. 물론 이 명령어 이외에도 몇 가지가 더 있습니다. 그러나 snmpwalk 명령어로 웬만한 값을 거의 다 가져올 수 있습니다. snmpwalk는 한 가지 값만 가져올 수도 있고 관련된 값을 모두 가져올 수도 있습니다.
◆ SNMP system 관련 값 가져오기
- snmpwalk localhost public system
- snmpwalk ****.com public system
이 명령은 localhost의 system 관련 값을 가져오는 것입니다. 그리고 해당 서버를 지정하면 그 서버의 값도 가져올 수 있습니다. 물론 다른 서버의 값을 가져오고자 할 경우 그 서버에 SNMP가 설치되어 있어야 합니다. 그렇다면 SNMP가 설치되어 있는 서버는 무조건 모니터링할 수 있을까요? 일단 그 서버에 접근 권한이 있어야 합니다. 그리고 SNMP 환경 설정에서 지정한 값만을 모니터링할 수 있습니다. 보안상 SNMP 값을 모두 모니터링하도록 허용한 것이 아니라 일부 값만 모니터링할 수 있도록 허용했을 수도 있습니다.
◆ SNMP system 관련 값의 일부
- system.sysDescr.0 = Linux localhost ...
- system.sysObjectID.0 = OID:
- enterprises.ucdavis.ucdSnmpAgent.linux
- system.sysUpTime.0 = Timeticks: (3526547) 15:33:12.22
- system.sysContact.0 = admin@****.com
- system.sysName.0 = ****.com
- system.sysLocation.0 = Unknown
= system.sysORLastChange.0 = Timeticks: (9) 0:00:00.09
system 관련 값의 일부입니다. 시스템에 관련된 값을 구할 수 있습니다. 그렇다면 이렇게 전부가 아닌 하나의 값만 구하려면 어떻게 할까요?
◆ 하나의 값만 구하기
- snmpwalk ****.com public system.sysDescr.0
- snmpwalk ****.com public sysDescr.0
하나의 값만 구하고자 할 경우에는 이렇게 해당 값을 지정해 주면 됩니다. 그리고 SNMP는 값을 구하는 것만이 아니라 해당 값을 설정할 수도 있습니다. 값을 구하는 것은 단순히 해당 서버의 값을 구하는 것이기 때문에 별다른 영향을 미치지 않습니다. 그러나 값을 설정하는 것은 해당 서버에 영향을 미칠 수도 있습니다. 여기서는 간단한 모니터링을 위한 SNMP 값을 이용하기 때문에 SNMP 값을 설정하는 부분은 다루지 않습니다.
CPU, 메모리 값 가져오기
모니터링하기 위해서 주로 사용되는 값인 cpu, 메모리 그리고 Load Averages 값을 가져오는 부분을 알아보겠습니다. cpu 값을 가져오기 위해서는 해당 MIB를 입력해 주면 됩니다. 여기서 사용되는 MIB 값은 공통적으로 사용되는 것입니다. MIB는 OID라는 숫자로도 표기될 수 있으며 정확하게 ssCpuUser의 계층구조까지 다 적는다면 nterprises.ucdavis.systemStats.ssCpuUser 표현될 수도 있습니다. OID 값으로 표현하면 1.3.6.1.4.1.2021.11.9.0이 됩니다. 모두 같은 의미입니다.
◆ cpu 관련 값 가져오기
- snmpwalk ****.com public ssCpuUser
- snmpwalk ****.com public ssCpuSystem
- snmpwalk ****.com public ssCpuIdle
이렇게 하면 각각 cpu 사용 퍼센트를 가져올 수 있습니다. 이 값은 리눅스에서 top 명령어를 실행했을 때 cpu user, system, idle 값과 같은 값을 가져오게 됩니다. 해당 서버에 접속하지 않고도 SNMP를 이용하면 한 줄? 명령으로 cpu 값을 가져올 수가 있습니다. 그렇다면 메모리 관련 값들에는 어떤 것이 있을까요?
◆ 메모리 관련 값 가져오기
- snmpwalk ****.com public memTotalReal
- snmpwalk ****.com public memTotalFree
- snmpwalk ****.com public memShared
- snmpwalk ****.com public memBuffer
- snmpwalk ****.com public memCached
이렇게 하면 메모리 관련 SNMP 값을 가져올 수 있습니다. 이 값 또한 top 명령을 실행했을 때 출력되는 메모리 관련 값들과 같습니다.
◆ Load Averages 값 가져오기
- snmpwalk ****.com public laLoad.1
- snmpwalk ****.com public laLoad.2
- snmpwalk ****.com public laLoad.3
각각 1, 5, 10분의 Load Averages 값을 가져옵니다. 이렇듯 SNMP를 이용하면 쉽고도 간단하게 다른 서버의 모니터링에 필요한 값을 가져올 수 있습니다. 이렇게 SNMP 값을 모니터링 값에 사용하려면 MIB 또는 OID를 알고 있어야 합니다. 그렇다면 MIB는 어떻게 알 수 있을까요? 여러 사이트와 문서가 있겠지만 net-snmp 사이트에서 제공하는 문서를 볼 수 있습니다. cpu, 메모리, Load Averages MIB가 포함되어 있는 문서는 http://net-snmp.sourceforge.net/mibs/UCD-SNMP-MIB.txt에서 볼 수 있습니다. 이 문서에 있는 MIB 값을 참고한다면 좀 더 다양한 값을 모니터링할 수 있을 것입니다.
MIB, OID는 같다
ssCpuUser, memTotalFree, laLoad.1 등 이런 값들을 MIB라고 부릅니다. MIB는 간단하게 설명하면 SNMP의 값들을 분류해 놓은 것입니다. 그리고 MIB에 해당하는 OID 값이 있습니다. ssCpuUser는 축약한 것으로 enterprises.ucdavis.systemStats.ssCpuUser라고 써주면 됩니다. 그리고 이것의 OID 값은 1.3.6.1.4.1.2021.11.9가 됩니다.
◆ MIB와 OID 예
- MIB : enterprises.ucdavis.systemStats.ssCpuUser
(OID : 1.3.6.1.4.1.2021.11.9)
- MIB : enterprises.ucdavis.memory.memTotalFree
(OID : 1.3.6.1.4.1.2021.4.11)
- MIB : enterprises.ucdavis.laTable.laEntry.laLoad
(OID : 1.3.6.1.4.1.2021.10.1.3)
◆ MIB, OID로 값 얻기
- snmpwalk ****.com public ssCpuUser
- snmpwalk ****.com public enterprises.ucdavis.systemStats.ssCpuUser
- snmpwalk ****.com public .1.3.6.1.4.1.2021.11.9
각각 MIB, OID로 값을 가져오는 것입니다. MIB와 OID 값은 같습니다. MIB는 계층구조로 이뤄져 있습니다. 최상위 계층을 보면 System, Interface, IP, ICMP, TCP, UDP, EGP, Transmission, SNMP 그룹들로 이뤄져 있고 하위 그룹은 트리구조를 이루고 있습니다.
SNMP는 어떻게 PHP 안에 들어갔을까?
일반적으로 PHP는 웹 사이트를 제작하는데 주로 사용되고 있습니다. 물론 다른 곳에도 사용되고 있습니다. 웹 사이트를 만드는 데만 주로 사용하다 보면 다른 곳에 사용할 생각을 잊어버리는 경우가 있습니다. ‘시스템 모니터링하는 프로그램을 만들어야 하는데 어떤 언어를 이용해서 만들 수 있을까?’는 질문에서 PHP를 떠올리기는 쉽지 않을 것입니다. 그러나 데이터베이스를 연동한 프로그램 이외에도 PHP로 할 수 있는 것은 많이 있습니다.
좀 더 자세히 살펴보면 의외로 PHP에는 많은 함수들이 존재하고 있다는 것을 알 게 될 것입니다. 꼭 필요하지 않는 함수라면 굳이 사용할 필요가 없겠지요. PHP를 오래 사용한 사람이라도 ‘이런 함수가 있었나?’고 할 정도로 다양한 함수군이 존재합니다. 그 중에서도 SNMP 관련 함수들이 있습니다.
그렇다면 어떻게 PHP에서 SNMP 함수를 사용할 수 있는 것일까요? 그것은 바로 PHP의 확장성입니다. 확장성이란 필요한 함수를 추가해서 사용할 수 있는 것입니다. SNMP 함수는 이미 누군가 개발을 해서 PHP에서 사용할 수 있도록 추가해 놓았기 때문에 우리는 함수를 호출해서 사용하기만 하면 되는 것입니다. 그렇다면 직접 SNMP 함수를 PHP에서 사용할 수 있도록 만들려면 어떻게 하면 될까요? PHP는 C언어로 만들어졌기 때문에 확장을 하려면 C언어로 확장할 수 있습니다. 물론 C, C++를 알아야 합니다. 그리고 C, C++로 PHP Extensions을 만들어서 추가할 수가 있습니다. SNMP 또한 PHP Extensions으로 만들어서 추가된 것입니다.
PHP에서 사용할 수 있는 SNMP 함수들
PHP에서는 SNMP 값을 어떻게 가져올 수 있을까요? 그것은 간단하게 SNMP 함수를 호출함으로서 가능합니다. 몇 가지의 함수들이 있는데 다음은 PHP에서 사용할 수 있는 SNMP 함수 입니다.
◆ PHP의 SNMP 함수
- snmp_get_quick_print
- snmp_get_valueretrieval
- snmp_read_mib
- snmp_set_enum_print
- snmp_set_oid_numeric_print
- snmp_set_quick_print
- snmp_set_valueretrieval
- snmpget
- snmpgetnext
- snmprealwalk
- snmpset
- snmpwalk
- snmpwalkoid
이 함수들 중에서 유용하게 사용할 수 있는 것은 snmpget, snmpwalkoid입니다. snmpget은 하나의 값을 가져 올 수 있으며 snmpwalkoid는 관련된 값들을 모두 가져올 수 있습니다. <리스트 1>을 보면 snmpget 함수의 사용 예가 있습니다. 먼저 snmp로 cpu 사용량을 가져오기 위해서는 값을 가져올 서버를 지정해야 합니다. 그리고 cpu idle 값에 해당하는 oid를 알고 있어야 합니다.
◆ cpu idle 에 해당하는 snmp oid
- .1.3.6.1.4.1.2021.11.11.0
그리고 snmp 설정에 따라서 다르겠지만 커뮤니티에 해당하는 값은 ‘public’으로 해주면 됩니다. 이 세 가지 값을 지정하면 snmpget 함수는 해당 서버의 cpu idle의 값을 가져오게 됩니다. 값을 가져오지 못했을 경우 false를 리턴하게 됩니다. 그리고 값을 정상적으로 가져왔을 경우에는 10, 20 등 이런 식으로 cpu idle 퍼센트 값이 들어 있게 됩니다.
<리스트 1> CPU 사용량 가져오기
<?php
// CPU 사용
$host = "www.*****.com";
$oid = ".1.3.6.1.4.1.2021.11.11.0";
$timeout = 1;
// enterprises.ucdavis.systemStats.ssCpuIdle.0
$ssCpuIdle = @snmpget($host, "public", $oid, $timeout);
// 값을 구하지 뭇했다면
if ($ssCpuIdle === false) {
$ssCpuUser = "Error";
} else {
//(user, system) = 100 - idle
$ssCpuUser = 100 - $ssCpuIdle;
// CPU 사용
$ssCpuUser = $ssCpuUser . "%";
}
// cpu 사용량
echo $ssCpuUser;
?>
출력은 10%, 20% 등으로 해주면 됩니다. 그러나 여기서 구하고자 했던 값은 현재 cpu 사용량이었습니다. 그런데 왜 cpu 사용량을 구하지 않은 것일까요? 그 이유를 알기 위해서는 먼저 snmp에서 가져올 수 있는 cpu 관련 값을 알아야 합니다.
◆ snmp cpu 관련 값
- ssCpuUser
cpu user 값을 가져옵니다.
- ssCpuSystem
cpu system 값을 가져옵니다.
- ssCpuIdle
cput idle 값을 가져옵니다.
ssCpuUser + ssCpuSystem + ssCpuIdle = 100(%)
◆ 현재 cpu 사용량
ssCpuUser + ssCpuSystem
cpu 사용량 값을 퍼센트로 가져오게 됩니다. 세 가지 값을 합하면 100이 됩니다. 그래서 cpu idle 값을 가져온 후에 ‘100-idle’ 해주면 현재 cpu 사용량이 나오게 됩니다. 이 값은 cpu 사용의 퍼센트를 의미하므로 %를 붙여서 출력해 주면 됩니다.
echo $ssCpuUser . "%";
snmpget 함수를 이용해서 cpu 관련 값들을 가져오는 방법을 알아봤습니다.
메모리 관련 값 가져오기
snmpget 함수를 이용해서 메모리 관련 값을 가져오는 방법 또한 cpu의 값을 가져오는 것과 비슷합니다. 여기서 먼저 알아야할 것은 메모리 값을 가져오는데 필요한 SNMP OID 값입니다. <리스트 2>를 보면 메모리 관련 값을 가져오는 예가 있습니다. 먼저 값을 가져올 서버와 메모리 관련 OID 값을 지정합니다.
◆ 메모리 Free 구하기
// enterprises.ucdavis.memory.memTotalFree.0
$memTotalFree = @snmpget($host, "public", $oid, $timeout);
메모리 Free량을 구하는 것입니다. 값을 구했을 경우에는 12444, 45442 이렇게 남은 메모리 량을 리턴하게 됩니다. 이 값은 KB 단위이므로 출력하고자 할 경우에는 K를 붙여서 12444K 이런 식으로 출력해 주면 됩니다.
◆ 전체 메모리 크기 구하기
// enterprises.ucdavis.memory.memTotalReal.0
$memTotalReal = @snmpget($host, "public", $oid, $timeout);
SNMP에서 구하는 값은 실제 메모리 크기와는 차이가 있습니다. 메모리는 두 가지 값을 구했습니다. 그 이유는 무엇일까요? 그것은 남은 메모리의 크기를 퍼센트로 표현하기 위해서는 전체 메모리의 크기를 알아야 하기 때문입니다. cpu는 퍼센트 값을 리턴하기 때문에 상관이 없지만 메모리는 크기를 리턴하기 때문에 전체 메모리 크기와 Free 메모리 크기를 구해서 퍼센트를 계산해 주면 됩니다.
<리스트 2> SNMP 함수로 메모리 관련 값 가져오기
<?php
// 메모리 사용량 구하기
$host = "www.*****.com";
$oid = ".1.3.6.1.4.1.2021.4.11.0";
$timeout = 200000;
// enterprises.ucdavis.memory.memTotalFree.0
$memTotalFree = @snmpget($host, "public", $oid, $timeout);
if ($memTotalFree === false) {
memTotalFree = "Error";
} else {
$memTotalFree = $memTotalFree . "K";
}
id = ".1.3.6.1.4.1.2021.4.5.0";
// enterprises.ucdavis.memory.memTotalReal.0
$memTotalReal = @snmpget($host, "public", $oid, $timeout);
if ($memTotalReal === false) {
$memTotalReal = "Error";
} else {
$memTotalReal = $memTotalReal . "K";
}
echo "메모리 크기 : " . $memTotalReal;
echo "메모리 free : " . $memTotalFree;
?>
SNMP는 시스템 리소스를 사용한다
SNMP 값을 가져오려면 일단 명령을 실행하는 서버와 값을 가져오려고 하는 서버에 모두 SNMP가 설치되어 있어야 합니다. 두 서버에 모두 설치가 되어 있으면 원하는 값을 가져올 수 있게 됩니다. 그렇다면 SNMP 값을 가져오는데 어느 정도의 시스템 리소스를 사용하게 될까요? 그것은 어떤 SNMP 값을 가져오는가에 따라서 다르게 됩니다. 그리고 시스템의 사양에 따라서도 조금씩 차이가 있습니다.
SNMP 값을 가져오는 데 해당 시스템의 리소스를 너무 많이 차지하게 된다면 서버에 영향을 미칠 수 있으므로 먼저 테스트해 보는 것이 좋습니다. SNMP 값을 가져오는 데는 주로 cpu system 리소스가 사용됩니다. 앞에서 테스트했던 cpu, Load Averages 값을 가져오는 것은 1% 미만의 cpu system을 사용하게 됩니다. 그러나 메모리의 값을 가져오는 것은 10% 정도까지 cpu system 리소스를 사용할 수도 있습니다. 물론 서버마다 차이가 있으니 테스트해 보면 됩니다.
그렇다면 1초에 한번씩 cpu 값을 가져오는 것은 큰 문제가 없어 보입니다. 해당 시스템을 모니터링하려면 1초에 한 번씩 값을 가져와서 출력해 주기 위해서입니다. 그러나 메모리의 값을 1초에 한 번씩 가져오는 것은 뭔가 문제가 있어 보입니다. 왜일까요? 1초에 한 번씩 해당 서버의 cpu system 리소스를 사용하게 되면 10% 정도의 cpu system 리소스를 사용하게 되기 때문에 뭔가 문제가 있어 보입니다. 그리고 프로그램을 하나만 실행시키는 것이 아니라 여러 사람이 모니터링 프로그램을 실행시켜서 사용하고 있다면 1초에 한 번씩 메모리 값을 가져오는 것은 문제가 있습니다. 그럴 경우에는 적당히 간격을 조정하면 됩니다. 한 5초 정도의 주기로 값을 가져오면 될 것입니다. 1초, 5초에 한 번씩 값을 가져오는 이유는 실시간 모니터링을 위해서입니다.
여러 서버의 Load Averages 구하기
서버가 여러 대 있을 때 현재 서버의 Load Averages를 보고자 할 경우 일반적으로는 리눅스에서는 서버에 접속해서 top 명령어를 실행해서 봐야 합니다. 물론 서버가 몇 대 없다면 충분히 가능한 일이겠지만 서버가 몇 십 대가 있을 경우 어떻게 해야 할까요? 일일이 서버에 접속해서 top 명령을 실행해서 결과를 보려고 해도 한참 걸릴 것입니다. 그러나 PHP에서 SNMP 함수를 이용한다면 간단하게 모든 서버의 Load Averages 값을 구할 수 있습니다. 그리고 더 중요한 것은 Load Averages 값이 큰 순서대로 정렬하는 것도 가능하다는 것입니다. Load Averages 값이 크다는 것은 해당 서버의 부하가 높다는 것입니다. 어떤 서버의 Load Averages 값이 높은지 쉽게 파악이 가능하다는 것입니다.
<리스트 3> 여러 서버의 Load Averages 구하기
<?php
// 모니터링할 서버 목록
$hostList = array("server***1.net",
"server***2.net",
"server***3.net",
"server***4.net",
"server***5.net");
// 1분 Load Averages
$oid = ".1.3.6.1.4.1.2021.10.1.6.1";
$timeout = 1;
$sort = "Desc";
// 각 서버의 Load Averages 값 구하기
for($z = 0; $z < $hostList; $z++) {
$host = $hostList[$z];
$valList[$host] = @snmpget($host, "public", $oid, $timeout);
}
// Asc, Desc 정렬하기
if ($sort == 'Asc')
asort($valList);
else if ($sort == 'Desc')
arsort($valList);
// 출력하기
foreach($valList as $host => $load) {
echo "<br> $host - $load";
}
// 출력 결과 예
//server***4.net - 0.124
//server***2.net - 0.110
//server***5.net - 0.012
//server***3.net - 0.003
//server***1.net - 0.001
?>
<리스트 3>을 보면 여러 서버의 Load Averages를 구하는 소스가 있습니다. 먼저 $hostList 배열에는 서버의 목록이 있습니다. cpu, 메모리 값을 구할 때는 한 대의 서버 값만 구했기 때문에 한 서버만 있었지만 Load Averages는 한 번에 여러 대의 서버에서 값을 구해야 하기 때문에 배열에 서버의 목록이 있습니다. 그리고 Load Averages의 OID 값도 있어야 합니다. $sort 값은 Desc 정렬을 할지 Asc 정렬을 할 지 지정해 주면 됩니다. 그리고 for 문을 이용해서 모든 서버의 값을 구합니다. 그 결과는 $valList 배열에 넣습니다.
그렇다면 for 문에서 값을 구해서 바로 출력해 버려도 되는데 굳이 배열에 값을 저장한 이유는 무엇일까요? 그것은 정렬을 하기 위해서입니다. 그냥 서버의 Load Averages 값을 순서대로 출력해도 되겠지만 Load Averages 값이 높거나 낮은 순으로 정렬해서 보여준다면 더 좋을 것입니다. 그래서 일단 값을 배열에 넣었습니다. 그리고 배열을 정렬하는 함수를 이용해서 정렬해 주면 됩니다. Asc 정렬은 asort() 함수를 Desc 정렬은 arsort() 함수를 호출해 주면 됩니다. 이렇게 정렬한 다음에 foreach 문을 이용해서 해당 값을 출력해 주면 됩니다. 그러면 Load Averages 값의 크기에 따라서 출력됩니다. 간단하게 웹 브라우저에서 여러 대의 서버의 Load Averages를 모니터링할 수 있는 것입니다. 서버의 대수가 많을수록 일일이 서버에 접속해서 top 명령을 실행해서 보는 것보다는 몇 배의 효과를 볼 수 있을 것입니다.
그렇다면 cpu, 메모리도 이와 같은 방법으로 볼 수 있지 않을까 하는 생각이 들 것입니다. 그러나 cpu 값은 수시로 변하는 것이기 때문에 한 서버의 값을 계속 모니터링하는 것은 의미가 있겠지만 이런 식으로 여러 대의 서버를 보는 것은 별 의미가 없습니다. 메모리 값은 충분히 해볼만 합니다. 다만 메모리 값을 구하는 데는 시간이 조금 걸리기 때문에 서버의 대수가 많을수록 값을 구하는 속도가 느릴 것입니다.
TCP 연결 상태 구하기
현재 서버의 어떤 포트에 tcp 연결이 있는지 확인하기 위해서는 리눅스에서는 netstat 명령으로 확인할 수가 있습니다. 그리고 이 값을 SNMP에서도 가져올 수 있습니다. SNMP는 MIB로 분류가 되어 있다고 했었는데 tcp 그룹에 해당되는 값을 가져오면 됩니다.
◆ tcp 값 가져오기
snmpwalk ****.net public tcp.tcpConnTable.tcpConnEntry.tcpConnState
이렇게 명령을 내리면 해당 서버의 tcp 연결 값들이 보일 것입니다. 한 가지 예를 들면 다음과 같이 연결된 값이 보이게 됩니다.
◆ tcp 값의 예
tcp.tcpConnTable.tcpConnEntry.tcpConnState.211.***.***.***.80.210.***.***.
***.12454 = established(5)
이것은 하나의 예를 든 것이고 연결된 실제로는 모든 값이 보이게 됩니다. 211.***.***.***은 해당 서버를 의미합니다. 그리고 80은 해당 서버의 포트를 의미합니다. 210.***.***.***은 해당 서버에 연결된 IP입니다. 12454는 해당 서버의 프로세스 아이디입니다. 결과적으로 210.***.***.*** IP가 211.***.***.*** 서버의 80포트에 12454 프로세스 아이디로 연결되어 있다는 의미입니다. 해당 서버의 tcp 연결 개수가 작다면 별 문제가 되지 않겠지만 연결이 많고 시스템 리소스가 부족한 경우에는 timeout으로 인해서 값을 가져오지 못하는 경우도 있습니다. 그리고 tcp 연결 개수에 따라서 cpu system 리소스 사용량도 달라집니다.
예를 들어서 200~300 정도 연결되어 있다면 약 10% 이내의 cpu system 리소스를 사용하겠지만 1000개 이상의 연결되어 있을 경우에는 약 40% 정도의 리소스를 사용할 수도 있으며 timeout으로 값을 가져오지 못할 수도 있습니다. 물론 이것은 서버 사양에 따라서 다를 수 있습니다. timeout 값을 크게 주면 tcp 값을 못 가져오는 경우는 없겠지만 해당 서버의 리소스를 너무 많이 사용하게 되는 문제가 발생할 수도 있습니다. 그래서 SNMP 값을 가져오는데 timeout 시간 지정 또한 중요합니다.
PHP에서 TCP 연결 상태 구하기
<리스트 4>에 PHP에서 SNMP로 tcp 연결 상태를 가져오는 소스가 있습니다. PHP에서 해당 서버의 tcp 연결 상태를 볼 수 있다는 것은 뭔가 새로울 것입니다. 물론 SNMP를 통해서 가져오는 것이지만요. 그리고 한 가지 더 연결 상태별로 카운트를 셀 수도 있습니다. 먼저 $tcpConnStateCount에는 tcp의 연결 종류가 있습니다.
<리스트 4> tcp 연결 상태 구하기
<?php
// tcp 연결 상태 카운트
$tcpConnStateCount = array('All' => 0,
'closed' => 0,
'listen' => 0,
'synSent' => 0,
'synReceived' => 0,
'established' => 0,
'finWait1' => 0,
'finWait2' => 0,
'closeWait' => 0,
'lastAck' => 0,
'closing' => 0,
'timeWait' => 0,
'deleteTCB' => 0);
$host = "*****.net";
$oid = ".1.3.6.1.2.1.6.13.1.1";
$timeout = 1;
// ex) tcp.tcpConnTable.tcpConnEntry.tcpConnState
// .211.***.***.***.80.210.***.***.***.12454 = established(5)
$tcpConn = @snmpwalkoid($host, "public", $oid, $timeout);
$tcpList = array();
// tcp 값을 구했다면
if ($tcpConn) {
foreach($tcpConn as $key => $val) {
// ex) established(5) -> established
$tcpStateTmp = ereg_replace("(\([0-9]+\))+$", "", $val);
// tcp 연결 상태별로 카운트 하기
$tcpConnStateCount[$tcpStateTmp]++;
$tcpList[] = $key;
} // foreach end
// tcp 연결 상태별로 카운트 출력
foreach($tcpConnStateCount as $key => $val) {
echo "<br>$key : $val";
}
// tcp 연결된 값들 출력
foreach($tcpList as $key) {
echo "<br>$key";
}
} // if end
?>
SNMP에서 분류하는 tcp의 연결 종류입니다. 그리고 다른 값을 가져올 때와 마찬가지로 서버, OID 값이 있습니다. cpu, 메모리 값을 가져올 때는 snmpget() 함수를 사용했었지만 여기서는 snmpwalkoid() 함수를 사용합니다. snmpwalkoid() 함수를 이용해야 tcp에 연결된 모든 목록을 가져올 수 있기 때문입니다. SNMP 값을 정상적으로 가져왔다면 $tcpConn 변수에 배열로 값이 리턴돼 있을 것입니다. 그렇다면 여기서 tcp 연결 상태별로 카운트를 세기 위해서 foreach 문으로 가공하면 됩니다. 여기서 연결 상태별로 카운트를 하고 $tcpList 배열에 상태를 저장해 주면 됩니다. 그리고 그 다음 foreach 문에서 값을 출력해 주면 됩니다. 이렇게 함으로써 tcp 연결 상태별로 개수를 파악할 수 있습니다. 그리고 어떤 포트에 어느 서버가 연결되어 있는지도 파악할 수가 있게 됩니다.
이 소스코드는 간단하게 연결 개수와 상태를 출력해 주는 것입니다. 그러나 더 기능을 추가해 보자면 어떤 것이 있을까요? 연결된 서버의 IP가 출력되도록 했는데, IP보다는 hostname으로 출력한다면 보기 쉬울 것입니다. 예를 들면 210.***.***.***를 hostname 으로 출력한다면 *****.net 이런식으로 해당 서버의 hostname이 출력 되므로 좀 더 명확하게 파악할 수 있을 것입니다. 그리고 모든 포트가 같이 출력되는데 특정 포트만 검색해서 출력할 수도 있습니다. 그것은 배열을 좀 더 가공해서 출력해 주면 됩니다.
◆ PHP에서 ip로 hostname 구하기
- gethostbyaddr("210.***.***.***");
좀 더 깊이 생각해보고 배열을 가공해 본다면 더 보기 쉽게 tcp 연결 상태를 출력할 수 있을 것입니다. 여기서는 tcp 연결 값을 구했지만 udp 연결 값 또한 SNMP에서 구할 수 있습니다.
그래프로 모니터링 툴 업그레이드
지금까지 SNMP의 기본 개념과 PHP로 SNMP 값을 가져오는 부분을 설명했습니다. 그러나 간단하게 웹 브라우저 상에서 값을 출력하는 정도에 그쳤습니다. cpu, 메모리, Load Averages 값을 그래프로 출력해서 볼 수도 있습니다. PHP에서 이런 값들을 가지고 그래프를 그리고자 한다면 쉽지는 않을 것입니다. 더군다나 cpu 모니터링 결과를 실시간으로 그려야 한다면 아마도 답이 보이지 않을 수도 있습니다. 여기서 만들어 보고자 했던 것은 간단한 모니터링 툴입니다.
로그를 남기고 <화면 1>처럼 그래프로 그리고 방대한 량의 정보를 수집하고 그래야 하는 툴이라면 다른 GUI 툴을 이용해서 만드는 것이 효과적일 것입니다. 아니면 이미 만들어져 있는 툴을 사용해도 될 것입니다. 굳이 PHP에서 그래프로 그려보는 이유는 스스로 만들다보면 다른 툴에서 지원되지 않는 기능 또한 간단하고 쉽게 추가해 볼 수 있기 때문입니다. 그것이 PHP의 장점이기도 합니다.
<화면 1> 원도우의 cpu, 메모리 사용량
그렇다면 여기서 지금까지 SNMP로 가져온 cpu, 메모리, Load Averages 값을 실시간으로 모니터링할 수 있는 방법은 무엇일까요? 제일 간단한 방법은 자바스크립트를 이용하는 것입니다. 자바스크립트로 공개된 그래프 소스들이 많으니 그걸 이용해서 그려보면 됩니다. PHP에서 SNMP로 구한 값을 iframe에서 자바스크립트 그래프로 값을 계속해서 공급해 주면 되는 것입니다. 그러면 <화면 1>과 같은 그래프가 나올 수 있을 것입니다.
새로운 것과의 만남
새로운 것과의 만남은 항상 사람의 마음을 설레게 합니다. 프로그래머 또한 새로운 것과의 만남은 즐거움일 수 있습니다. SNMP는 여러 가지 언어에서 지원하고 있습니다. 굳이 PHP가 아니더라도 다른 언어로 시스템 모니터링하는 프로그램을 만들어 봐도 좋을 것입니다. 중요한 것은 시스템 모니터링 프로그램을 만들면서 시스템을 이해하고 배워간다는 것입니다. 시스템을 이해하고 프로그램을 만든다면 그 프로그램은 이전의 것과 다를 것입니다. 그것이 바로 프로그래머의 즐거움이기도 합니다. @
'PHP관련' 카테고리의 다른 글
php 에서 사용하기 위한 라이브러리 설치 모음 (0) | 2011.10.14 |
---|---|
4,000 바이트 제한이 문제가 되십니까? LOB를 활용하십시오... (0) | 2011.10.14 |
그래프(chart ... )를 그려 보자 ㅡㅡ; (0) | 2011.10.14 |
PHP에서 공유메모리 사용하기 (0) | 2011.10.14 |
초급용 php : 게시판의 꽃 페이징을 아십니까? (0) | 2011.10.14 |