중요
Node.js 에이전트 14.0.0부터 Apollo Server 고객은 더 이상 @newrelic/apollo-server-plugin을(를) 설치하고 사용할 필요가 없습니다. 계측은 모든 Apollo Server 인스턴스에 자동으로 적용됩니다.
자세한 내용은 Apollo Server 마이그레이션 가이드 를 참조하세요.
New Relic Apollo Server 플러그인은 Apollo Server 애플리케이션을 계측하여 GraphQL 페이로드에 대한 가시성을 제공합니다. 이렇게 하면 느린 GraphQL 쿼리 의 원인을 찾아 진단하는 데 도움이 됩니다. 지원되는 Apollo 서버 버전은 2.14 이상입니다.
플러그인은 쿼리의 전체 타이밍을 기록하고 분산 추적 을 사용하여 경로 문제를 찾아냅니다. 이 계측을 사용하여 문제가 요청된 데이터의 일부를 처리하는 데서 발생하는지, 아니면 다른 서비스나 데이터베이스에서 수행된 작업에서 발생하는지 확인하십시오.
호환성
New Relic 플러그인은 다음 Apollo 서버 모듈과 함께 작동합니다.
@apollo/server@apollo/gateway@apollo/subgraphapollo-server(>= 2.14)apollo-server-expressapollo-server-hapiapollo-server-koaapollo-server-fastifyapollo-server-lambda
다른 플러그인은 기본 구현에 따라 작동할 수 있지만 확인되지는 않았습니다.
메트릭
트랜잭션 내부 및 트랜잭션 간 GraphQL 작업의 동작을 이해할 수 있도록 두 가지 새로운 메트릭이 도입되었습니다. 이에 대한 자세한 내용은 아래에서 확인하거나 시각화 섹션으로 이동하여 이 데이터를 사용하는 권장 방법을 확인하세요.
메트릭 쿼리 및 차트 생성에 대한 자세한 내용은 리소스 섹션을 참조하십시오.
작업 메트릭
/GraphQL/operation/ApolloServer/[operation-type]/[operation-name]/[deepest-unique-path]
작업 메트릭에는 작업 유형, 작업 이름 및 가장 깊은 경로가 포함됩니다. 이 메트릭은 개별 쿼리 또는 뮤테이션의 소요 시간을 나타냅니다. 이를 사용하여 여러 쿼리가 포함될 수 있는 개별 트랜잭션의 컨텍스트 외부에서 성능을 비교하십시오.
작업 유형: 작업이 쿼리인지 뮤테이션인지 나타냅니다.
작업 이름: 제공된 경우 작업 이름 또는 <anonymous>입니다.
가장 깊은 고유 경로: 각 레벨에서 하나의 필드만 선택된 쿼리의 선택 세트에 포함된 가장 깊은 경로입니다. 작업 이름은 재사용될 수 있으므로, 이는 특정 작업의 고유성을 추가로 확인하는 데 도움이 됩니다. 자세한 내용은 트랜잭션 섹션의 설명을 참조하십시오.
필드 리졸브 메트릭
/GraphQL/resolve/ApolloServer/[parent-type].[field-name]
리졸브 메트릭은 요청된 특정 GraphQL 데이터를 리졸브하는 데 소요된 시간을 기록합니다. 이를 사용하여 수신되는 쿼리의 속도 저하에 영향을 줄 수 있는 특정 리졸버를 찾거나, 서로 다른 타입에서 이름이 같은 필드 리졸버를 구별하거나, 여러 다른 타입에 적용된 동일한 리졸버를 식별할 수 있습니다.
이 항목들은 세그먼트 및 스팬 대응 항목과 명칭이 약간 다릅니다. 관계를 더 잘 시각화하기 위해 필드의 전체 경로는 세그먼트와 스팬으로 표시됩니다(예: libraries.books.title). 모든 사용 및 트랜잭션에 걸쳐 집계된 기간을 파악하기 위해, 이 메트릭은 전체 경로 없이 필드 이름을 사용합니다.
필드 및 인수 메트릭
/GraphQL/field/ApolloServer/[parent-type].[field-name] /GraphQL/arg/ApolloServer/[parent-type].[field-name]/[arg-name]
필드 메트릭은 config.apollo_server.field_metrics 이(가) true일 때만 수집됩니다. 필드 리졸브 메트릭과 달리, 이는 필드 또는 리졸버 인수가 나타날 때마다 캡처합니다. 이 메트릭을 사용하여 GraphQL 스키마의 필드가 여전히 사용 중인지, 제거해도 안전한지 판단하십시오.
지난 하루 동안 요청된 모든 필드 및 인수
FROM Metric SELECT count(newrelic.timeslice.value) where appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/{kind}/ApolloServer/{field}' where kind = 'arg' or kind = 'field' FACET kind, field limit max since 1 day ago시각화
다음 쿼리는 이러한 메트릭을 사용하여 Apollo GraphQL 애플리케이션의 동작을 이해하는 데 도움을 줍니다.
상위 10개 작업
가장 느린 상위 10개 작업 목록을 가져오려면, 요청 시 또는 대시보드의 일부로 다음 쿼리를 사용하세요.
FROM Metric SELECT average(newrelic.timeslice.value) * 1000 WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{operation}' FACET operation LIMIT 10바 (Bar) 차트 유형은 트랜잭션 개요와 유사한 시각화를 제공합니다.
테이 (Table)블 차트 유형은 작업 내역을 보여주는 데도 유용합니다. 추가적인 정렬 및 시각화 유연성을 위해 METRIC_FORMAT 을(를) 사용하십시오. 다음 쿼리는 작업 유형, 작업 이름, 가장 깊은 경로 및 AVG Duration (MS)에 대한 열을 생성합니다.
FROM Metric SELECT average(newrelic.timeslice.value) * 1000 as 'AVG Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{type}/{name}/{deepest-path}' FACET type, name, `deepest-path` LIMIT 20평균 작업 시간
작업의 시간 경과에 따른 평균 지속 시간을 추적하려면 TIMESERIES과(와) 함께 유사한 쿼리를 사용하세요.
FROM Metric SELECT average(newrelic.timeslice.value) WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/operation/ApolloServer/{operation}' TIMESERIES FACET operation모든 작업을 보거나 개별 작업을 토글할 수 있는 Line 차트 유형으로 이를 확인하십시오.
상위 10개 리졸버
가장 느린 상위 10개 리졸버 목록을 가져오려면, 필요에 따라 또는 대시보드의 일부로 다음 쿼리를 사용하십시오.
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{type}.{field}' FACET field LIMIT 20상위 유형을 포함하려면:
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{field}' FACET field LIMIT 20바 (Bar) 차트 유형은 트랜잭션 개요와 유사한 시각화를 제공합니다. 테이 (Table)블 차트 유형은 필드 및 Average Duration (MS) [평균 소요 시간(MS)]의 세부 내역을 표시하는 데에도 유용합니다.
평균 리졸버 시간
리졸버의 시간 경과에 따른 평균 기간을 추적하려면 TIMESERIES과(와) 함께 유사한 쿼리를 사용하십시오.
FROM MetricSELECT average(newrelic.timeslice.value) * 1000 as 'Average Duration (MS)' TIMESERIES WHERE appName = 'YOUR_APP_NAME' WITH METRIC_FORMAT 'GraphQL/resolve/ApolloServer/{field}' FACET field모든 리졸버를 확인하거나 개별 항목을 토글할 수 있는 선 (Line) 차트 유형으로 이를 확인하십시오.
자원
세그먼트 및 스팬
세그먼트 및 스팬(분산 추적이 활성화된 경우)은 GraphQL 작업, 필드 해석, 그리고 데이터베이스에 쿼리를 수행하는 것과 같이 필드 해석의 일부로 발생하는 추가적인 계측된 작업에 대해 캡처됩니다.
작업 세그먼트/스팬
/GraphQL/operation/ApolloServer/[operation-type]/[operation-name]/[deepest-unique-path]
작업 세그먼트와 스팬에는 작업 유형, 작업 이름, 가장 깊은 고유 경로가 포함됩니다. 이는 트랜잭션 또는 트레이스 내 특정 호출의 개별 소요 시간 및 속성을 나타냅니다.
각 부분에 대한 자세한 내용은 트랜잭션 섹션을 참조하세요.
속성
이름 | 설명 | 기본값 |
|---|---|---|
|
| 포함됨 |
| 작업에 지정된 이름 또는 | 포함됨 |
| 인수가 난독화된 원본 GraphQL 쿼리 | 포함됨 |
쿼리 속성(또는 모든 속성)을 제외하려면 속성 이름을 attributes 제외 목록에 추가하거나 세그먼트 및 스팬 속성 제외 목록에 각각 추가하세요.
속성 포함 및 제외에 대한 자세한 내용은 속성 문서를 참조하세요.
필드 해결 세그먼트/스팬
/GraphQL/resolve/ApolloServer/[path]
리졸브 세그먼트 및 스팬은 주어진 트레이스 또는 트랜잭션 내에서 가장 잘 구분하기 위해 개별 필드의 리졸루션 경로를 사용합니다. 예를 들어, 단순히 books 대신 libraries.books 경로가 사용됩니다. 이는 GraphQL 작업의 일부로 처리되는 특정 필드의 개별 소요 시간 및 속성을 나타냅니다.
속성
이름 | 설명 | 기본값 |
|---|---|---|
| 해결된 필드의 이름 | 포함됨 |
| 확인된 필드의 반환 유형( | 포함됨 |
| 이 필드의 상위 유형( | 포함됨 |
| 필드의 전체 확인 경로( | 포함됨 |
| 이 리졸버에 대한 GraphQL 쿼리 또는 뮤테이션에 전달되어 핵심 가치 쌍으로 캡처된 인수 | 제외됨 |
args 속성을 캡처하려면 graphql.field.args.* 을(를) attributes 포함 목록에 추가하거나 세그먼트 및 스팬 속성 포함 목록에 개별적으로 추가하십시오.
속성 포함 및 제외에 대한 자세한 내용은 속성 문서를 참조하세요.
업무
query { libraries { books { title author { name } } }}post /query/<anonymous>/libraries.books
트랜잭션은 웹 트랜잭션으로 캡처되고, 기본 프레임워크(Express, Koa 등)와 연결되며, 실행된 GraphQL 작업을 기반으로 이름이 지정됩니다.
에이전트는 트랜잭션 이름으로 고유한 쿼리 표현을 그룹화하기 위해 여러 세부 정보를 사용합니다: HTTP 메서드, 작업 유형, 작업 이름 및 확인된 가장 깊은 경로(여러 개인 경우 첫 번째).
트랜잭션의 원시 표현은 다음과 같습니다. /WebTransaction/{framework-name}/POST//{operation-type}/{operation-name}/{deepest-unique-path}
Apollo Server의 Express 사용의 경우, 다음과 같을 수 있습니다: /WebTransaction/Expressjs/POST//query/<anonymous>/libraries.books
뉴렐릭 One의 트랜잭션은 궁극적으로 다음과 유사하게 표시됩니다: post /query/<anonymous>/libraries.books.
세부
HTTP 메서드
웹 요청에 대한 HTTP 메서드입니다. 요청은 GET 또는 POST를 통해 수신될 수 있으며, 다른 웹 트랜잭션과 유사하게 표시됩니다.
작업 유형
작업이 쿼리인지 돌연변이인지 나타냅니다.
작업 이름
제공된 경우 작업 이름 또는 <anonymous>입니다.
query { libraries } 이름이 제공되지 않았으므로 작업 이름 <anonymous> 을(를) 사용합니다.
query GetLibraries { libraries } 와(과) 같은 명명된 쿼리는 작업 이름 GetLibraries을(를) 사용합니다.
가장 깊은 고유 경로
각 수준에서 하나의 필드만 선택된 쿼리의 선택 집합에 포함된 가장 깊은 경로입니다. 작업 이름을 재사용할 수 있으므로 지정된 작업의 고유성을 추가로 결정하는 데 도움이 됩니다.
에이전트는 애플리케이션의 속도 저하 원인에 대한 세부 정보를 암시하거나 숨길 수 있는 임의의 명명 결정을 내리는 것을 피하기 위해 (가장 깊은 경로 대신) 가장 깊은 고유 경로를 사용합니다.
쿼리의 경우:
query { libraries { branch booksInStock { isbn title author } magazinesInStock { issue title } }}해당 지점 이후에 여러 필드가 선택되었기 때문에 가장 깊은 고유 경로는 libraries (으)로 확인됩니다. 그 시점 이후에 실행되는 모든 리졸버는 트랜잭션의 성능 특성에 영향을 미칠 수 있습니다.
쿼리가 리졸버당 하나의 필드만 선택하는 경우, 각 선택 세트가 고유하므로 전체 경로가 사용됩니다.
쿼리:
query { libraries { booksInStock { title } }}가장 깊은 고유 경로의 결과: libraries.booksInStock.title.
id 및 __typename 필드는 이름 지정 결정에서 자동으로 제외됩니다.
예를 들어, 페더레이션된 서브그래프 쿼리:
query { libraries { branch __typename id }}가장 깊은 고유 경로의 결과: libraries.branch.
유니온 타입과 인라인 프래그먼트
인라인 프래그먼트를 사용하는 유니언 타입의 경우, 쿼리에 하나의 결과 타입만 지정될 때 트랜잭션 이름은 < ... > 괄호를 사용하여 기본 선택된 필드를 나타냅니다.
다음 스키마의 경우:
union SearchResult = Book | Author
type Book { title: String!}
type Author { name: String!}
type Query { search(contains: String): [SearchResult!]}그리고 다음 쿼리는:
query example { search(contains: "author") { __typename ... on Author { name } }}다음 트랜잭션 이름이 생성됩니다:
post /query/example/search<Author>.name
하지만 쿼리가 Book과 Author를 모두 반환하는 경우:
query example { search(contains: "author") { __typename ... on Author { name } ... on Book { title } }}결과 트랜잭션 이름은:
post /query/example/search
오류 발생 시 이름 지정
GraphQL 요청을 파싱하거나 유효성을 검사할 때 발생하는 오류는 트랜잭션 이름 지정에 영향을 미칠 수 있습니다.
검증 오류
요청이 파싱되었으나 유효성 검사에 실패한 경우, 에이전트는 시도된 작업을 기반으로 트랜잭션 이름을 지정합니다. 예를 들어, 이는 수신되는 GraphQL 쿼리에 필드가 존재하지 않는 경우에 발생합니다.
이 상황에서, 에이전트는 파싱된 문서를 사용하여 가장 깊은 의도된 경로를 계산하는 것을 포함하여 의도된 각 부분을 나타냅니다.
다음은 존재하지 않는 필드(doesnotexist)를 쿼리하는 예와 이것이 NR One에서 어떻게 보이는지에 대한 예입니다.
query GetBooksByLibrary { libraries { books { doesnotexist { name } } }}post /query/GetBooksByLibrary/libraries.books.doesnotexist.name
구문 분석 오류
요청된 작업을 구문 분석할 수 없는 경우, 에이전트는 일반적인 작업 부분 대신 와일드카드(*)를 사용하여 트랜잭션 이름을 지정합니다. 이 상황에서는 쿼리가 유효하지 않으며, 계속 진행할 수 있는 식별 가능한 부분이 없습니다.
다음은 닫는 } 이(가) 누락되어 구문 분석할 수 없는 예와 NR One에서 어떻게 보이는지에 대한 예입니다.
query GetBooksByLibrary { libraries { books { title author { name } } }// missing closing }post /*
이러한 상황에서는 오류와 관련된 작업 스팬의 query 속성이 특정 원인을 식별하는 가장 좋은 방법입니다.
배치 쿼리
Apollo Server는 배치 쿼리를 지원합니다. 이러한 상황에서는, 명명에 영향을 미치는 여러 작업이 관여합니다.
트랜잭션 그룹을 가장 잘 식별하기 위해 에이전트는 추가 /batch 표시기 뒤에 작업 이름을 집계합니다. 이러한 이름은 꽤 길 수 있습니다.
다음은 배치 쿼리의 예와 NR One에서 어떻게 보이는지 보여주는 예입니다.
[ { query: query GetBookForLibrary { library(branch: "downtown") { books { title author { name } } } } }, { query: mutation { addThing(name: "added thing!") } }]post /batch/query/GetBookForLibrary/library.books/mutation/<anonymous>/addThing
여기에서 batch/ 다음에 query/GetBookForLibrary/library.books 및 mutation/<anonymous>/addThing가 오는 것을 볼 수 있습니다.