지속성 함수의 성능 및 크기 조정(Azure Functions)

성능 및 확장성을 최적화하려면 지속성 함수의 고유한 크기 조정 특징을 이해하는 것이 중요합니다. 이 문서에서는 부하를 기반으로 작업자를 조정하는 방법과 다양한 매개 변수를 조정할 수 있는 방법을 설명합니다.

작업자 확장

작업 허브 개념의 기본적인 이점은 작업 허브 작업 항목을 처리하는 작업자의 수를 지속적으로 조정할 수 있다는 것입니다. 특히 애플리케이션은 작업을 더 빨리 처리해야 하는 경우 작업자를 더 추가(스케일 아웃)할 수 있고 작업자를 계속 바쁘게 유지하기에 충분한 작업이 없으면 작업자를 제거(스케일 인)할 수 있습니다. 작업 허브가 완전히 유휴 상태인 경우 크기를 0으로 조정하는 것도 가능합니다. 크기를 0으로 조정하면 작업자가 전혀 없습니다. 크기 조정 컨트롤러와 스토리지만 활성 상태로 유지하면 됩니다.

다음 다이어그램은 이 개념을 보여 줍니다.

Worker scaling diagram

자동 크기 조정

Consumption 및 Elastic Premium 플랜에서 실행 중인 모든 Azure Functions와 마찬가지로 Durable Functions는 Azure Functions 스케일 컨트롤러를 통해 자동 스케일링을 지원합니다. 크기 조정 컨트롤러는 메시지와 작업이 처리되기 전에 대기해야 하는 시간을 모니터링합니다. 이러한 대기 시간을 기반으로 작업자 추가 또는 제거 여부를 결정할 수 있습니다.

참고 항목

Durable Functions 2.0부터 함수 앱은 Elastic Premium 플랜의 VNET 보호 서비스 엔드포인트 내에서 실행되도록 구성할 수 있습니다. 이 구성에서 Durable Functions 트리거는 스케일링 컨트롤러 대신 스케일링 요청을 시작합니다. 자세한 정보는 런타임 스케일링 모니터링을 참조하세요.

프리미엄 플랜에서 자동 크기 조정을 통해 작업자 수(즉, 운영 비용)를 애플리케이션에서 발생하는 부하에 대략 비례하도록 유지할 수 있습니다.

CPU 사용량

오케스트레이터 함수는 여러 번의 재생을 거치면서 실행이 결정적이 될 수 있도록 단일 스레드에서 실행됩니다. 이러한 단일 스레드 실행 때문에, 오케스트레이터 함수 스레드는 어떤 이유로든 CPU 집약적 작업을 수행하지 않고, I/O를 수행하지 않고, 차단하지 않습니다. I/O, 차단 또는 다중 스레드가 필요한 작업은 작업 함수로 이동해야 합니다.

작업 함수에는 일반 큐 트리거 함수와 동일한 모든 동작이 있습니다. I/O를 안전하게 수행하고, CPU 집약적 작업을 실행하며, 여러 스레드를 사용할 수 있습니다. 작업 트리거는 상태 비저장이므로 VM 수에 관계 없이 자유롭게 확장할 수 있습니다.

엔터티 함수도 단일 스레드에서 실행되고 작업은 한 번에 하나씩 처리됩니다. 그러나 엔터티 함수에서는 실행할 수 있는 코드의 형식이 제한되지 않습니다.

함수 시간 제한

작업, 오케스트레이터 및 엔터티 함수에는 모든 Azure Functions와 동일한 함수 시간 제한이 적용됩니다. 일반적으로 Durable Functions는 애플리케이션 코드에서 throw된 처리되지 않은 예외와 동일한 방식으로 함수 시간 제한을 처리합니다.

예를 들어 작업 시간이 초과되면 함수 실행이 실패로 기록되고 오케스트레이터에 알림이 표시되고 다른 예외와 마찬가지로 시간 제한이 처리됩니다. 호출을 통해 지정된 경우 다시 시도되거나 예외 처리기가 실행될 수 있습니다.

엔터티 작업 일괄 처리

성능을 개선하고 비용을 줄이기 위해 단일 작업 항목이 엔터티 작업의 전체 일괄 처리를 실행할 수 있습니다. 사용량 플랜에서 각 일괄 처리는 단일 함수 실행으로 청구됩니다.

기본적으로 최대 일괄 처리 크기는 50(소비 플랜의 경우) 및 5000(다른 모든 플랜의 경우)입니다. 최대 일괄 처리 크기는 host.json 파일에서도 구성할 수 있습니다. 최대 일괄 처리 크기가 1이면 일괄 처리가 효과적으로 비활성화됩니다.

참고 항목

개별 엔터티 작업을 실행하는 데 시간이 오래 걸리는 경우, 특히 소비 플랜에서 함수 시간 제한의 위험을 줄이기 위해 최대 일괄 처리 크기를 제한하는 것이 도움이 될 수 있습니다.

인스턴스 캐싱

일반적으로 작업자는 오케스트레이션 작업 항목을 처리하기 위해 다음 두 작업 모두 수행해야 합니다.

  1. 오케스트레이션 기록을 가져옵니다.
  2. 기록을 사용하여 오케스트레이터 코드를 재생합니다.

동일한 작업자가 동일한 오케스트레이션에 대해 여러 작업 항목을 처리하는 경우 스토리지 공급자는 작업자의 메모리에 기록을 캐싱하여 이 프로세스를 최적화할 수 있으므로 첫 번째 단계가 필요하지 않습니다. 또한 실행 중 오케스트레이터를 캐시할 수 있어 두 번째 단계인 히스토리 재생도 제거합니다.

캐싱의 일반적인 효과는 기본 스토리지 서비스에 대한 I/O 감소와 전반적으로 개선된 처리량 및 대기 시간입니다. 반면에 캐싱은 작업자의 메모리 사용량을 증가시킵니다.

인스턴스 캐싱은 현재 Azure Storage 공급자 및 Netherite 스토리지 공급자에서 지원됩니다. 아래 표는 비교를 제공합니다.

Azure Storage 공급자 Netherite 스토리지 공급자 MSSQL 스토리지 공급자
인스턴스 캐싱 지원됨
(.NET 처리 중인 작업자만 해당)
지원됨 지원되지 않음
기본 설정 사용 안 함 사용 해당 없음
메커니즘 확장 세션 인스턴스 캐시 해당 없음
설명서 확장 세션 참조 인스턴스 캐시 참조 해당 없음

캐싱은 기록 재생 빈도를 줄일 수 있지만 재생을 완전히 제거할 수는 없습니다. 오케스트레이터를 개발할 때 캐싱을 사용하지 않도록 설정하는 구성에서 테스트하는 것이 좋습니다. 이 강제 재생 동작은 개발 시 오케스트레이터 함수 코드 제약 조건 위반을 검색하는 데 유용할 수 있습니다.

캐싱 메커니즘 비교

공급자는 다양한 메커니즘을 사용하여 캐싱을 구현하고 다양한 매개 변수를 제공하여 캐싱 동작을 구성합니다.

  • Azure Storage 공급자에서 사용하는 확장 세션은 중간 실행 오케스트레이터가 얼마 동안 유휴 상태가 될 때까지 메모리에 유지합니다. 이 메커니즘을 제어하는 매개 변수는 extendedSessionsEnabledextendedSessionIdleTimeoutInSeconds입니다. 자세한 내용은 Azure Storage 공급자 설명서의 확장 세션을 참조하세요.

참고 항목

확장 세션은 .NET In Process 작업자에서만 지원됩니다.

  • Netherite 스토리지 공급자가 사용하는 인스턴스 캐시는 사용된 총 메모리를 추적하면서 기록을 포함한 모든 인스턴스의 상태를 작업자의 메모리에 유지합니다. 캐시 크기가 InstanceCacheSizeMB에 의해 구성된 제한을 초과하면 오래 전에 사용한 인스턴스 데이터가 제거됩니다. CacheOrchestrationCursors가 true로 설정되면 캐시는 인스턴스 상태와 함께 중간 실행 조정자를 저장합니다. 자세한 내용은 Netherite 스토리지 공급자 설명서의 인스턴스 캐시 섹션을 참조하세요.

참고 항목

인스턴스 캐시는 모든 언어 SDK에서 작동하지만 CacheOrchestrationCursors 옵션은 .NET In Process 작업자에만 사용할 수 있습니다.

동시성 제한

단일 작업자 인스턴스는 여러 작업 항목을 동시에 실행할 수 있습니다. 이렇게 하면 병렬 처리를 늘리고 작업자를 보다 효율적으로 활용할 수 있습니다. 그러나 작업자가 동시에 너무 많은 작업 항목을 처리하려고 하면 CPU 로드, 네트워크 연결 수 또는 사용 가능한 메모리와 같은 사용 가능한 리소스가 모두 사용될 수 있습니다.

개별 작업자가 과도하게 커밋되지 않도록 하려면 인스턴스별 동시성을 제한해야 할 수 있습니다. 각 작업자에서 동시에 실행되는 함수 수를 제한하면 해당 작업자의 리소스 제한이 소진되지 않도록 방지할 수 있습니다.

참고 항목

동시성 제한은 현재 작업자당 처리 중인 항목을 제한하기 위해 로컬에서만 적용됩니다. 따라서 이러한 제한은 시스템의 총 처리량을 제한하지 않습니다.

경우에 따라 작업자별 동시성을 제한하면 시스템의 총 처리량이 실제로 증가할 수 있습니다. 이는 각 작업자가 더 적은 작업을 수행하여 크기 조정 컨트롤러가 큐를 따라잡기 위해 더 많은 작업자를 추가하여 총 처리량을 증가시킬 때 발생할 수 있습니다.

제한 구성

작업, 오케스트레이터 및 엔터티 함수 동시성 제한은 둘 다 host.json 파일에서 구성할 수 있습니다. 관련 설정은 작업 함수의 경우 durableTask/maxConcurrentActivityFunctions이고 오케스트레이터와 엔터티 함수 둘 다의 경우 durableTask/maxConcurrentOrchestratorFunctions입니다. 이러한 설정은 단일 작업자의 메모리에 로드되는 오케스트레이터, 엔터티 또는 작업 함수의 최대 수를 제어합니다.

참고 항목

오케스트레이션 및 항목은 이벤트 또는 작업을 활발하게 처리하거나 인스턴스 캐싱이 사용하도록 설정된 경우에만 메모리에 로드됩니다. 해당 논리 및 대기는 실행 후(예: 오케스트레이터 함수 코드의 await(C#) 또는 yield(JavaScript, Python) 문을 실행) 메모리에서 언로드될 수 있습니다. 메모리에서 언로드된 오케스트레이션 및 엔터티는 maxConcurrentOrchestratorFunctions 스로틀을 계산하는 데 포함되지 않습니다. 수백만 개의 오케스트레이션 또는 엔터티가 ‘실행 중’ 상태인 경우에도 활성 메모리에 로드될 때만 스로틀 제한으로 계산됩니다. 마찬가지로 작업 함수를 예약하는 오케스트레이션은 오케스트레이션이 작업이 실행 완료를 기다리는 경우 스로틀에 포함되지 않습니다.

Functions 2.0

{
  "extensions": {
    "durableTask": {
      "maxConcurrentActivityFunctions": 10,
      "maxConcurrentOrchestratorFunctions": 10
    }
  }
}

Functions 1.x

{
  "durableTask": {
    "maxConcurrentActivityFunctions": 10,
    "maxConcurrentOrchestratorFunctions": 10
  }
}

언어 런타임 고려 사항

선택한 언어 런타임은 엄격한 동시성 제한 또는 함수를 적용할 수 있습니다. 예를 들어 Python 또는 PowerShell로 작성된 Durable Function 앱은 단일 VM에서 한 번에 하나의 함수만 실행할 수 있습니다. 따라서 신중하게 고려하지 않으면 상당한 성능 문제가 발생할 수 있습니다. 예를 들어 오케스트레이터가 10개의 활동으로 팬아웃하지만 언어 런타임이 동시성을 하나의 함수로만 제한하는 경우 10개의 작업 함수 중 9개는 실행될 기회를 기다리는 동안 중단됩니다. 또한 이렇게 중단된 9개의 활동은 Durable Functions 런타임이 이미 메모리에 로드했으므로 다른 작업자에게 부하를 분산할 수 없습니다. 활동 함수가 오래 실행되는 경우 특히 문제가 됩니다.

사용 중인 언어 런타임이 동시성에 제한을 두는 경우 Durable Functions 동시성 설정을 언어 런타임의 동시성 설정과 일치하도록 업데이트해야 합니다. 이렇게 하면 Durable Functions 런타임이 언어 런타임에서 허용하는 것보다 더 많은 함수를 동시에 실행하려고 시도하지 않으므로 보류 중인 모든 활동의 부하가 다른 VM에 분산되도록 할 수 있습니다. 예를 들어 동시성을 4개의 함수로 제한하는 Python 앱(단일 언어 작업자 프로세스에서 4개의 스레드로만 구성되거나 4개 언어 작업자 프로세스에서 1개의 스레드로만 구성됨)이 있는 경우 maxConcurrentOrchestratorFunctionsmaxConcurrentActivityFunctions를 모두 4로 구성해야 합니다.

Python에 대한 자세한 내용 및 성능 권장 사항은 Azure Functions Python 앱의 처리량 성능 향상을 참조하세요. 이 Python 개발자 참조 설명서에 언급된 기술은 Durable Functions 성능 및 확장성에 상당한 영향을 줄 수 있습니다.

파티션 수

일부 스토리지 공급자는 파티션 메커니즘을 사용하고 partitionCount 매개 변수 지정을 허용합니다.

분할을 사용할 때 작업자는 개별 작업 항목에 대해 직접 경쟁하지 않습니다. 대신 작업 항목이 먼저 partitionCount 파티션으로 그룹화됩니다. 그런 다음 이러한 파티션이 작업자에게 할당됩니다. 부하 분산에 대한 이러한 분할 방법은 필요한 총 스토리지 액세스 수를 줄이는 데 도움이 될 수 있습니다. 또한 인스턴스 캐싱을 사용하도록 설정하고 선호도를 만들기 때문에 지역성을 개선할 수 있습니다. 동일한 인스턴스의 모든 작업 항목이 동일한 작업자에 의해 처리됩니다.

참고 항목

최대 partitionCount명의 작업자가 분할된 큐에서 작업 항목을 처리할 수 있으므로 분할 제한이 스케일 아웃됩니다.

다음 표는 각 스토리지 공급자에 대해 분할된 큐와 partitionCount 매개 변수의 허용 범위 및 기본값을 보여 줍니다.

Azure Storage 공급자 Netherite 스토리지 공급자 MSSQL 스토리지 공급자
인스턴스 메시지 Partitioned Partitioned 분할되지 않음
작업 메시지 분할되지 않음 Partitioned 분할되지 않음
기본값 partitionCount 4 12 해당 없음
최대 partitionCount 16 32 해당 없음
설명서 오케스트레이터 스케일 아웃 참조 파티션 수 고려 사항 참조 해당 없음

Warning

작업 허브를 만든 후에는 더 이상 파티션 수를 변경할 수 없습니다. 따라서 작업 허브 인스턴스에 대한 향후 스케일 아웃 요구 사항을 수용할 수 있을 만큼 충분히 큰 값으로 설정하는 것이 좋습니다.

파티션 수 구성

partitionCount 매개 변수는 host.json 파일에서 지정할 수 있습니다. 다음 예제 host.json 코드 조각에서는 durableTask/storageProvider/partitionCount 속성(또는 durableTask/partitionCount in Durable Functions 1.x)을 3으로 설정합니다.

Durable Functions 2.x

{
  "extensions": {
    "durableTask": {
      "storageProvider": {
        "partitionCount": 3
      }
    }
  }
}

Durable Functions 1.x

{
  "extensions": {
    "durableTask": {
      "partitionCount": 3
    }
  }
}

호출 대기 시간을 최소화하기 위한 고려 사항

정상적인 상황에서 호출 요청(활동, 오케스트레이터, 엔터티 등)은 오히려 신속하게 처리되어야 합니다. 그러나 호출 요청의 최대 대기 시간은 App Service 계획의 크기 조정 동작 유형, 동시성 설정 및 애플리케이션 백로그 크기와 같은 요인에 따라 달라지기 때문에 보장되지 않습니다. 따라서 스트레스 테스트투자하여 애플리케이션의 비상 대기 시간을 측정하고 최적화하는 것이 좋습니다.

성능 목표

프로덕션 애플리케이션에 대해 지속형 함수를 사용하려는 경우 계획 프로세스의 초기에 성능 요구 사항을 검토해야 합니다. 몇 가지 기본 사용 시나리오는 다음과 같습니다.

  • 순차적 작업 실행: 이 시나리오에서는 일련의 작업 함수를 순차적으로 실행하는 오케스트레이터 함수를 설명합니다. 이 시나리오는 함수 체인 샘플과 가장 유사합니다.
  • 병렬 작업 실행: 이 시나리오에서는 팬아웃, 팬인 패턴을 사용하여 많은 작업 함수를 병렬로 실행하는 오케스트레이터 함수를 설명합니다.
  • 병렬 응답 처리:이 시나리오는 팬아웃, 팬인 패턴의 두 번째 절반 부분입니다. 팬인 부분의 성능에 중점을 둡니다. 팬아웃과 달리, 팬인은 단일 오케스트레이터 함수 인스턴스에 의해 수행되므로 단일 VM에서만 실행될 수 있습니다.
  • 외부 이벤트 처리: 이 시나리오에서는 한 번에 하나씩 외부 이벤트를 처리하는 단일 오케스트레이터 함수 인스턴스를 나타냅니다.
  • 엔터티 작업 처리: 이 시나리오는 단일카운터 엔터티가 작업의 상수 스트림을 처리할 수 있는 속도를 테스트합니다.

스토리지 공급자에 대한 해당 설명서에서 이러한 시나리오에 대한 처리량 수치를 제공합니다. 특히 다음 사항에 주의하십시오.

팬아웃과 달리, 팬인 작업은 단일 VM으로 제한됩니다. 애플리케이션이 팬아웃, 팬인 패턴을 사용하며, 팬인 성능에 걱정될 경우 여러 하위 오케스트레이션에 걸쳐 작업 함수 팬아웃을 세분화하는 것을 고려합니다.

다음 단계