Azure AI Search에서 성능 분석

이 문서에서는 Azure AI Search에서 쿼리 및 인덱싱 성능을 분석하기 위한 도구, 동작 및 방법을 설명합니다.

기준 번호 개발

대규모 구현에서는 프로덕션 환경에 배포하기 전에 Azure AI Search 서비스의 성능 벤치마킹 테스트를 수행하는 것이 중요합니다. 예상되는 검색 쿼리 로드뿐만 아니라 예상되는 데이터 수집 워크로드도 테스트해야 합니다(가능한 경우 두 워크로드를 동시에 실행). 벤치마크 수치를 통해 적절한 검색 계층, 서비스 구성 및 예상 쿼리 대기 시간을 확인할 수 있습니다.

벤치마크를 개발하려면 Azure-search-performance-testing(GitHub) 도구를 사용하는 것이 좋습니다.

분산 서비스 아키텍처의 효과를 격리하려면 복제본(replica) 하나와 파티션 1개의 서비스 구성을 테스트해 보세요.

참고 항목

스토리지 최적화 계층(L1 및 L2)의 경우 표준 계층보다 더 낮은 쿼리 처리량과 더 높은 대기 시간을 예상해야 합니다.

리소스 로깅 사용

관리자가 처리할 때 가장 중요한 진단 도구는 리소스 로깅입니다. 리소스 로깅은 검색 서비스에 대한 운영 데이터 및 메트릭의 컬렉션입니다. 리소스 로깅은 Azure Monitor를 통해 사용하도록 설정됩니다. Azure Monitor 사용 및 데이터 저장에 대한 비용이 들지만 서비스에 사용하도록 설정하면 성능 문제를 조사하는 데 도움이 될 수 있습니다.

다음 이미지는 쿼리 요청 및 응답의 이벤트 체인을 보여 줍니다. 대기 시간은 네트워크 전송 중, 앱 서비스 계층의 콘텐츠 처리 또는 검색 서비스에서 발생할 수 있습니다. 리소스 로깅의 주요 이점은 활동이 검색 서비스 관점에서 기록된다는 것입니다. 즉, 로그는 성능 문제가 쿼리 또는 인덱싱 문제 또는 다른 실패 지점으로 인한 것인지 확인하는 데 도움이 될 수 있습니다.

Chain of logged events

리소스 로깅은 기록된 정보를 저장하는 옵션을 제공합니다. 사용량 및 성능에 대한 많은 질문에 대답하기 위해 데이터에 대해 고급 Kusto 쿼리를 실행할 수 있도록 Log Analytics를 사용하는 것이 좋습니다.

검색 서비스 포털 페이지에서 진단 설정을 통해 로깅을 사용하도록 설정한 다음 로그를 선택하여 Log Analytics에 대해 Kusto 쿼리를 실행할 수 있습니다. 설정에 대한 자세한 내용은 로그 데이터 수집 및 분석을 참조하세요.

Logging menu options

제한 동작

제한은 검색 서비스가 용량에 있을 때 발생합니다. 제한은 쿼리 또는 인덱싱 중에 발생할 수 있습니다. 클라이언트 쪽에서 API 호출은 제한되었을 때 503 HTTP 응답을 생성합니다. 인덱싱하는 동안 하나 이상의 항목이 인덱싱에 실패했음을 나타내는 207 HTTP 응답을 받을 수도 있습니다. 이 오류는 검색 서비스가 용량에 가까워지고 있음을 나타냅니다.

엄지 손가락의 규칙으로, 제한의 양과 패턴을 정량화하려고합니다. 예를 들어 500,000개 중 하나의 검색 쿼리가 제한되면 조사할 가치가 없을 수 있습니다. 그러나 일정 기간 동안 많은 비율의 쿼리가 제한되면 큰 문제가 될 수 있습니다. 기간 동안 제한을 살펴보면 제한이 발생할 가능성이 더 큰 시간 프레임을 식별하고 이를 가장 잘 수용하는 방법을 결정하는 데 도움이 됩니다.

대부분의 제한 문제에 대한 간단한 해결 방법은 검색 서비스에서 더 많은 리소스를 throw하는 것입니다(일반적으로 쿼리 기반 제한의 경우 복제본(replica) 또는 인덱싱 기반 제한을 위한 파티션). 그러나 복제본(replica) 또는 파티션을 늘리면 비용이 추가되므로 제한이 발생하는 이유를 아는 것이 중요합니다. 제한을 일으키는 조건을 조사하는 방법은 다음의 몇 개 섹션에서 설명합니다.

다음은 부하 상태에 있는 검색 서비스의 HTTP 응답 분석을 식별할 수 있는 Kusto 쿼리의 예입니다. 렌더링된 가로 막대형 차트는 7일 동안 성공한 응답 수(200개)와 비교하여 검색 쿼리의 상대적으로 큰 비율이 제한되었음을 보여 줍니다.

AzureDiagnostics
| where TimeGenerated > ago(7d)
| summarize count() by resultSignature_d 
| render barchart 

Bar chart of http error counts

특정 기간 동안 제한을 검사하면 제한이 더 자주 발생할 수 있는 시간을 식별하는 데 도움이 될 수 있습니다. 아래 예에서 시계열 차트는 지정된 시간 프레임 동안 발생한 제한된 쿼리 수를 표시하는 데 사용됩니다. 이 경우 성능 벤치마킹과 시간 상관 관계가 있는 제한된 쿼리가 수행되었습니다.

let ['_startTime']=datetime('2021-02-25T20:45:07Z');
let ['_endTime']=datetime('2021-03-03T20:45:07Z');
let intervalsize = 1m; 
AzureDiagnostics 
| where TimeGenerated > ago(7d)
| where resultSignature_d != 403 and resultSignature_d != 404 and OperationName in ("Query.Search", "Query.Suggest", "Query.Lookup", "Query.Autocomplete")
| summarize 
  ThrottledQueriesPerMinute=bin(countif(OperationName in ("Query.Search", "Query.Suggest", "Query.Lookup", "Query.Autocomplete") and resultSignature_d == 503)/(intervalsize/1m), 0.01)
  by bin(TimeGenerated, intervalsize)
| render timechart   

Line chart of throttled queries

개별 쿼리 측정

경우에 따라 개별 쿼리를 테스트하여 수행 방법을 확인하는 것이 유용할 수 있습니다. 이렇게 하려면 검색 서비스가 작업을 완료하는 데 걸리는 시간과 클라이언트에서 다시 클라이언트로 왕복 요청을 수행하는 데 걸리는 시간을 확인할 수 있어야 합니다. 진단 로그를 사용하여 개별 작업을 조회할 수 있지만 Postman과 같은 클라이언트 도구에서 이 모든 작업을 수행하는 것이 더 쉬울 수 있습니다.

아래 예제에서는 REST 기반 검색 쿼리가 실행되었습니다. Azure AI Search는 모든 응답에 "경과된 시간"의 헤더 탭에 표시되는 쿼리를 완료하는 데 걸리는 시간(밀리초)을 포함합니다. 응답 맨 위에 있는 상태 옆에는 왕복 기간(이 경우 418밀리초)이 있습니다. 결과 섹션에서 "헤더" 탭을 선택했습니다. 아래 이미지에서 빨간색 상자로 강조 표시된 이 두 값을 사용하면 검색 서비스가 검색 쿼리를 완료하는 데 21ms가 걸렸고 전체 클라이언트 왕복 요청이 125ms를 차지했음을 알 수 있습니다. 이 두 숫자를 빼서 검색 쿼리를 검색 서비스로 전송하고 검색 결과를 클라이언트로 다시 전송하는 데 104ms의 추가 시간이 걸렸다는 것을 확인할 수 있습니다.

이 기술을 사용하면 쿼리 성능에 영향을 주는 다른 요인으로부터 네트워크 대기 시간을 격리할 수 있습니다.

Query duration metrics

쿼리 속도

검색 서비스에서 요청을 제한하는 잠재적인 이유 중 하나는 볼륨이 QPS(초당 쿼리) 또는 QPM(분당 쿼리)으로 캡처되는 쿼리 수가 매우 많기 때문입니다. 검색 서비스가 더 많은 QPS를 받으면 더 이상 유지할 수 없을 때까지 이러한 쿼리에 응답하는 데 일반적으로 더 오래 걸리며, 이로 인해 제한 503 HTTP 응답이 다시 전송됩니다.

다음 Kusto 쿼리는 쿼리의 평균 기간(밀리초)(AvgDurationMS) 및 각 쿼리에서 반환된 평균 문서 수(AvgDocCountReturned)와 함께 QPM으로 측정된 쿼리 볼륨을 보여 줍니다.

AzureDiagnostics
| where OperationName == "Query.Search" and TimeGenerated > ago(1d)
| extend MinuteOfDay = substring(TimeGenerated, 0, 16) 
| project MinuteOfDay, DurationMs, Documents_d, IndexName_s
| summarize QPM=count(), AvgDuractionMs=avg(DurationMs), AvgDocCountReturned=avg(Documents_d)  by MinuteOfDay
| order by MinuteOfDay desc 
| render timechart

Chart showing queries per minute

이 차트 뒤의 데이터를 표시하려면 | render timechart 줄을 제거한 다음 쿼리를 다시 실행합니다.

쿼리에 대한 인덱싱의 영향

성능을 살펴볼 때 고려해야 할 중요한 요소는 인덱싱이 검색 쿼리와 동일한 리소스를 사용한다는 것입니다. 많은 양의 콘텐츠를 인덱싱하는 경우 서비스가 두 워크로드를 모두 수용하려고 할 때 대기 시간이 증가할 것으로 예상할 수 있습니다.

쿼리 속도가 느려지는 경우 인덱싱 작업의 타이밍을 확인하여 쿼리 성능 저하와 일치하는지 확인합니다. 예를 들어 인덱서가 검색 쿼리의 성능 저하와 관련된 일별 또는 시간별 작업을 실행하고 있을 수 있습니다.

이 섹션에서는 검색 및 인덱싱 속도를 시각화하는 데 도움이 되는 일련의 쿼리를 제공합니다. 이러한 예에서는 시간 범위가 쿼리에서 설정됩니다. Azure Portal에서 쿼리를 실행할 때 쿼리에서 집합을 나타내야 합니다.

Setting time ranges in the query tool

평균 쿼리 대기 시간

아래 쿼리에서는 검색 쿼리의 평균 대기 시간을 표시하기 위해 1분 간격 크기를 사용합니다. 차트에서 평균 대기 시간이 오후 5시 45분까지 낮고 오후 5시 53분까지 지속되었음을 알 수 있습니다.

let intervalsize = 1m; 
let _startTime = datetime('2021-02-23 17:40');
let _endTime = datetime('2021-02-23 18:00');
AzureDiagnostics
| where TimeGenerated between(['_startTime']..['_endTime']) // Time range filtering
| summarize AverageQueryLatency = avgif(DurationMs, OperationName in ("Query.Search", "Query.Suggest", "Query.Lookup", "Query.Autocomplete"))
    by bin(TimeGenerated, intervalsize)
| render timechart

Chart showing average query latency

QPM(분당 평균 쿼리 수)

다음 쿼리는 대기 시간에 영향을 미칠 수 있는 검색 요청이 급증하지 않았는지 확인하기 위해 분당 평균 쿼리 수를 확인합니다. 차트에서 약간의 차이가 있지만 요청 수가 급증했음을 나타내는 것은 없습니다.

let intervalsize = 1m; 
let _startTime = datetime('2021-02-23 17:40');
let _endTime = datetime('2021-02-23 18:00');
AzureDiagnostics
| where TimeGenerated between(['_startTime'] .. ['_endTime']) // Time range filtering
| summarize QueriesPerMinute=bin(countif(OperationName in ("Query.Search", "Query.Suggest", "Query.Lookup", "Query.Autocomplete"))/(intervalsize/1m), 0.01)
  by bin(TimeGenerated, intervalsize)
| render timechart

Chart showing average queries per minute

OPM(분당 인덱싱 작업)

여기서는 분당 인덱싱 작업 수를 살펴보겠습니다. 차트에서 많은 양의 데이터가 오후 5시 42분에 시작되고 오후 5시 50분에 종료된 것을 볼 수 있습니다. 이 인덱싱은 검색 쿼리가 대기 상태가 되기 3분 전에 시작되었으며 검색 쿼리가 더 이상 대기하지 않는 3분 전에 종료되었습니다.

이 인사이트에서 검색 서비스가 쿼리 대기 시간에 영향을 줄 만큼 인덱싱이 충분히 사용되기까지 약 3분이 걸렸다는 것을 알 수 있습니다. 또한 인덱싱이 완료된 후 검색 서비스가 새로 인덱싱된 콘텐츠의 모든 작업을 완료하고 쿼리 대기 시간이 해결되는 데 3분이 더 걸렸다는 것을 알 수 있습니다.

let intervalsize = 1m; 
let _startTime = datetime('2021-02-23 17:40');
let _endTime = datetime('2021-02-23 18:00');
AzureDiagnostics
| where TimeGenerated between(['_startTime'] .. ['_endTime']) // Time range filtering
| summarize IndexingOperationsPerSecond=bin(countif(OperationName == "Indexing.Index")/ (intervalsize/1m), 0.01)
  by bin(TimeGenerated, intervalsize)
| render timechart 

Chart showing indexing operations per minute

백그라운드 서비스 처리

쿼리 또는 인덱싱 대기 시간이 주기적으로 급증하는 것은 드문 일이 아닙니다. 인덱싱 또는 높은 쿼리 속도에 대한 응답으로 급증이 발생할 수 있지만 병합 작업 중에 발생할 수도 있습니다. 검색 인덱스는 청크 또는 분할된 데이터베이스에 저장됩니다. 시스템은 정기적으로 더 작은 분할된 데이터베이스를 큰 분할된 데이터베이스에 병합하여 서비스 성능을 최적화하는 데 도움이 됩니다. 또한 이 병합 프로세스는 이전에 인덱스에서 삭제되도록 표시된 문서를 클린 저장 공간을 복구합니다.

분할된 데이터베이스 병합은 빠르지만 리소스를 많이 사용하므로 서비스 성능이 저하될 수 있습니다. 짧은 쿼리 대기 시간이 표시되고 이러한 버스트가 인덱싱된 콘텐츠의 최근 변경 내용과 일치하는 경우 지연 시간이 분할된 데이터베이스 병합 작업 때문이라고 가정할 수 있습니다.

다음 단계

서비스 성능 분석과 관련된 이러한 문서를 검토합니다.