Golang 을 사용하여 NGINX Plus 모니터링 통계 수집
Go, 또는 Golang 으로도 알려진 Go 언어는 Google에서 개발한 오픈 소스 프로그래밍 언어로, 간단하고 신뢰할 수 있으며 효율적인 소프트웨어를 쉽게 구축할 수 있도록 도와줍니다. Go에 대해 더 알고 싶다면 “How to Write Go Code“와 “Go by Example“을 확인해보세요. Go 사이트에는 다양한 패키지에 대한 상세한 문서도 있습니다.
해당 포스트의 목표는 NGINX Plus 실시간 활동 모니터링 API 메트릭을 수집하는 데 사용할 수 있는 몇 가지 기본 메서드와 Go 패키지를 보여주는 것입니다.
$ go version
go version go1.4.2 linux/amd64
$ sudo /usr/sbin/nginx -V
nginx version: nginx/1.9.4 (nginx-plus-r7)
목차
1. 개요
2. Golang 패키지 가져오기
3. JSON 데이터 구조 정의
4. Golang NginxStatus 및 SendStatsD 함수 정의
5. main 함수 기능 정의
6. Golang 스크립트
7. 요약
1. 개요
현대에 있어서 확장 가능하고 신뢰할 수 있는 인프라를 갖는 것은 사이트의 성공에 매우 중요합니다. NGINX 성능 모니터링과 로드 밸런싱된 애플리케이션의 상태를 모니터링하는 것은 매우 중요합니다. 가상 서버가 받는 트래픽 양을 알고 있다면 필요할 때 확장할 수 있으며, 오류율을 주시하면 애플리케이션을 효과적으로 처리할 수 있습니다.
이러한 메트릭을 모니터링하고 이에 대응하는 것은 사용자에게 신뢰할 수 있고 만족스러운 경험을 제공하는 데 도움이 됩니다.
NGINX Plus의 실시간 활동 모니터링 기능을 사용하면 핵심 로드 및 성능 메트릭을 실시간으로 쉽게 얻을 수 있습니다. NGINX Plus를 통해 흐르는 트래픽에 대한 유용한 데이터는 내장된 대시보드와 HTTP 기반 API를 통해 쉽게 분석 가능한 JSON 형식으로 제공됩니다.
Live Activity 모니터링 API에서 제공하는 데이터를 활용하는 효과적인 방법은 다양합니다.
예를 들어, 특정 가상 서버의 상위 트래픽을 모니터링하고 NGINX Plus 동적 재구성 API를 사용하여 Docker 컨테이너를 자동으로 확장할 수 있습니다.
메트릭을 직접 표준 출력으로 덤프하고 로그 파일에 기록하여 ELK 스택이나 Splunk 클러스터로 메트릭을 전송할 수도 있습니다.
또는 API 데이터를 statsd와 collectd와 같은 데이터 집계기로 수집하고 전송하여 그래프 작성이나 로깅 등 다른 목적으로 사용할 수도 있습니다.
Golang 커뮤니티 멤버들이 작성한 많은 패키지들이 원하는 기능을 제공할 수 있습니다. 다른 예로, 이번 포스트에서는 go-statsd-client라는 타사 패키지를 사용하여 일부 통계를 직접 StatsD로 전송했습니다.
StatsD는 Node.js 플랫폼에서 실행되는 네트워크 데몬으로, UDP 또는 TCP를 통해 보내진 카운터 및 타이머와 같은 통계를 수신하고 하나 이상의 플러그 가능한 백엔드 서비스로 집계를 전송합니다.
2. Golang 패키지 가져오기
Golang 스크립트에서 첫 번째로 정의하는 것은 패키지 이름과 실행 또는 빌드 시에 가져올 패키지입니다.
package main
import (
"encoding/json"
"errors"
"fmt"
"github.com/cactus/go-statsd-client/statsd"
"io/ioutil"
"log"
"net/http"
"time"
)
샘플 스크립트에서는 Golang 표준 라이브러리에서 제공하는 몇 가지 패키지를 사용합니다. 다음은 해당 패키지들과 간단한 설명입니다.
- encoding/json: JSON 객체의 인코딩 및 디코딩을 위해 사용됩니다.
- errors: 오류 메시지를 조작하기 위해 사용됩니다.
- fmt: 입출력 형식을 지정하기 위한 함수들로, 데이터를 터미널에 출력하는 데 사용됩니다.
- io/ioutil: I/O 유틸리티 함수를 구현하기 위해 사용됩니다.
- log: 로깅 및 오류 출력을 위해 사용됩니다.
- net/http: API 엔드포인트에 대한 HTTP 클라이언트 연결을 생성하기 위해 사용됩니다.
- time: 스크립트에서 대기 메커니즘을 생성하기 위해 사용됩니다.
3. JSON 데이터 구조 정의
Golang 에서는 JSON의 데이터 구조를 정의해야 합니다. Golang 은 데이터 구조에 정의되지 않은 JSON 데이터를 무시합니다. 이 예제에서는 NGINX Plus API에서 연결 통계만 가져오고 있습니다.
type NginxResponse struct {
Connections struct {
Accepted int64 `json:"accepted"`
Active int64 `json:"active"`
Dropped int64 `json:"dropped"`
Idle int64 `json:"idle"`
} `json:"connections"`
}
만약 이 JSON 데이터 구조를 기반으로 하여 upstream 및 server zone 값을 추가하려고 결정한다면, NGINX Plus 인스턴스와 구성에 따라 일부 데이터 필드 이름이 고유할 것임을 염두에 두세요.
온라인에서는 JSON 덤프를 쉽게 Golang 구조체로 변환해주는 많은 도구들이 있지만, 구조체가 어떻게 정의되는지 이해하면 직접 만들기도 매우 쉽습니다.
4. Golang NginxStatus 및 SendStatsD 함수 정의
Golang 스크립트는 NginxStatus, SendStatsD 및 main 함수로 구성되어 있습니다. 이들을 순서대로 설명하겠습니다. NginxStatus 함수는 NGINX Plus Live Activity 모니터링 API에 요청을 보냅니다.
먼저 NGINX Plus 서버를 정의한 다음, 실시간 활동 모니터링 API에 GET 요청을 수행합니다.
응답의 상태 코드가 200 OK인지 확인하고, 그렇지 않은 경우 errors 패키지를 사용하여 문제를 로그에 기록합니다. 또한, 함수가 완료될 때까지 연결을 닫기 위해 defer를 사용하여 연결을 자동으로 닫습니다.
그런 다음 응답 본문을 변수에 읽어들이고, 정의한 구조체를 사용하여 JSON을 디코딩합니다.
데이터를 main 함수로 반환하고, 통계를 화면에 출력하고 SendStatsD 함수로 전달합니다.
func NginxStatus() (*NginxResponse, error) {
// assign variable for NGINX Plus server
var nginxStatusServer string = "my.nginx.server.com"
// perform a request to the NGINX Plus status API
resp, err := http.Get(fmt.Sprintf("http://%s/status", nginxStatusServer))
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New("Non 200 OK")
}
// clean up the connection
defer resp.Body.Close()
// read the body of the request into a variable
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// unmarshall the JSON data into a variable
var er NginxResponse
if err := json.Unmarshal(data, &er); err != nil {
return nil, err
}
return &er, nil
}
SendStatsD 함수에서는 StatsD로 직접 전송할 변수와 타입을 정의합니다. 함수의 시작 부분에서는 연결할 StatsD 서버와 포트, 클라이언트 이름을 정의합니다. 그런 다음 연결을 설정하고 예기치 않은 오류를 기록하며, 연결을 닫는 것을 지연시킵니다. StatsD에 대한 플러시 간격을 나타내는 변수와 메트릭 이름의 일부를 할당합니다. 플러시 간격은 StatsD가 데이터를 백엔드로 전송하기 전에 기다리는 시간을 나타냅니다. 마지막으로 SendStatsD 함수의 끝에서 내장된 Inc 함수를 사용하여 모든 데이터를 StatsD로 전송합니다.
func SendStatsD(gs string, gt string, gv int64) {
// assign variables for statsd server and metric name prefix
var statsdServer string = "127.0.0.1:8125"
var gk string = "nginx"
// connect to statsd
client, err := statsd.NewClient(statsdServer, gk)
if err != nil {
log.Println(err)
}
// clean up the connections
defer client.Close()
// assign variables for metric name and interval
var fi float32 = 1.0
var st string = "status"
var sn string = "my_nginx_server_com"
// send metrics to StatsD
client.Inc(st+"."+sn+"."+gs+"."+gt, gv, fi)
}
이는 StatsD데이터를 구성하는 방법을 알려주기 때문에 올바르게 구성하는 것이 매우 중요합니다. 메트릭 이름을 각 수준 사이의 구분 기호로 마침표가 있는 폴더 구조와 같다고 생각하세요.
지표 네임스페이스의 이름을 지정하는 방법에 따라 Graphite 웹 UI에서 데이터가 저장되고 사용 가능한 위치가 결정됩니다.
데이터를 저장하는 방법은 귀하에게 달려 있지만 측정항목 이름을 정의할 때 다음 명명 규칙을 사용하는 것이 좋습니다.
여기서는 이름 부분을 더 쉽게 볼 수 있도록 꺾쇠 괄호를 사용했습니다. 실제 이름에는 사용되지 않습니다.
<namespace>.<section-type>.<server-name>.<target noun>.<stat adjective or verb>
이 예에서는 my.nginx.server.comStatsD 이라는 서버에서 현재 활성화된 연결에 대해 NGINX Plus 상태 API의 데이터를 보내도록 지시합니다 . 이름 세그먼트 내의 마침표나 공백을 밑줄 문자로 바꿉니다.
nginx.status_api.my_nginx_server_com.connections.active
이 예제는 StatsD에게 my.nginx.server.com이라는 서버에서 현재 활성화된 연결에 대한 NGINX Plus 상태 API 데이터를 전송하도록 지시합니다. 이름의 각 세그먼트 내의 마침표(.)나 공백을 밑줄(_) 문자로 대체해야 함에 유의하세요.
5. main 함수 기능 정의
Golang main 함수에서는 무한 루프를 생성한 다음, 위에서 설명한 함수들을 호출하여 필요에 따라 데이터를 수신하고 전송합니다.
func main() {
for {
// query the NginxStatus function to get data
nr, err := NginxStatus()
if err != nil {
log.Println(err)
}
// print the statistics on screen
fmt.Println("Connections Accepted:", nr.Connections.Accepted)
fmt.Println("Connections Dropped:", nr.Connections.Dropped)
fmt.Println("Connections Active:", nr.Connections.Active)
fmt.Println("Connections Idle", nr.Connections.Idle)
// send metrics to the SendStatsD function
go SendStatsD("connections", "accepted", nr.Connections.Accepted)
go SendStatsD("connections", "dropped", nr.Connections.Dropped)
go SendStatsD("connections", "active", nr.Connections.Active)
go SendStatsD("connections", "idle", nr.Connections.Idle)
// sleep for one second
time.Sleep(time.Millisecond * 1000)
}
}
여기서는 Golang 의 NginxStatus 함수를 사용하여 NGINX Plus에 대한 API 호출 결과를 변수에 할당합니다. 그런 다음 fmt 패키지를 사용하여 일부 연결 통계를 화면에 출력하고 SendStatsD 함수를 사용하여 해당 데이터를 Graphite에 전달합니다.
또한, 각 요청 사이에 1초의 지연을 삽입하기 위해 sleep 함수를 실행합니다. 이 블로그에서는 연결 또는 시간 관리에 대한 자세한 내용을 다루지 않습니다. 스크립트를 작성할 때 연결 시간 초과 또는 지연 시간을 처리하는 방법과 각 요청 사이의 시간을 고려하는 방법을 결정해야 합니다.
다음은 스크립트를 실행한 후의 화면 출력 예시입니다. StatsD로 전송된 데이터는 투명하게 표시되며 Graphite 웹 UI를 확인하여 확인할 수 있습니다.
$ go run main.go
Connections Accepted: 36480962
Connections Dropped: 0
Connections Active: 13
Connections Idle 30
6. Golang 스크립트
참고용으로 스크립트의 전체 내용을 제공합니다. Golang 에서는 공백이 중요하므로 오류가 발생하는 경우 구문을 확인해야 합니다.
package main
import (
"encoding/json"
"errors"
"fmt"
"github.com/cactus/go-statsd-client/statsd"
"io/ioutil"
"log"
"net/http"
"time"
)
type NginxResponse struct {
Connections struct {
Accepted int64 `json:"accepted"`
Active int64 `json:"active"`
Dropped int64 `json:"dropped"`
Idle int64 `json:"idle"`
} `json:"connections"`
}
func NginxStatus() (*NginxResponse, error) {
// assign variable for NGINX Plus server
var nginxStatusServer string = "my.nginx.server.com"
// perform a request to the NGINX Plus status API
resp, err := http.Get(fmt.Sprintf("http://%s/status", nginxStatusServer))
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New("Non 200 OK")
}
// clean up the connection
defer resp.Body.Close()
// read the body of the request into a variable
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// unmarshall the JSON data into a variable
var er NginxResponse
if err := json.Unmarshal(data, &er); err != nil {
return nil, err
}
return &er, nil
}
func SendStatsD(gs string, gt string, gv int64) {
// assign variables for statsd server and metric name prefix
var statsdServer string = "127.0.0.1:8125"
var gk string = "nginx"
// connect to statsd
client, err := statsd.NewClient(statsdServer, gk)
if err != nil {
log.Println(err)
}
// clean up the connections
defer client.Close()
// assign variables for metric name and interval
var fi float32 = 1.0
var st string = "status"
var sn string = "my_nginx_server_com"
// send metrics to statsd
client.Inc(st+"."+sn+"."+gs+"."+gt, gv, fi)
}
func main() {
for {
// query the NginxStatus function to get data
nr, err := NginxStatus()
if err != nil {
log.Println(err)
}
// print the statistics on screen
fmt.Println("Connections Accepted:", nr.Connections.Accepted)
fmt.Println("Connections Dropped:", nr.Connections.Dropped)
fmt.Println("Connections Active:", nr.Connections.Active)
fmt.Println("Connections Idle", nr.Connections.Idle)
// send metrics to the SendStatsD function
go SendStatsD("connections", "accepted", nr.Connections.Accepted)
go SendStatsD("connections", "dropped", nr.Connections.Dropped)
go SendStatsD("connections", "active", nr.Connections.Active)
go SendStatsD("connections", "idle", nr.Connections.Idle)
// sleep for one second
time.Sleep(time.Millisecond * 1000)
}
}
7. 요약
Golang 을 사용하여 NGINX Plus의 실시간 활동 모니터링 API에 액세스하면 NGINX Plus에서 이미 사용 가능한 데이터에 대해 추가적인 유연성을 제공할 수 있습니다. NGINX Plus에서 가져온 통계 데이터는 더 나은 로깅을 제공하고, 실시간 활동 모니터링을 자동화하며, NGINX Plus의 성능 기록을 기반으로 그래프나 차트를 생성하는 데 도움이 될 수 있습니다. NGINX Plus를 사용해보려면 무료 30일 체험판을 시작하거나 사용 사례에 대해 문의하세요.
아래 뉴스레터를 구독하고 NGINX와 NGINX STORE의 최신 정보들을 빠르게 전달 받아보세요.