Durable Functions 문제 해결 가이드

이 문서는 Durable Functions 앱의 일반적인 시나리오 문제를 해결하는 데 도움이 됩니다. 다음 목록에서 증상을 찾고 연결된 단계에 따라 문제를 진단하고 해결합니다.

일반적인 증상

Application Insights에서 실행할 수 있는 KQL 진단 쿼리에 대해 알아보려면 Durable Functions 진단을 위한 샘플 KQL 쿼리를 참조하세요.

Pending 상태에서 오케스트레이션이 중단됨

오케스트레이션을 시작하면 지속성 확장에서 관리하는 내부 큐에 "시작" 메시지가 기록되고 오케스트레이션 상태가 "보류 중"으로 설정됩니다. 사용 가능한 앱 인스턴스가 오케스트레이션 메시지를 선택하고 성공적으로 처리하면 상태가 "운행 중" (또는 다른 '보류 중'이 아닌 상태로) 전환됩니다.

다음 단계에 따라 "보류 중" 상태에서 무기한 중단된 오케스트레이션 인스턴스의 문제를 해결합니다.

  1. 영향을 받는 오케스트레이션 인스턴스 ID에 대한 경고 또는 오류를 확인하기 위해 Durable Task Framework 추적을 점검하십시오. Application Insights의 추적 오류 및 경고 쿼리 를 사용하여 인스턴스와 관련된 오류를 검색합니다.

  2. Azure Storage 제어 큐를 확인하여 오케스트레이션의 "시작 메시지"가 큐에 있는지 확인합니다. Azure 포털에서 스토리지 계정으로 이동하고, 큐에 넣기를 선택하고, control 접두사를 사용하여 큐를 찾습니다. 제어 큐의 작동 방식에 대한 배경 정보는 Azure Storage 공급자 제어 큐 설명서 참조하세요.

  3. 앱의 플랫폼 구성64비트로 변경합니다. 앱의 메모리가 부족하여 오케스트레이션을 시작하지 못하는 경우가 있습니다. 64비트 프로세스로 전환하면 앱에서 총 메모리를 더 많이 할당할 수 있습니다. 이 변경 내용은 App Service Basic, Standard, Premium 및 Elastic Premium 플랜에만 적용됩니다. 무료 또는 소비 요금제는 64비트 프로세스를 지원하지 않습니다.

오케스트레이션은 긴 지연 후 시작됩니다.

일반적으로 오케스트레이션은 예약된 후 몇 초 이내에 시작됩니다. 그러나 오케스트레이션은 특정 경우에 시작하는 데 더 오래 걸릴 수 있습니다. 다음 단계에 따라 오케스트레이션 실행을 시작하는 데 몇 초 이상 걸리는 문제를 해결합니다.

  1. 지연이 파티션 리밸런싱 또는 타이머 기반 폴링 간격과 같은 Azure Storage 공급자의 알 수 없는 제한 사항과 일치하는지 확인합니다.

  2. 영향을 받는 오케스트레이션 인스턴스 ID를 사용하여 지속성 작업 프레임워크 추적에서 경고 또는 오류를 확인합니다. Application Insights의 추적 오류 및 경고 쿼리 를 사용하여 인스턴스와 관련된 오류를 검색합니다.

Running 상태에서 오케스트레이션이 중단됨

오케스트레이션 상태가 예상보다 오랫동안 "실행 중"으로 표시되거나 진행이 중지된 것으로 보이는 경우 오케스트레이션이 완료되지 않은 작업을 기다리고 있을 수 있습니다. 예를 들어, 이는 내구성 타이머, 활동 작업 또는 외부 이벤트를 대기할 수 있습니다. 예약된 작업이 성공적으로 완료되었지만 오케스트레이션이 계속 진행되지 않는 경우 다음 단계로 진행하지 못하는 문제가 있을 수 있습니다. 이 상태의 오케스트레이션은 종종 "중단된 오케스트레이션"이라고 합니다.

다음 단계에 따라 중단된 오케스트레이션 문제를 해결합니다.

  1. 함수 앱을 다시 시작해 보세요. 이 단계는 앱 또는 확장 코드에서 일시적인 버그 또는 교착 상태로 인해 오케스트레이션이 중단되는 경우에 도움이 될 수 있습니다.

  2. Azure Storage 계정 제어 큐를 확인하여 큐가 지속적으로 증가하는지 확인합니다. Application Insights에서 Azure Storage 메시징 쿼리를 사용하여 오케스트레이션 메시지 큐에서 발생하는 문제를 식별합니다. 문제가 단일 제어 큐에만 영향을 미치는 경우 특정 앱 인스턴스에 문제가 있음을 나타낼 수 있습니다. 이 경우 비정상 VM 인스턴스에서 벗어나기 위해 스케일링을 조정하는 것이 도움이 될 수 있습니다.

  3. Azure Storage 메시징 쿼리 결과를 파티션 ID로 큐 이름으로 필터링하여 특정 제어 큐 파티션과 관련된 문제를 찾습니다.

  4. Durable Functions 버전 관리 설명서 확인합니다. 진행 중인 오케스트레이션 인스턴스에 대한 호환성을 손상시키는 변경 사항은 오케스트레이션이 멈추게 할 수 있습니다.

오케스트레이션을 완료하는 데 예상보다 오래 걸립니다.

데이터 처리가 많고, 내부 오류가 발생하고, 컴퓨팅 리소스가 부족하면 오케스트레이션이 정상보다 느리게 실행될 수 있습니다. 다음 단계에 따라 완료하는 데 예상보다 오래 걸리는 오케스트레이션 문제를 해결합니다.

  1. 영향을 받은 오케스트레이션 인스턴스 ID에 대한 경고 또는 오류를 확인하려면 지속성 작업 프레임워크의 추적 기록을 확인하십시오. Application Insights의 추적 오류 및 경고 쿼리 를 사용하여 인스턴스와 관련된 오류를 검색합니다.

  2. 앱에서 .NET in-process 모델을 사용하는 경우 확장 세션을 사용하도록 설정하는 것이 좋습니다. 확장 세션은 기록 로드를 최소화하므로 처리 속도가 느려질 수 있습니다.

  3. 성능 및 확장성 병목 상태를 확인합니다. CPU 사용량이 많거나 메모리 사용량이 많으면 지연이 발생할 수 있습니다. 자세한 지침은 Durable Functions의 성능 및 크기 조정을 참조하세요.

Durable Functions 진단의 샘플 KQL 쿼리

Azure Functions 앱에 대해 구성된 Azure 애플리케이션 Insights 인스턴스에서 사용자 지정 KQL 쿼리를 작성하여 문제를 해결합니다. 이러한 쿼리에 사용되는 열 정의는 열 참조를 참조하세요.

Azure Storage 메시징

기본 Azure Storage 공급자를 사용하는 경우 모든 Durable Functions 동작은 Azure Storage 큐 메시지에 의해 구동되며 오케스트레이션과 관련된 모든 상태는 테이블 스토리지 및 Blob Storage에 저장됩니다. 지속성 작업 프레임워크 추적을 사용하도록 설정하면 모든 Azure Storage 상호 작용이 Application Insights에 기록됩니다. 이 데이터는 실행 및 성능 문제를 디버깅하는 데 매우 중요합니다.

Durable Functions 확장의 v2.3.0부터 host.json 파일에서 로깅 구성을 업데이트하여 이러한 지속성 작업 프레임워크 로그를 Application Insights 인스턴스에 게시할 수 있습니다. 자세한 내용은 Durable Task Framework 로깅 문서를 참조하세요.

다음 쿼리는 특정 오케스트레이션 인스턴스에 대한 엔드 투 엔드 Azure Storage 상호 작용을 검사합니다. startorchestrationInstanceID을 편집하여 시간 범위 및 인스턴스 ID로 필터링합니다.

let start = datetime(XXXX-XX-XXTXX:XX:XX); // edit this 
let orchestrationInstanceID = "XXXXXXX"; //edit this
traces  
| where timestamp > start and timestamp < start + 1h 
| where customDimensions.Category == "DurableTask.AzureStorage" 
| extend taskName = customDimensions["EventName"]
| extend eventType = customDimensions["prop__EventType"] 
| extend extendedSession = customDimensions["prop__IsExtendedSession"]
| extend account = customDimensions["prop__Account"] 
| extend details = customDimensions["prop__Details"] 
| extend instanceId = customDimensions["prop__InstanceId"] 
| extend messageId = customDimensions["prop__MessageId"] 
| extend executionId = customDimensions["prop__ExecutionId"] 
| extend age = customDimensions["prop__Age"] 
| extend latencyMs = customDimensions["prop__LatencyMs"] 
| extend dequeueCount = customDimensions["prop__DequeueCount"] 
| extend partitionId = customDimensions["prop__PartitionId"] 
| extend eventCount = customDimensions["prop__TotalEventCount"] 
| extend taskHub = customDimensions["prop__TaskHub"] 
| extend pid = customDimensions["ProcessId"]
| extend appName = cloud_RoleName
| extend newEvents = customDimensions["prop__NewEvents"]
| where instanceId == orchestrationInstanceID
| sort by timestamp asc
| project timestamp, appName, severityLevel, pid, taskName, eventType, message, details, messageId, partitionId, instanceId, executionId, age, latencyMs, dequeueCount, eventCount, newEvents, taskHub, account, extendedSession, sdkVersion

추적 오류 및 경고

다음 쿼리는 지정된 오케스트레이션 인스턴스에 대한 오류 및 경고를 검색합니다. 에 대한 orchestrationInstanceID값을 제공합니다.

let orchestrationInstanceID = "XXXXXX"; // edit this
let start = datetime(XXXX-XX-XXTXX:XX:XX); 
traces  
| where timestamp > start and timestamp < start + 1h
| extend instanceId = iif(isnull(customDimensions["prop__InstanceId"] ) , customDimensions["prop__instanceId"], customDimensions["prop__InstanceId"] ) 
| extend logLevel = customDimensions["LogLevel"]
| extend functionName = customDimensions["prop__functionName"]
| extend status = customDimensions["prop__status"]
| extend details = customDimensions["prop__Details"] 
| extend reason = customDimensions["prop__reason"]
| where severityLevel >= 1 // to see all logs of severity level "Information" or greater.
| where instanceId == orchestrationInstanceID
| sort by timestamp asc 

큐 및 파티션 ID 로그 관리

다음 쿼리는 instanceId의 제어 큐와 연결된 모든 활동을 검색합니다. 인스턴스 ID orchestrationInstanceID 의 값과 쿼리의 시작 시간을 입력합니다 start.

let orchestrationInstanceID = "XXXXXX"; // edit this
let start = datetime(XXXX-XX-XXTXX:XX:XX); // edit this
traces  // determine control queue for this orchestrator
| where timestamp > start and timestamp < start + 1h 
| extend instanceId = customDimensions["prop__TargetInstanceId"] 
| extend partitionId = tostring(customDimensions["prop__PartitionId"])
| where partitionId contains "control" 
| where instanceId == orchestrationInstanceID
| join kind = rightsemi(
traces  
| where timestamp > start and timestamp < start + 1h 
| where customDimensions.Category == "DurableTask.AzureStorage" 
| extend taskName = customDimensions["EventName"]
| extend eventType = customDimensions["prop__EventType"] 
| extend extendedSession = customDimensions["prop__IsExtendedSession"]
| extend account = customDimensions["prop__Account"] 
| extend details = customDimensions["prop__Details"] 
| extend instanceId = customDimensions["prop__InstanceId"] 
| extend messageId = customDimensions["prop__MessageId"] 
| extend executionId = customDimensions["prop__ExecutionId"] 
| extend age = customDimensions["prop__Age"] 
| extend latencyMs = customDimensions["prop__LatencyMs"] 
| extend dequeueCount = customDimensions["prop__DequeueCount"] 
| extend partitionId = tostring(customDimensions["prop__PartitionId"])
| extend eventCount = customDimensions["prop__TotalEventCount"] 
| extend taskHub = customDimensions["prop__TaskHub"] 
| extend pid = customDimensions["ProcessId"]
| extend appName = cloud_RoleName
| extend newEvents = customDimensions["prop__NewEvents"]
) on partitionId
| sort by timestamp asc
| project timestamp, appName, severityLevel, pid, taskName, eventType, message, details, messageId, partitionId, instanceId, executionId, age, latencyMs, dequeueCount, eventCount, newEvents, taskHub, account, extendedSession, sdkVersion

Durable Functions 쿼리의 Application Insights 열 참조

다음 표에는 이전 쿼리에서 프로젝팅된 열과 해당 설명이 나열되어 있습니다.

칼럼 설명
pid 함수 앱 인스턴스의 프로세스 ID입니다. 이 값은 오케스트레이션이 실행되는 동안 프로세스가 재활용되었는지 확인하는 데 유용합니다.
태스크명 기록되는 이벤트의 이름입니다.
eventType 일반적으로 오케스트레이터가 수행한 작업을 나타내는 메시지 유형입니다. 가능한 값 및 해당 설명의 전체 목록은 EventType.cs 참조하세요.
확장 세션 확장 세션을 사용할 수 있는지 여부를 나타내는 부울 값입니다.
account 앱에서 사용하는 스토리지 계정입니다.
details 사용 가능한 경우 특정 이벤트에 대한 추가 정보입니다.
instanceId 지정된 오케스트레이션 또는 엔터티 인스턴스의 ID입니다.
messageId 지정된 큐 메시지의 고유한 Azure Storage ID입니다. 이 값은 ReceivedMessage, ProcessingMessage 및 DeletingMessage 추적 이벤트에 가장 일반적으로 나타납니다. 메시지 ID는 메시지를 보낸 Azure Storage 이후에 생성되므로 SendingMessage 이벤트에는 이 값이 없습니다.
실행 ID 오케스트레이터가 호출될 때마다 변경되는 실행 ID입니다.
연령 메시지가 큐에 삽입된 이후의 시간(밀리초)입니다. 큰 숫자는 종종 성능 문제를 나타냅니다. 예외는 TimerFired 메시지 유형으로, 타이머 지속 시간에 따라 Age 값이 클 수 있습니다.
latencyMs ** 일부 스토리지 작업에 걸린 시간(밀리초)입니다.
디큐 카운트 메시지가 큐에서 해제된 횟수입니다. 정상적인 상황에서 이 값은 항상 1입니다. 둘 이상인 경우 문제가 있을 수 있습니다.
파티션ID 이 로그와 연결된 큐의 이름입니다.
totalEventCount (총 이벤트 수) 현재 작업에 관련된 기록 이벤트의 수입니다.
taskHub 작업 허브의 이름입니다.
새 이벤트 스토리지의 기록 테이블에 기록되는 기록 이벤트의 쉼표로 구분된 목록입니다.

소비 계획의 연결 관리 문제

Azure Functions 사용 계획에서 실행되는 앱에는 연결 제한 적용됩니다. 일반적인 증상에는 다음이 포함됩니다.

  • 활동 함수 또는 외부 서비스를 호출할 때 일시적인 연결 오류입니다.
  • 부하 상태에서 산발적으로 실패하는 오케스트레이션입니다.
  • 로그에서 소켓 고갈 오류가 발생했습니다.

연결 사용량을 줄이려면 모든 함수 호출에서 새 HttpClientFactory 인스턴스를 만드는 대신 정적 클라이언트를 사용 HttpClient 하거나 공유합니다. 연결 풀링 및 모범 사례에 대한 자세한 지침은 Azure Functions에서 연결 관리를 참조하세요.

일반 팁

팁 (조언)

특정 문제 해결 단계를 살펴보기 전에 앱에서 최신 Durable Functions 확장 버전을 사용하는지 확인합니다. 대부분의 경우 최신 버전을 사용하면 다른 사용자가 이미 보고한 알려진 문제가 완화됩니다. 업그레이드하는 방법에 대한 지침은 Durable Functions 확장 버전 업그레이드 참조하세요.

Azure 포털의 과정 및 문제 해결 탭은 애플리케이션과 관련된 문제를 모니터링하고 진단하고 잠재적인 솔루션을 제안하는 데 도움이 될 수 있습니다. 자세한 내용은 Azure 함수 앱 진단 참조하세요.

Durable Functions 문제에 대한 지원 받기

이 가이드를 사용하여 문제를 해결할 수 없는 경우 Azure 포털의 함수 앱 페이지의 < support + 문제 해결 섹션에서 >새 지원 요청 블레이드를 열어 지원 티켓을 제출할 수 있습니다.

Azure 포털의 지원 요청 페이지 스크린샷

질문 및 커뮤니티 지원을 위해 다음 GitHub 리포지토리 중 하나에서 문제를 엽니다. 버그를 보고할 때 영향을 받는 인스턴스 ID, 문제를 표시하는 UTC의 시간 범위, 애플리케이션 이름(가능한 경우) 및 배포 지역과 같은 정보를 포함하여 조사 속도를 향상합니다.