New Relic Now+ New Relic’s most transformative platform update yet with 20+ product launches.
Watch the event on-demand now.

Go 애플리케이션은 소규모 서비스부터 대규모 분산 시스템까지 모든 것을 지원합니다. 복잡성이 이러한 수준인 경우 성능 메트릭에 대한 가시성이 반드시 필요합니다. 요청 지연 시간, 처리량 및 오류율 같은 주요 메트릭은 애플리케이션에 대한 명확한 그림을 제공하여, 문제를 더 빠르게 감지 및 해결하고 규모에 맞게 성능을 최적화하며 원활한 사용자 경험을 유지하는 데 도움이 됩니다. 하지만 Go 애플리케이션에 계측을 추가하는 작업은 코드 전반에서 수동 작업으로 이뤄지기 때문에 복잡하고 시간이 많이 걸리는 경우가 많습니다. 개발자가 익숙해지는 데 시간이 걸리고 계측 프로세스에 간극이 생길 위험도 큽니다.

뉴렐릭의 Go easy instrumentation을 사용하면, 각 프레임과 세그먼트별로 수동으로 구성할 필요 없이 Go 애플리케이션에서 간단하게 인사이트를 확보할 수 있습니다. 이 블로그 게시물에서는 독립형 Hello, World! 앱을 사용하는 기본 서비스부터 gRPC를 사용하는 고급 분산 시스템까지, Go 앱을 쉽게 계측하는 데 도움이 되는 네 가지 실용적인 예를 소개합니다. Go easy instrumentation을 활용하면 개발을 간소화하는 동시에 많은 시간을 들이지 않고 애플리케이션을 수월하게 계측해 포괄적으로 모니터링할 수 있습니다.

샘플 시나리오: 점진적 모니터링 사용 사례

4가지 샘플 구성을 통해 Go easy instrumentation가 Go SDK용 뉴렐릭에 얼마나 밀접하게 통합되어 효율적이고 간편한 모델링을 가능하게 하는지를 살펴보겠습니다.

예시에서는 점차 복잡성을 더해가며, 애플리케이션이 커짐에 따라 모니터링 노력을 어떻게 확장하는지 보여줍니다. 다음의 샘플 애플리케이션과 시나리오에 초점을 맞춥니다: 

  1. Greetings: 간단한 Hello,World! 기본 개념을 효과적으로 보여주기 위해 앱이 강화되었습니다. 여기에서는 Go easy instrumentation을 사용한 계측의 기본 사항을 중점적으로 설명합니다.
  2. REST API:  net/http 패키지가 있는 매우 간단한 단일 엔드포인트 HTTP API. 여기에서는 HTTP 핸들러에 계측을 추가하는 데 중점을 둡니다.
  3. REST API with Gin Gin 라이브러리를 사용하는 멀티-엔드포인트 HTTP. 여기에서는 세그먼트화된 트랜잭션과 개별 엔드포인트에 대한 세부 모니터링에 중점을 둡니다.
  4. gRPC with client and server 클라이언트와 서버 애플리케이션 간의 트랜잭션을 캡처하고 Goroutine을 사용하여 병렬 작업을 수행하는 분산 시스템의 사례를 살펴봅니다.

각 샘플은 구체적인 사용 사례와 Go easy instrumentation의 이점을 보여주며, 간단한 애플리케이션에서 복잡한 분산 시스템까지 확장하는 방식을 강조합니다.

다음은 Go 애플리케이션 계측을 위한 명령을 실행한 후 예상할 수 있는 출력을 간략하게 보여 줍니다.

Go Easy instrumentation 


Greetings: A simple Go app

이 예시에서는 간단한 Hello, World! 애플리케이션을 통해 기본 계측에 대해 소개합니다. Go 애플리케이션을 위한 뉴렐릭 계측 툴을 처음 사용하는 모든 사람에게 이상적인 시작점입니다.

이 시나리오에서는 간단한 애플리케이션을 사용합니다. 이 블로그 게시물에 사용된 샘플 앱의 소스 코드는 여기에서 확인할 수 있습니다.

이러한 샘플 애플리케이션은 샘플 애플리케이션의 루트 디렉터리에서 Go easy instrumentation 프로그램을 실행하도록 구성되어 있습니다.

애플리케이션의 계측된 버전을 생성하려면 샘플 애플리케이션의 루트에서 다음 명령을 실행합니다.

go-easy-instrumentation instrument 1.hello-world -o 1.hello-world/greetings.diff 

Go easy instrumentation 프로그램의 명령어와 파라미터를 자세히 살펴보겠습니다:

  • instrument:
  • <path>: Go easy instrumentation 프로그램이 실행될 애플리케이션 경로를 예상합니다.
  • –output: 이 파라미터는 원하는 위치와 파일 이름으로 지정된 애플리케이션을 위한 .diff 출력 파일을 만들 수 있도록 해줍니다. 위치나 이름이 지정되지 않으면 프로그램은 애플리케이션의 루트에 new-relic-instrumentation.diff라는 이름으로 파일을 생성합니다.
  • –debug: 이 파라미터는 잠재적인 계측 문제에 대한 경고를 출력하고 코드와 콘솔에 인라인 주석으로 표시합니다. 디버그 출력이나 인라인 주석이 나타나지 않으면 앱에 식별된 문제가 없음을 의미합니다.
  • completion: 특정 셸(Bash, Fish, Zsh 또는 PowerShell)에 대한 Go easy instrumentation을 위한 자동 완성 스크립트를 생성합니다.

명령을 실행한 후, 프로그램은 제공된 이름으로 특정 애플리케이션의 디렉터리에 출력 파일을 생성합니다(-–output 파라미터가 사용된 경우). 이 .diff 파일을 사용하면 Go 애플리케이션에서 변경된 사항을 검토할 수 있습니다.

.diff 파일에는 다음이 포함되어 있습니다:

greetings 앱을 위해 생성된 diff

Go easy instrumentation 프로그램은 뉴렐릭 Go 에이전트를 자동으로 가져오고 프로그램의 모든 기능을 트랜잭션 및 세그먼트로 적절하게 장식합니다. 이렇게 하면 개별 기능을 수동으로 장식하는 번거로운 작업이 제거됩니다.

아래 명령을 앱 디렉터리에서 실행하면 이러한 변경 사항을 적용할 수 있습니다.

git apply greetings.diff

이제 애플리케이션은 추가 변경을 하지 않아도 뉴렐릭에 데이터를 보고하기 시작합니다.

Instrumented 앱에서의 트랜잭션

REST API: Simple API with net/http package

기본 사항을 확장하여, 이 샘플은 모니터링을 단일 엔드포인트 HTTP API에 통합하는 방법을 보여줍니다.

이 예시에서는 표준 net/http 패키지로 생성된 매우 간단한 HTTP API를 사용하겠습니다. 이 애플리케이션은 단일 목적, 즉 localhost:8080에서 GET 요청을 처리하는 것을 지원합니다.

Go easy instrumentation 실행 전의 애플리케이션:

package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, World!")
}

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("Server is running on http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

다음으로 Go easy instrumentation을 실행하여 뉴렐릭 계측을 애플리케이션에 추가합니다. Go easy instrumentation의 동일한 루트 디렉터리에서 명령을 실행해야 합니다:

go-easy-instrumentation instrument 2.rest-api --output 2.rest-api/rest-api.diff

그러면 rest-api.diff 라는 이름의 출력 .diff 파일이 rest-API 디렉터리에 생겨납니다. 장식된 앱은 다음과 같은 모습이 됩니다.

REST API를 위해 생성된 계측

Go easy instrumentation은 HandleFunc()를 뉴렐릭의 WrapHandleFunc()로 간단히 래핑하여 모든 수신 요청에 대한 모든 요청과 응답 시간을 캡처합니다. 이렇게 하면 SDK 래퍼를 사용하여 핸들러를 리팩토링하는 번거로운 작업을 제거할 수 있습니다.

적용 과정은 간단합니다. git apply 명령을 실행하기만 하면 됩니다.

git apply rest-api.diff

REST API 앱의 트레이스

이 예에서는 경량 HTTP 서비스를 구축하는 개발자가 표준 'net/http' 패키지를 사용하여 REST API 애플리케이션을 위한 계측을 신속하게 설정하여 요청-응답 텔레메트리를 캡처하는 방법을 보여줍니다.

REST API with Gin: Gin 패키지를 사용한 다수의 엔드포인트

이 샘플에서는 한 가지를 변경해 이전 HTTP API 애플리케이션을 다음 단계로 끌어올려 보겠습니다. 즉, Gin 라이브러리를 사용하여 REST API를 빌드하는 것입니다. GET, POST, PUT, DELETE와 같은 다양한 HTTP 메서드를 처리하기 위해 여러 엔드포인트를 추가하고 로깅을 위한 미들웨어와 같은 고급 기능을 통합합니다.

앱 구조는 아래와 같습니다. 전체 애플리케이션 소스 코드는 여기에서 확인할 수 있습니다.

func main() {
	// Create a new Gin router
	router := gin.Default()

	// Logging middleware
	router.Use(loggingMiddleware)

	// Define routes
	router.GET("/items", getItems)
	router.POST("/items", addItem)
	router.GET("/items/:id", getItemByID)
	router.PUT("/items/:id", updateItemByID)
	router.DELETE("/items/:id", deleteItemByID)

	// Start the server
	log.Println("Server is running on http://localhost:8080")
	router.Run(":8080")
}


// getItems handles GET /items and returns the list of items
func getItems(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, items)
	log.Println("Returned all items")
}

// addItem handles POST /items and adds a new item
func addItem(ctx *gin.Context) {
...
...
}

// getItemByID handles GET /items/:id and returns a single item by ID
func getItemByID(ctx *gin.Context) {
...
...
}

// updateItemByID handles PUT /items/:id to update an existing item by ID
func updateItemByID(ctx *gin.Context) {
...
...
}

// deleteItemByID handles DELETE /items/:id to delete an item by ID
func deleteItemByID(ctx *gin.Context) {
...
...
}

이렇게 설정된 애플리케이션에서는 보통 각 엔드포인트마다 메트릭을 캡처하고 각 요청-응답 주기의 복잡한 연산을 세부적으로 나누기 위해 트랜잭션과 세그먼트에 집중합니다.

이처럼 복잡한 애플리케이션에서, 간극을 남기지 않고 적절한 계측을 적절한 위치에 포함하도록 리팩토링하는 것은 어려운 작업입니다. 이 작업은 팀이나 개발자의 여러 스프린트에 걸쳐 이루어질 수 있는데, 이는 이상적이지 않습니다.

아래 명령을 실행하고 Go easy instrumentation으로 코드를 장식하면 수동 계측 작업에 소요되는 시간을 크게 절약할 수 있습니다.

go-easy-instrumentation instrument 3.gin -o 3.gin/gin-rest.diff

Go easy를 사용해 계측된 Gin 앱

Go Easy로 Gin 앱을 계측

뉴렐릭의 Go easy instrumentation은 여러 엔드포인트나 세부적인 성능 모니터링이 필요한 서비스는 물론 Gin 프레임워크를 사용하여 구축된 애플리케이션의 경우에도 복잡한 계측 시나리오를 간소화해줍니다.

gRPC: Client and server with Goroutines

Golang을 사용한 분산 애플리케이션은 서비스 간 통신을 보통 gRPC에 의존합니다. 이 예시는 gRPC 클라이언트-서버 아키텍처를 모니터링하는 방법을 보여줍니다. 여기에는 단일 요청-응답, 서버 스트리밍 RPC 호출, 클라이언트 스트리밍 RPC 호출, 양방향 스트리밍 RPC 호출과 같은 gRPC의 일반적인 패턴이 포함됩니다.

전체 애플리케이션 소스 코드는 여기에서 확인할 수 있습니다.

func doClientCalls(ctx context.Context, client sampleapp.SampleApplicationClient) {

	// doUnaryUnary performs a unary RPC call where both the client request and server response
	// are single messages. This is similar to a traditional HTTP request/response pattern.
	doUnaryUnary(ctx, client)

	// doUnaryStream performs a server-streaming RPC call where the client sends a single request
	// and receives a stream of responses from the server.
	doUnaryStream(ctx, client)

	// doStreamUnary performs a client-streaming RPC call where the client sends multiple messages
	// to the server and receives a single response.
	doStreamUnary(ctx, client)

	// doStreamStream performs a bidirectional streaming RPC call where both the client and server
	// can send multiple messages in any order.
	doStreamStream(ctx, client)
}

클라이언트-서버 트랜잭션을 위한 메트릭을 캡처하고 레이턴시 및 처리량에 대한 Goroutine 기반 병렬 연산을 모니터링하면 분산된 애플리케이션에서 포괄적인 가시성을 확보하는 데 도움이 됩니다. 이를 통해 비동기 연산 전반에서도 요청을 종단 간 추적하고 분산 시스템에 대한 가시성을 확보할 수 있습니다.

이를 위해서는 클라이언트 및 서버 애플리케이션에 대해 별도로 Go easy instrumentation을 실행해야 합니다.

Client

go-easy-instrumentation instrument 4.gRpc/client --output 4.gRpc/client/grpc-client.diff

Server

go-easy-instrumentation instrument 4.gRpc/server --output 4.gRpc/server/grpc-server.diff

계측된 gRPC 클라이언트 및 서버 앱

멀티-엔드포인트 REST 애플리케이션과 유사하게, Go easy instrumentation은 트랜잭션 및 세그먼트로 모든 메소드를 장식합니다. 또한, Goroutine의 사용을 식별하여 Goroutine 작업을 캡처하고 필요한 경우 적절한 오류 처리를 위한 적절한 계측 기능을 추가합니다. 

뉴렐릭의 gRPC 클라이언트 계측

뉴렐릭의 gRPC 서버 계측

뉴렐릭 easy instrumentation가 Go를 간소화하는 방법

뉴렐릭의 Go easy instrumentation은 Golang 애플리케이션 계측을 위해 간단하고 원활한 경험을 제공합니다. 각 시나리오에서 어떻게 도움이 되는지 살펴봅니다.

  1. 간단한 플러그 앤 플레이 방식 설정: 새로운 사용자도 최소한의 구성으로 빠르게 통합할 수 있습니다.
  2. 포괄적인 메트릭: 트랜잭션 시간, 세그먼트, Goroutine 및 오류율 등 모든 항목을 추적하여 완전한 가시성을 제공합니다.
  3. 확장성: 기본 앱에서 분산 앱까지 손쉽게 확장 가능합니다.
  4. 사용자 정의: .diff 파일 옵션을 사용하여 현재 애플리케이션 상태를 유지하며 계측을 수정할 수 있습니다.

결론

오늘날 개발자가 직면하고 있는 복잡성과 확장성 문제를 감안하면, Go 애플리케이션을 위한 계측은 더 이상 수동적이고 어려운 작업이 되어서는 안됩니다. 이러한 도전과제를 해결하기 위해, 뉴렐릭의 Go easy instrumentation은 프로세스를 효율적이고 간소화된 경험으로 전환하고, 계측에 필요한 수동 작업을 크게 줄여 줍니다. 뉴렐릭의 Go easy instrumentation을 사용하면 모니터링이 수월해집니다. 계측의 간극을 줄이고 누구나 쉽게 프로세스를 구현할 수 있습니다. 이 블로그 게시물에서 설명한 4가지 샘플은 다양한 복잡성 수준의 애플리케이션을 모니터링하기 위한 로드맵을 제공하며, 이를 통해 실제 환경의 도전과제에 대비할 수 있습니다.

이 샘플을 살펴보고 Go easy instrumentation을 애플리케이션에 통합하여 선제적 모니터링의 편리함을 경험해 보시기 바랍니다. 성능 인사이트를 손쉽게 확보하면 가장 중요한 일, 즉 훌륭한 소프트웨어를 만드는 데만 집중할 수 있습니다.

이 라이브러리는 데이터 저장소 등 여러 다른 기능에 대한 지원을 포함하도록 정기적으로 업데이트되고 있습니다. 아직 프리뷰 상태이기는 하지만 운영 애플리케이션에 맞게 계측을 확장하는 데 도움이 될 수 있습니다.