:meta-keywords: install systemtap, systemtap marker, systemtap probe, systemtap event, systemtap script, connection markers, query markers, object operation markers, index operation markers, locking markers, transaction markers, I/O markers :meta-description: SystemTap is a tool that can be used to dynamically monitor and track the process of running, to find and diagnose performance bottlenecks; learn how to use CUBRID markers in SystemTap scripts. ********* SystemTap ********* 개요 ==== SystemTap은 실행 중인 프로세스를 동적으로 모니터링하고 추적할 수 있는 도구이다. CUBRID는 SystemTap을 지원하며, 이를 통해 성능 병목 현상의 원인을 찾아낼 수 있다. SystemTap 스크립트의 기본 아이디어는 이벤트를 명명하고, 거기에 핸들러를 부여하는 것이다. 핸들러는 이벤트가 발생할 때마다 행해져야할 작업을 명시하는 스크립트 문장이다. SystemTap을 사용하여 CUBRID의 성능을 모니터링하려면 먼저 SystemTap을 설치해야 한다. 설치 이후 C 언어와 비슷한 SystemTap 스크립트를 작성, 수행하여 시스템의 성능을 모니터링할 수 있다. SystemTap은 Linux OS에서만 지원한다. SystemTap에 대한 자세한 내용 및 설치 방법에 대해서는 http://sourceware.org/systemtap/index.html\ 을 참고한다. SystemTap 설치하기 ================== 설치 확인 --------- 1. /etc/group 파일에 stapusr, stapdev 그룹 계정이 있는지 확인한다. 이 계정이 없으면 설치가 되지 않은 상태일 것이다. 2. stapusr, stapdev 그룹 계정에 CUBRID를 설치할 때 사용한 사용자 계정을 추가한다. 여기서는 cubrid라고 가정한다. :: $ vi /etc/group stapusr:x:156:cubrid stapdev:x:158:cubrid 3. SystemTap의 수행 가능 여부는 간단히 다음 명령을 실행하여 확인할 수 있다. :: $ stap -ve 'probe begin { log("hello world") exit() }' 버전 ---- CUBRID에서 SystemTap 스크립트를 실행하려면 SystemTap 2.2 이상 버전을 사용해야 한다. 다음은 CentOS 6.3에서 SystemTap을 설치한 예이다. 버전 확인 및 설치 방법은 각 Linux 배포판마다 다를 수 있다. 1. 현재 설치된 SystemTap 버전을 확인한다. :: $ sudo yum list|grep systemtap systemtap.x86_64 1.7-5.el6_3.1 @update systemtap-client.x86_64 1.7-5.el6_3.1 @update systemtap-devel.x86_64 1.7-5.el6_3.1 @update systemtap-runtime.x86_64 1.7-5.el6_3.1 @update systemtap-grapher.x86_64 1.7-5.el6_3.1 update systemtap-initscript.x86_64 1.7-5.el6_3.1 update systemtap-sdt-devel.i686 1.7-5.el6_3.1 update systemtap-sdt-devel.x86_64 1.7-5.el6_3.1 update systemtap-server.x86_64 1.7-5.el6_3.1 update systemtap-testsuite.x86_64 1.7-5.el6_3.1 update 2. SystemTap 2.2 미만 버전이 설치되어 있다면 삭제한다. :: $ sudo yum remove systemtap-runtime $ sudo yum remove systemtap-devel $ sudo yum remove systemtap 3. SystemTap 2.2 이상 버전의 RPM 배포 패키지를 설치한다. RPM 배포 패키지는 (http://rpmfind.net/linux/rpm2html/)에서 찾을 수 있다. :: $ sudo rpm -ivh systemtap-devel-2.3-3.el6.x86_64.rpm $ sudo rpm -ivh systemtap-runtime-2.3-3.el6.x86_64.rpm $ sudo rpm -ivh systemtap-client-2.3-3.el6.x86_64.rpm $ sudo rpm -ivh systemtap-2.3-3.el6.x86_64.rpm 관련 용어 ========= .. https://sourceware.org/systemtap/wiki/UsingMarkers 마커(Marker) ------------ 코드 안에 위치하는 마커는 실행 중에 제공할 수 있는 함수(프로브)를 호출하기 위한 훅(hook)을 제공한다. 마커가 발동될 때마다 사용자가 제공한 함수가 호출되고, 해당 함수가 종료되면 호출자에게 돌아온다. 마커 발동 시 사용자가 정의하는 함수, 즉 프로브는 추적 및 성능 측정을 위해 사용될 수 있다. 프로브(Probe) ------------- 프로브(probe)는 어떤 이벤트가 발생했을 때의 동작을 정의하는 일종의 함수로서, 이벤트와 핸들러로 나뉜다. SystemTap 스크립트에는 특정 이벤트, 즉 마커가 발생할 때의 동작을 정의한다. SystemTap 스크립트는 여러 개의 프로브를 가질 수 있으며, 프로브의 핸들러는 프로브 바디(probe body)라고 불린다. SystemTap 스크립트는 코드의 재컴파일 없이 계측 코드의 삽입을 허용하며 핸들러에 관해 더 많은 유연성을 제공한다. 이벤트는 핸들러가 실행하도록 트리거로 동작한다. 핸들러는 데이터를 기록하고 그것을 출력하도록 명시될 수 있다. CUBRID가 제공하는 마커는 :ref:`cubrid-marker`\ 를 참고한다. .. https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/5/html-single/SystemTap_Beginners_Guide/#systemtapscript-events 비동기 이벤트 ------------- 비동기 이벤트는 내부에서 정의된 것으로, 코드에서 특정 작업이나 위치에 의존적이지 않다. 이러한 계열의 프로브 이벤트는 주로 카운터, 타이머 등이다. 비동기 이벤트의 예는 다음과 같다. * begin SystemTap 세션의 시작. 예) SystemTap이 시작하는 순간. * end SystemTap 세션의 끝. * timer events 핸들러가 주기적으로 실행되는 것을 명시하는 이벤트. 예) 5초마다 "hello world"를 출력한다. :: probe timer.s(5) { printf("hello world\n") } CUBRID에서 SystemTap 사용하기 ============================= CUBRID 소스 빌드 ---------------- SystemTap 은 리눅스에서만 사용할 수 있다. CUBRID 소스를 빌드해 SystemTap을 사용하려면 **ENABLE_SYSTEMTAP** 을 **ON** (기본값)으로 설정한다. 이 옵션은 릴리즈 빌드에 포함되어 있으며, CUBRID 소스 파일을 빌드하지 않고 인스톨 패키지를 이용하여 설치한 사용자라도 SystemTap 스크립트를 이용할 수 있다. 다음은 CUBRID의 소스를 빌드하는 예이다. :: build.sh -m release SystemTap 스크립트 실행 ----------------------- CUBRID에서 SystemTap 스크립트 예제는 $CUBRID/share/systemtap 이하 디렉터리에 제공하고 있다. 다음은 buffer_access.stp 파일을 수행하는 명령의 예이다. :: cd $CUBRID/share/systemtap/scripts stap -k buffer_access.stp -o result.txt 결과 출력 --------- 특정 스크립트를 수행하면, 스크립트에 기록한 코드에 의해 필요한 정보를 콘솔에 출력한다. -o *filename* 옵션을 명시하는 경우 해당 옵션에 명시한 *filename*\ 에 결과를 기록한다. 다음은 앞서 보인 예제의 출력 결과이다. :: Page buffer hit count: 172 Page buffer miss count: 172 Miss ratio: 50 .. _cubrid-marker: CUBRID 마커 =========== SystemTap의 가장 유용한 기능은 마커를 사용자 소스 코드(CUBRID 코드) 안에 삽입할 수 있다는 점과 이 마커에 다다를 때 발동하는 프로브를 스크립트에서 작성할 수 있다는 점이다. 연결 마커 --------- 일정 기간 동안 연결 활동(연결 개수, 연결 지속 시간, 평균 연결 지속 시간, 최대 연결 획득 개수 등)과 관련된 분석에 도움이 되는 정보를 수집하는 것은 관심이 가는 일이다. 이러한 모니터링 스크립트를 작성하기 위해서는 연결 시작 마커와 연결 끝 마커가 필요하다. .. function:: conn_start(connection_id, user) 서버에서 질의 실행이 시작되면 이 마커가 발동된다. :param connection_id: 연결 ID를 포함한 정수값 :param user: 연결의 사용자 이름. .. function:: conn_end(connection_id, user) 서버에서 질의 실행이 끝나면 이 마커가 발동된다. :param connection_id: 연결 ID를 포함한 정수값 :param user: 연결의 사용자 이름 질의 마커 --------- 이벤트 관련 질의 실행을 위한 마커로서, 비록 전체 시스템에 관련된 전체(global) 정보를 포함하지는 않지만 모니터링 작업에서 매우 유용하다. 적어도 아래 두 개의 마커는 가장 기본이 되는 것이다. 질의 실행의 시작과 종료 시에 각각 해당 마커가 발동된다. .. function:: query_exec_start(query_string, query_id, connection_id, user) 서버에서 질의 실행이 시작되면 이 마커가 발동된다. :param query_string: 실행할 질의를 나타내는 문자열 :param query_id: 질의 식별자 :param connection_id: 연결 식별자 :param user: 연결할 때 사용하는 사용자 이름 .. function:: query_exec_end(query_string, query_id, connection_id, user, status) 서버에서 질의 실행이 끝나면 이 마커가 발동된다. :param query_string: 실행할 질의를 나타내는 문자열 :param query_id: 질의 식별자 :param connection_id: 연결 식별자 :param user: 연결할 때 사용하는 사용자 이름 :param status: 질의 실행 시 반환 상태(Success, Error) 객체 연산 마커 -------------- 저장 엔진을 포함하는 연산들은 치명적이며 테이블이나 객체 수준에서 업데이트를 조사하는 것(probing)은 데이터베이스의 동작을 모니터링하는 데 큰 도움이 된다. 객체가 매번 INSERT/UPDATE/DELETE될 때마다 마커가 발동되는데, 이 점은 모니터링 스크립트와 서버 둘 다에 성능 상 약점이 될 수 있다. .. function:: obj_insert_start(table) 이 마커는 객체가 삽입되기 전에 발동된다. :param table: 이 연산의 대상 테이블 .. function:: obj_insert_end(table, status) 이 마커는 객체가 삽입된 이후에 발동된다. :param table: 이 연산의 대상 테이블 :param status: 이 연산의 성공 여부를 나타내는 값 .. function:: obj_update_start(table) 이 마커는 객체가 갱신되기 전에 발동된다. :param table: 이 연산의 대상 테이블 .. function:: obj_update_end(table, status) 이 마커는 객체가 갱신된 후에 발동된다. :param table: 이 연산의 대상 테이블 :param status: 이 연산의 성공 여부를 나타내는 값 .. function:: obj_deleted_start(table) 이 마커는 객체가 삭제되기 전에 발동된다. :param table: 이 연산의 대상 테이블 .. function:: obj_delete_end(table, status) 이 마커는 객체가 삭제된 후에 발동된다. :param table: 이 연산의 타겟 테이블 :param status: 이 연산의 성공 여부를 나타내는 값 인덱스 연산 마커 ---------------- 위의 마커는 테이블 기반 마커이고, 다음은 인덱스 기반 마커이다. 잘못된 인덱스의 사용은 시스템에서 많은 문제를 유발하는 원인이 될 수 있으며, 인덱스를 모니터링할 수 있다는 점은 매우 유용하다. 아래 마커들은 테이블에서 사용된 마커와 매우 유사한데, 인덱스가 테이블과 같은 연산을 지원하기 때문이다. .. function:: idx_insert_start(classname, index_name) 이 마커는 B-Tree에 인덱스 노드를 삽입하기 전에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 .. function:: idx_insert_end(classname, index_name, status) 이 마커는 B-Tree에 인덱스 노드를 삽입한 이후에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 :param status: 연산의 성공 여부를 나타내는 값 .. function:: idx_update_start(classname, index_name) 이 마커는 B-Tree에서 인덱스 노드를 갱신하기 전에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 .. function:: idx_update_end(classname, index_name, status) 이 마커는 B-Tree에서 인덱스 노드를 갱신한 이후에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 :param status: 연산의 성공 여부를 나타내는 값 .. function:: idx_delete_start(classname, index_name) 이 마커는 B-Tree에서 인덱스 노드를 삭제하기 전에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 .. function:: idx_delete_end(classname, index_name, status) 이 마커는 B-Tree에서 인덱스 노드를 삭제한 후에 발동된다. :param classname: 대상 인덱스의 테이블 이름 :param index_name: 대상 인덱스 이름 :param status: 연산의 성공 여부를 나타내는 값 잠금(locking) 마커 ------------------ 잠금 이벤트를 포함하는 마커는 아마도 전체를 모니터링하는 작업에서 가장 중요할 것이다. 잠금 시스템은 서버 성능과에 큰 영향을 끼치며, 잠금 대기 시간 및 카운트(교착 상태 및 회피된 트랜잭션 개수)는 문제를 찾는데 매우 유용하다. .. function:: lock_acquire_start(OID, table, type) 이 마커는 잠금이 요청되기 전에 발동된다. :param OID: 잠금 요청 대상 객체 ID :param table: 객체를 유지하고 있는 테이블 :param type: 잠금 타입(X_LOCK, S_LOCK 등) .. function:: lock_acquire_end(OID, table, type) 이 마커는 잠금 요청이 완료된 이후에 발동된다. :param OID: 잠금 요청 대상 객체 ID :param table: 객체를 유지하고 있는 테이블 :param type: 잠금 타입(X_LOCK, S_LOCK etc.) :param status: Value showing whether the request has been granted or not. .. function:: lock_release_start(OID, table, type) 이 마커는 잠금이 해제된 이후에 발동된다. :param OID: 잠금 요청 대상 객체 ID :param table: 객체를 유지하고 있는 테이블 :param type: 잠금 타입(X_LOCK, S_LOCK etc.) .. function:: lock_release_end(OID, table, type) This marker should be triggered after a lock release operation has been completed. :param OID: 잠금 요청 대상 객체 ID :param table: 객체를 유지하고 있는 테이블 :param type: 잠금 타입(X_LOCK, S_LOCK etc.) 트랜잭션 마커 ------------- 서버 모니터링에서 관심있게 봐야 할 측정 대상은 트랜잭션의 활동이다. 간단한 예로, 트랜잭션이 취소된 개수는 교착 상태가 발생한 개수와 밀접하게 관련되어 있으며, 매우 중요한 성능 식별자라 할 수 있다. 또 다른 직관적인 사용 예는 간단한 SystemTap 스크립트를 사용하여 TPS와 같은 시스템 성능 통계를 수집하는 방법을 단순화하는 것이다. .. function:: tran_commit(tran_id) 이 마커는 트랜잭션이 성공적으로 완료된 이후에 발동된다. :param tran_id: 트랜잭션 식별자 .. function:: tran_abort(tran_id, status) 이 마커는 트랜잭션이 중단(abort)된 이후에 발동된다. :param tran_id: 트랜잭션 식별자 :param status: 종료 상태 .. function:: tran_start(tran_id) 이 마커는 트랜잭션이 시작된 이후에 발동된다. :param tran_id: 트랜잭션 식별자 .. function:: tran_deadlock() 이 마커는 교착상태가 감지된 이후에 발동된다. I/O 마커 -------- I/O 액세스는 RDBMS의 주요 병목(bottleneck)이며, I/O 성능을 모니터링하는 마커가 제공되어야 한다. 이 마커를 통해 사용자는 I/O 페이지 액세스 시간을 측정하고, 이 측정에 기반하여 다양하고 복잡한 통계를 집계할 수 있다. .. function:: pgbuf_hit() 이 마커는 페이지 버퍼에서 요청 페이지가 발견되어 디스크에서 그것을 검색할 필요가 없을 때 발동된다. .. function:: pgbuf_miss() 이 마커는 페이지 버퍼에서 요청 페이지가 발견되지 않아 디스크에서 그것을 검색해야 할 때 발동된다. .. function:: io_write_start (query_id) 이 마커는 디스크에 페이지를 기록하는 프로세스가 시작할 때 발동된다. :param query_id: 질의 식별자 .. function:: io_write_end(query_id, size, status) 이 마커는 디스크에 페이지를 기록하는 프로세스가 종료될 때 발동된다. :param query_id: 질의 식별자 :param size: 기록되는 바이트 수 :param status: 연산이 성공적으로 종료되었는지 여부를 나타내는 값 .. function:: io_read_start(query_id) 이 마커는 디스크에서 페이지를 읽는 작업이 시작될 때 발동된다. :param query_id: 질의 식별자 .. function:: io_read_end (query_id, size, status) 이 마커는 디스크에서 페이지를 읽는 작업이 종료될 때 발동된다. :param query_id: 질의 식별자 :param size: 읽은 바이트 수 :param status: 연산이 성공적으로 종료되었는지 여부를 나타내는 값 기타 마커 --------- .. function:: sort_start () 이 마커는 정렬 연산이 시작될 때 발동된다. .. function:: sort_end (nr_rows, status) 이 마커는 정렬 연산이 완료될 때 발동된다. :param nr_rows: 정렬되는 행의 개수 :param status: 연산이 성공적으로 종료되었는지 여부