애플리케이션 자체만 모니터링하는 것으로는 시스템 전체를 파악하기에 부족한 경우가 많습니다. 위성 앱(또는 보조 앱)에서 실행되는 서비스가 일상 운영에 큰 영향을 미치는 일이 빈번하기 때문입니다. 데이터베이스 서버가 대표적인 예이며, 백업 스크립트나 기타 백그라운드 작업 역시 시스템 성능을 저하시킬 수 있음에도 종종 간과되곤 합니다.
Node.js용 AppSignal APM, Ruby APM, Elixir APM은 앱 자체를 자동으로 계측하지만, 기본적으로 이러한 위성 프로세스까지는 감시하지 않습니다. 모니터링 범위를 전체 시스템으로 확장하고 모든 데이터를 하나의 앱에서 통합 관리하려면 AppSignal의 독립 실행형 에이전트(standalone agent)를 설치하면 됩니다.
AppSignal의 독립 실행형 에이전트
독립 실행형 에이전트는 Ruby, Elixir, JavaScript 애플리케이션을 계측할 때 사용하는 것과 동일한 소프트웨어를 기반으로 하며, 독립 실행 모드로도 구동할 수 있습니다.
독립 실행형 에이전트는 다음과 같은 대상을 모니터링하는 데 활용할 수 있습니다.
- 인프라: 시스템의 일부이지만 애플리케이션 코드를 실행하지 않는 머신
- 백그라운드 작업: 리소스를 많이 사용하는 cron 작업이나 장기 실행 데이터 처리 스크립트 등. 해당 작업이 지원 언어(Ruby, Elixir, Node.js)로 작성된 경우 표준 통합을 사용할 수 있습니다.
- 추가 언어: 기본적으로 지원되지 않는 언어로 작성된 프로그램
예를 들어 독립 실행형 에이전트를 활용하면 Python으로 작성된 머신 러닝 모델을 추적하고, 백업 스크립트를 계측하고, Kafka 브로커를 모니터링하거나, 웹 팜의 호스트 메트릭을 수집할 수 있습니다. 이렇게 수집한 정보는 AppSignal에서 주요 애플리케이션의 기존 메트릭과 함께 확인할 수 있어 시스템 전체를 한눈에 파악하는 데 큰 도움이 됩니다.
작동 방식
에이전트는 deb 또는 rpm 패키지 형태로 배포되며 언어 종속성이 없습니다. Debian/Ubuntu 계열 또는 Red Hat 기반 시스템이라면 어디서든 실행할 수 있습니다. 자세한 설치 절차는 에이전트 공식 문서를 참고하세요.
설치 후 몇 분 안에 설정을 마칠 수 있으며, 에이전트는 데몬으로 상시 실행되면서 조용히 인프라를 감시합니다. 특히 에이전트에는 StatsD 서버가 내장되어 있어, 로깅하는 커스텀 데이터를 AppSignal 대시보드로 전달할 수 있습니다.
StatsD란 무엇인가?
StatsD는 임의의 데이터를 수집하고 집계하기 위한 표준 프로토콜로, 메트릭 및 성능 정보 기록에 특화되어 있습니다. UDP 연결 위에서 동작하는 경량 텍스트 프로토콜을 사용하기 때문에 시스템에 거의 부담을 주지 않습니다.
StatsD 메시지는 다음과 같은 형식을 따릅니다.
KEY:VALUE|TYPEKEY는 임의의 문자열, VALUE는 숫자이며, 유형(TYPE) 값에 따라 숫자가 처리되는 방식이 결정됩니다.
지원되는 메트릭 유형은 세 가지입니다.
- c: 호출될 때마다 값이 증가하는 카운터(counter)입니다. 예를 들어
active_users:1|c는active_users카운터에 1을 더합니다. - g: 숫자 값을 받아 갱신될 때까지 유지하는 게이지(gauge)입니다. 처리량, 활성 사용자 수, 대기열의 작업 수처럼 시간에 따라 오르내리는 값을 기록하는 데 적합합니다.
- t: 타이밍(timing) 값을 저장합니다. 지속 시간 추적에 이상적이며, AppSignal은 기록된 모든 타이밍에 대해 평균, 횟수, 백분위수를 자동으로 계산합니다.
지원되지 않는 다른 메트릭 유형은 자동으로 무시됩니다.
StatsD로 데이터 전송하기
독립 실행형 에이전트는 포트 8125에서 UDP 패킷을 수신 대기합니다. netcat을 사용하면 명령줄에서 바로 StatsD 형식의 문자열을 전송할 수 있습니다.
echo -n "myscript.myevent.counter:1|c" | nc -4u -w0 localhost 8125UDP를 사용하므로 응답을 기다릴 필요가 없습니다. Socat으로도 동일하게 전송할 수 있습니다.
echo -n "myscript.myevent.counter:1|c" | socat - udp:localhost:8125이러한 방식 덕분에 배치 작업이나 cron 작업도 손쉽게 계측할 수 있습니다. 예를 들어 다음 명령은 게이지를 사용해 백업 작업이 생성한 데이터 용량을 기록합니다.
backup_size=$(du -m /backups | cut -f1)
echo -n "backup.data:$backup_size|g" | nc -4u -w0 localhost 8125정수뿐 아니라 부동 소수점 숫자도 지원합니다.
echo -n "network.latency:0.2|g" | nc -4u -w0 localhost 8125태그(Tag) 활용하기
메트릭에 태그를 추가할 수도 있습니다. StatsD 서버는 메시지 끝에 선택적 태그를 지원합니다.
KEY:VALUE|TYPE|#TAGS하나의 메시지에 여러 태그를 적용할 수 있으며, 태그에 값을 할당해 나중에 필터링하는 용도로 활용할 수 있습니다.
echo -n "backup.data:$backup_size|g|#backups,env:production" | nc -4u -w0 localhost 8125AppSignal에서 이 데이터를 확인하는 방법은 뒤에서 자세히 살펴보겠습니다.
다양한 언어에서 계측하기
StatsD 서버는 UDP 패킷을 전송할 수 있는 모든 언어와 호환됩니다. 몇 가지 실제 예제를 살펴보겠습니다.
Python은 데이터 마이닝과 머신 러닝 분야에서 널리 쓰이는 언어입니다. 내장 socket 라이브러리를 사용하면 별도 의존성 없이 계측 코드를 추가할 수 있습니다.
import time
# 함수 실행 시간 측정
start = time.process_time()
train_my_model()
training_time = time.process_time() - start
# statsd로 값 전송
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 8125
MESSAGE = b"model.training.time:" + bytes(str(training_time), 'utf-8') + b"|t"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))Java에서는 java.net 라이브러리로 비슷한 결과를 얻을 수 있습니다.
byte[] buffer = "mybatch.exception.counter:1|c".getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
DatagramPacket packet = new DatagramPacket(
buffer, buffer.length, address, 8125
);
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.send(packet);PHP 역시 널리 사용되는 언어로, socket_sendto 함수를 통해 UDP 패킷을 전송할 수 있습니다.
$msg = "mywebsite.active_users:$ACTIVE_USERS|g";
$len = strlen($msg);
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_sendto($sock, $msg, $len, 0, '127.0.0.1', 8125);
socket_close($sock);StatsD 클라이언트
지금까지는 각 언어에 내장된 네트워킹 기능을 활용했습니다. 하지만 선택지는 더 많습니다. 대부분의 언어와 제품에는 서드파티 StatsD 클라이언트나 애드온이 존재합니다. StatsD 규격을 준수하는 클라이언트라면 최소한 지원되는 데이터 유형에 한해서는 정상적으로 작동합니다. 클라이언트 목록은 StatsD 프로젝트 위키에서 확인할 수 있습니다.
AppSignal에서 호스트 데이터 확인하기
Host Metrics 대시보드에서는 머신의 리소스 사용률을 확인할 수 있습니다.
AppSignal은 독립 실행형 에이전트가 실행 중인 모든 머신에 대해 개별 항목을 자동으로 추가합니다.
대시보드에는 부하(load)와 CPU 평균값, 디스크·네트워크·메모리·스왑 사용량이 표시됩니다.
커스텀 대시보드 만들기
AppSignal은 전송된 StatsD 값에 대한 대시보드를 자동으로 생성하지 않으므로, 직접 커스텀 대시보드를 만들어야 합니다.
먼저 대시보드 메뉴에서 Add dashboard(대시보드 추가)를 클릭합니다.
대시보드 이름을 입력한 뒤, Add graph(그래프 추가) 버튼을 누르면 그래프 빌더가 열립니다.
그래프 이름을 지정하고 Add metric(메트릭 추가)을 클릭한 후, 메뉴에서 원하는 메트릭을 선택합니다.
필요하다면 태그를 활용해 데이터를 필터링할 수도 있습니다.
이후 Back to overview(개요로 돌아가기)를 클릭합니다. 표현하려는 데이터에 가장 적합한 그래프 유형과 값 단위를 찾기 위해 여러 옵션을 시도해 보는 것이 좋습니다.
타이밍 데이터는 평균과 백분위수가 더 선명하게 드러나는 영역(area) 그래프가 잘 어울립니다. 반면 카운터와 게이지는 꺾은선(line) 그래프로 시각화하는 것이 효과적입니다.
결과에 만족했다면 Create graph(그래프 만들기)를 클릭해 완료합니다.
참고로 Node.js용 APM으로 AppSignal을 설정했거나 Ruby(Rails) APM, Elixir APM을 사용 중이라면, 자동으로 계측되거나 측정되는 다른 메트릭에 대해서도 동일한 방식으로 대시보드를 추가할 수 있습니다.
마무리
이번 글에서는 AppSignal의 독립 실행형 에이전트를 활용해 머신과 위성 코드를 감시하는 방법을 살펴보았습니다. 내장된 StatsD 서버를 활용하면 임의의 성능 데이터를 자유롭게 기록하고 어떤 프로세스든 계측할 수 있습니다.
독립 실행형 에이전트에 대해 더 자세히 알아보려면 다음 자료를 참고하세요.
- StatsD 레퍼런스 문서
- 커스텀 메트릭 전송 방법
- AppSignal에서 대시보드 만들기
- 독립 실행형 에이전트로 Kafka 문제 식별 및 해결하기