[Azure Functions] ServiceBusTrigger의 In-Process 와 Out of Process(Isolated)의 차이점

Azure Functions 란?

Azure에서 Azure Functions는 Azure의 비용을 조금이라도 절감하고 효율적으로 Message를 처리하고자 나온 리소스입니다.
비슷한 서비스로 App Service가 있는데 이 서비스는 장기간 이용하지 않을 경우 휴면모드에 들어가며, Access 했을 때 휴면에서 깨어나게 됩니다. 그러면서 깨어나는 시간도 필요합니다.
반면 Azure Functions는 24시간 휴면모드 없이 동작하며 Azure Functions의 호출횟수와 동작시간을 적절하게 계산하여 특정 상수값으로 나눈 값은 금액으로 청구합니다. 또한 병렬처리도 지원하는 유용한 리소스입니다.

Azure Functions Type

.NET으로 Azure Functions을 개발하려면 Visual Studio던, Visual Studio Code 던 In-Process 또는 Isolated Process 둘 중 하나를 반드시 택 1 해야합니다.

MSDN문서를 보면 아래 이미지와 같은 부분이 있습니다.

보면 Azure Functions 3.x는 In-Process일 때 .NET Core 3.1, Out of Process 에서는 .NET 5.0으로 적혀있습니다. 이것은 In-Process로는 .NET 5로 개발이 불가능하다는 것이고, 반대인 Out of Process에서 .NET Core 3.1로 개발이 불가능하다는 것입니다. 물론 Azure Functions 4.x 에서는 이 부분이 개선되어 .NET 6로 In-Process, Out of Process를 둘 다 개발할 수 있게 되었습니다.

아직 In-Process, Out of Process에 대한 감이 잘 오지 않습니다. 눈에 보이는 차이점은 아래 사진 부분인데요.

image

이게 무슨 말인지 저도 한참 생각했는데, 아래 사진과 같은 경우 같습니다.

image

Azure Portal에서 함수 앱을 만드는 과정인데 .NET 의 버전이 3.1과 6만 있습니다.
이 경우 Visual Studio에서 .NET 5로 개발하고자 할 경우, .NET 5로 개발하는 Azure Functions은 개발은 .NET 5로 하고, Azure에 배포 했을 때는 만들어놓은 Azure Functions의 .NET Runtime을 따른다는 의미 같습니다. 내가 .NET 3.1로 Azure Functions 를 만들어 놓으면 개발은 .NET 5로 개발하고 디버깅까지 한 다음, 배포해 놓으면 .NET Core 3.1 에서 동작하는 것입니다. Azure에 Azure Functions 리소스를 .NET 6으로 만들어놨어도 같은 경우일 것입니다.

.NET Azure Functions에서 Service Bus의 In-Process, Out of Process 차이

.NET Azure Functions의 Dependency Injection

솔직히 써본 입장에서는 런타임에서 어떻게 동작하는지는 모르겠지만, 개발의 소스코드 형태로 봤을 때 큰 차이점은 DI를 이용하는 방법입니다.

In-Process에서 종속성 주입을 하려면 Startup 클래스를 따로 작성하여 MSDN의 지침을 따라야합니다.

Out of Process에서 종속성 주입을 하려면 Console App 에서 일반 호스트를 이용할 때와 똑같이 이용하면 됩니다. MSDN 문서에도 Out of Process는 Console App Base라고 명시되어 있습니다. MSDN

Service Bus Trigger 에서 출력 바인딩

Service Bus에서 처리할 작업이 시간이 오래 걸릴 경우, 더욱 효과적인 병렬 처리를 위해 Service Bus를 쪼갤 수 있습니다. 예를 들면 작업이 총합 100짜리 작업이 있는데 50과 50으로 나눠서, 첫번째 50이 다 되었을 때의 결과 문자열을 다음 50을 작업할 수 있는 Service Bus Trigger로 전송하는 것입니다. 그렇게 하고나면 첫번째 50을 처리하는 Trigger는 다음 Message에 대해 작업할 수 있으니 효율적으로 Message를 처리할 수 있게 됩니다. 또한 Trigger를 나눴을 때의 이점은, 첫번째 50의 작업을 수행했더니 뒷 작업으로는 이어지지 않아도 되는 결과 Message가 나왔을 경우 전달하지 않고 첫번째 Trigger에서 작업을 중간에 끝낼 수 있습니다.

이 부분에 대해 저도 커뮤니티 전문가에게 질문한 적이 있는데 이렇게 답변이 달렸습니다.

return null;

을 하라는 내용입니다. 링크해준 github 소스를 보면 null이 아닐 경우에만 출력 바인딩을 진행하고 있습니다.

Out of Process

MSDN에서 확인 가능합니다. 중간 MSDN 글에도 나와있지만, 바인딩 확장 참조 샘플에서 사용하고자 하는 Azure Functions Trigger 예제를 볼 수 있습니다. class를 만들어서 여러 출력 바인딩도 가능합니다. 동시에 여러개의 Service Bus에 메세지를 전송하는 것입니다.

In-Process

MSDN에서 확인 가능하며 Out of Process와는 조금 다르게 생긴 Attribute를 사용합니다.

여기까지 봤을 때는 일반 호스트도 쓸 수 있고, 런타임과 개발단계의 플랫폼을 다르게 가져갈 수도 있는 Out of Process가 더 좋아보입니다. 하지만 Out of Process는 치명적인 단점이 있습니다. Message의 성공여부를 Azure Functions Service Bus Trigger에 위임해야한 다는 것입니다.

Message의 완료 여부 결정

.NET Azure Functions Service Bus Trigger에서 hosts.json에 autoComplete 항목을 true, false를 주냐에 따라 메세지 처리 상태를 결정할 수 있습니다.

true

기본 값은 true이며 이는 Azure Functions가 Function Method의 Scope까지 Exception 없이 정상 진행되고 탈출 했을 경우 무조건 Message를 Complete으로 간주하는 모드입니다. 중간에 Exception이 발생하면 Dead Letter로 빠지게 됩니다.

false

false로 사용자가 설정하게 되면, Azure Functions Service Bus Trigger는 Message를 자동으로 완료하지 않고 처리할 때까지 메세지가 Service Bus에 대기하게 됩니다. Pop 되지 않고 계속 잔류하다가 얼마 시간이 흐른 후 Service Bus가 새 메세지로 간주하고 다시 작업을 시작합니다. 무한 반복하게 되는 것입니다. 이것은 정상 작동이므로 Service Bus의 최대 배달 횟수와 무관합니다. 따라서 Message Handler를 통해 Message를 코딩으로 제어해야합니다. 여기서 Out of Process의 단점이 나옵니다. Out of Process는 .NET Azure Functions 에서 종속성 주입으로 넣어주는 FunctionContext를 통해 Message의 완료여부를 제어할 수 없습니다. 오로지 In-Process만 가능합니다. Microsoft.Azure.ServiceBus, Azure.Messaging.ServiceBus

Service Bus Message SDK는 .NET에 현재 3가지가 있습니다. .NET Framework 용으로 사용되는 SDK 가 있고, MS에서 1차적으로 개발한 SDK가 있고, 가장 최신 SDK인 Azure.Messaging.ServiceBus가 있습니다. 방식은 비슷하지만 Class 이름이 완전히 다릅니다. 따라서 Azure Functions Service Bus Trigger 입문자가 본다면 이미 구글에 검색되는 Service Bus Trigger의 예제를 Lagacy버전으로 잘못 학습할 수 있으니 주의가 필요합니다.

따라서 여기서부터는 In-Process 방식을 기본으로 깔고 가겠습니다.

Microsoft.Azure.WebJobs.Extensions.ServiceBus 4.3.0 이하

Service Bus Trigger에서 이 SDK를 사용해서 Message 완료여부를 결정하려면 반드시 4.3.0 버전을 초과해서는 안됩니다. 4.3.0버전까지는 MessageReceiver 클래스를 이용해서 제어할 수 있습니다. Dependency Injection 중, 함수 파라미터 주입형태로 받은 문자열(Message 클래스)을 주입받고 제어(MessageReceiver.CompleteAsync, MessageReceiver.DeadLetterAsync etc)할 수 있습니다.

4.3.0 버전의 상위 버전인 5.0.0 버전을 확인해보면 내부 Service Bus SDK가 Azure.Messaging.ServiceBus로 바뀌어있습니다. 따라서 Microsoft.Azure.ServiceBus를 직접 Nuget에서 받더라도 IoC 컨테이너에서 파라미터 주입을 해주지 못합니다.

또한 4.3.0 버전을 설치하면 Microsoft.Azure.ServiceBus 의 버전이 4.2.1이므로 필요하다면, 따로 Nuget에서 Lagacy 마지막 버전인 5.2.0을 설치해주어도 됩니다.

Microsoft.Azure.WebJobs.Extensions.ServiceBus 5.0.0 이상

MSDN을 보면 이런식으로 5버전 대부터는 뭔가 다르다고 일러주고 있고, Serivce Bus Trigger 관련 문서를 보면 어렵지 않게 비슷한 문구를 찾아볼 수 있습니다. .NET Service Bus Trigger에 대해 5 버전이 달라진 것은 이 MSDN에 있습니다. 뭐가 바뀐 것 같지만 역시 In-Process라서 아까 In-Process에서 봤던 Attribute 형식을 유지하고 있습니다.

Azure Functions 에 대해 질문 할 곳은…?

이 부분이 저도 많이 난감한 부분입니다. 그래도 답변이 가장 잘 이뤄지는 곳은 Microsoft Q&A 라고 생각합니다. Azure Functions Github Page에서도 기술을 어떻게 써야할지 모르겠으면 Microsoft Q&A를 이용하라고 안내되고 있습니다.

긴 글 읽어주셔서 감사드리며, 피드백은 언제나 감사드리겠습니다.

3개의 좋아요