Partilhar via


Desempenho do Windows Workflow Foundation 4

O .NET Framework 4 inclui uma grande revisão do Windows Workflow Foundation (WF) com investimentos pesados em desempenho. Esta nova revisão introduz alterações significativas de design das versões anteriores do WF fornecidas como parte do .NET Framework 3.0 e do .NET Framework 3.5. Ele foi rearquitetado a partir do núcleo do modelo de programação, tempo de execução e ferramentas para melhorar significativamente o desempenho e a usabilidade. Este tópico mostra as características de desempenho importantes dessas revisões e as compara com as da versão anterior.

O desempenho de componentes individuais do fluxo de trabalho aumentou em ordens de magnitude entre WF3 e WF4. Isso deixa a lacuna entre os serviços Windows Communication Foundation (WCF) codificados manualmente e os serviços de fluxo de trabalho WCF muito pequena. A latência do fluxo de trabalho foi significativamente reduzida no WF4. O desempenho de persistência aumentou por um fator de 2,5 - 3,0. O monitoramento de integridade por meio do rastreamento do fluxo de trabalho tem significativamente menos despesas gerais. Estas são razões imperiosas para migrar ou adotar o WF4 em seus aplicativos.

Terminologia

A versão do WF introduzida no .NET Framework 4 será referida como WF4 para o resto deste tópico. O WF foi introduzido no .NET Framework 3.0 e teve algumas pequenas revisões através do .NET Framework 3.5 SP1. A versão do .NET Framework 3.5 do Workflow Foundation será referida como WF3 para o resto deste tópico. O WF3 é fornecido no .NET Framework 4 lado a lado com o WF4. Para obter mais informações sobre como migrar artefatos WF3 para WF4, consulte: Windows Workflow Foundation 4 Migration Guide.

O Windows Communication Foundation (WCF) é o modelo de programação unificado da Microsoft para a criação de aplicativos orientados a serviços. Ele foi introduzido pela primeira vez como parte do .NET Framework 3.0 juntamente com o WF3 e agora é um dos principais componentes do .NET Framework.

O Windows Server AppFabric é um conjunto de tecnologias integradas que facilitam a criação, o dimensionamento e o gerenciamento de aplicativos Web e compostos executados no IIS. Ele fornece ferramentas para monitorar e gerenciar serviços e fluxos de trabalho. Para obter mais informações, consulte Windows Server AppFabric 1.0.

Objetivos

O objetivo deste tópico é mostrar as características de desempenho do WF4 com dados medidos para diferentes cenários. Também fornece comparações detalhadas entre WF4 e WF3, mostrando assim as grandes melhorias que foram feitas nesta nova revisão. Os cenários e dados apresentados neste artigo quantificam o custo subjacente de diferentes aspetos do WF4 e WF3. Esses dados são úteis para entender as características de desempenho do WF4 e podem ser úteis no planejamento de migrações do WF3 para o WF4 ou no uso do WF4 no desenvolvimento de aplicativos. No entanto, deve-se ter cuidado nas conclusões retiradas dos dados apresentados neste artigo. O desempenho de um aplicativo de fluxo de trabalho composto depende muito de como o fluxo de trabalho é implementado e como os diferentes componentes são integrados. Deve-se medir cada aplicativo para determinar as características de desempenho desse aplicativo.

Visão geral dos aprimoramentos de desempenho do WF4

O WF4 foi cuidadosamente projetado e implementado com alto desempenho e escalabilidade, que são descritos nas seções a seguir.

Tempo de execução do WF

No núcleo do tempo de execução do WF está um agendador assíncrono que orienta a execução das atividades em um fluxo de trabalho. Ele fornece um ambiente de execução eficiente e previsível para as atividades. O ambiente tem um contrato bem definido para execução, continuação, conclusão, cancelamento, exceções e um modelo de threading previsível.

Em comparação com o WF3, o tempo de execução do WF4 tem um agendador mais eficiente. Ele aproveita o mesmo pool de threads de E/S usado para WCF, que é muito eficiente na execução de itens de trabalho em lote. A fila interna do agendador de itens de trabalho é otimizada para os padrões de uso mais comuns. O tempo de execução do WF4 também gerencia os estados de execução de uma maneira muito leve com sincronização mínima e lógica de manipulação de eventos, enquanto o WF3 depende de registro e invocação de eventos pesados para executar sincronização complexa para transições de estado.

Armazenamento e fluxo de dados

No WF3, os dados associados a uma atividade são modelados por meio de propriedades de dependência implementadas pelo tipo DependencyProperty. O padrão de propriedade de dependência foi introduzido no Windows Presentation Foundation (WPF). Em geral, esse padrão é muito flexível para suportar a vinculação de dados fácil e outros recursos da interface do usuário. No entanto, o padrão requer que as propriedades sejam definidas como campos estáticos na definição do fluxo de trabalho. Sempre que o tempo de execução do WF define ou obtém os valores de propriedade, ele envolve uma lógica de pesquisa muito ponderada.

O WF4 usa uma lógica clara de escopo de dados para melhorar significativamente a forma como os dados são tratados em um fluxo de trabalho. Ele separa os dados armazenados em uma atividade dos dados que estão fluindo através dos limites da atividade usando dois conceitos diferentes: variáveis e argumentos. Usando um escopo hierárquico claro para variáveis e argumentos "In/out/InOut", a complexidade do uso de dados para atividades é drasticamente reduzida e o tempo de vida dos dados também é automaticamente definido como escopo. As atividades têm uma assinatura bem definida descrita por seus argumentos. Simplesmente inspecionando uma atividade, você pode determinar quais dados ela espera receber e quais dados serão produzidos por ela como resultado de sua execução.

No WF3, as atividades eram inicializadas quando um fluxo de trabalho era criado. No WF 4, as atividades são inicializadas somente quando as atividades correspondentes são executadas. Isso permite um ciclo de vida de atividade mais simples sem executar operações de inicialização/desinicialização quando uma nova instância de fluxo de trabalho é criada e, portanto, alcançou mais eficiência

Fluxo de Controlo

Assim como em qualquer linguagem de programação, o WF fornece suporte para fluxos de controle para definições de fluxo de trabalho, introduzindo um conjunto de atividades de fluxo de controle para sequenciamento, looping, ramificação e outros padrões. No WF3, quando a mesma atividade precisa ser reexecutada, uma nova ActivityExecutionContext é criada e a atividade é clonada por meio de uma lógica de serialização e desserialização pesada baseada em BinaryFormatter. Normalmente, o desempenho para fluxos de controle iterativos é muito mais lento do que a execução de uma sequência de atividades.

O WF4 lida com isso de forma bem diferente. Ele usa o modelo de atividade, cria um novo objeto ActivityInstance e o adiciona à fila do agendador. Todo esse processo envolve apenas a criação explícita de objetos e é muito leve.

Programação assíncrona

Os aplicativos geralmente têm melhor desempenho e escalabilidade com programação assíncrona para operações de bloqueio de longa duração, como E/S ou operações de computação distribuída. WF4 fornece suporte assíncrono através de tipos AsyncCodeActivityde atividade base, AsyncCodeActivity<TResult>. O tempo de execução compreende nativamente as atividades assíncronas e, portanto, pode colocar automaticamente a instância em uma zona sem persistência enquanto o trabalho assíncrono estiver pendente. As atividades personalizadas podem derivar desses tipos para executar trabalho assíncrono sem segurar o thread do agendador de fluxo de trabalho e bloquear quaisquer atividades que possam ser executadas em paralelo.

Mensagens

Inicialmente, o WF3 tinha um suporte de mensagens muito limitado através de eventos externos ou invocações de serviços Web. No .NET Framework 3.5, os fluxos de trabalho podem ser implementados como clientes WCF ou expostos como serviços WCF através de SendActivity e ReceiveActivity. No WF4, o conceito de programação de mensagens baseada em fluxo de trabalho foi ainda mais fortalecido através da integração estreita da lógica de mensagens WCF no WF.

O pipeline de processamento unificado de mensagens fornecido no WCF no .NET 4 ajuda os serviços WF4 a terem desempenho e escalabilidade significativamente melhores do que o WF3. O WF4 também fornece suporte de programação de mensagens mais avançado que pode modelar padrões complexos de troca de mensagens (MEPs). Os desenvolvedores podem usar contratos de serviço tipados para obter programação fácil ou contratos de serviço não tipados para obter melhor desempenho sem pagar custos de serialização. O suporte ao cache de canal do lado do cliente por meio da SendMessageChannelCache classe no WF4 ajuda os desenvolvedores a criar aplicativos rápidos com o mínimo de esforço. Para obter mais informações, consulte Alterando os níveis de compartilhamento de cache para atividades de envio.

Programação Declarativa

O WF4 fornece uma estrutura de programação declarativa limpa e simples para modelar processos e serviços de negócios. O modelo de programação suporta a composição totalmente declarativa de atividades, sem código ao lado, simplificando muito a criação do fluxo de trabalho. No .NET Framework 4, a estrutura de programação declarativa baseada em XAML foi unificada no System.Xaml.dll de assembly único para oferecer suporte a WPF e WF.

No WF4, o XAML fornece uma experiência verdadeiramente declarativa e permite que toda a definição do fluxo de trabalho seja definida na marcação XML, fazendo referência a atividades e tipos criados usando .NET. Isso era difícil de fazer no WF3 com o formato XOML sem envolver a lógica code-behind personalizada. A nova pilha XAML no .NET 4 tem um desempenho muito melhor na serialização/desserialização de artefatos de fluxo de trabalho e torna a programação declarativa mais atraente e sólida.

Designer de fluxo de trabalho

O suporte de programação totalmente declarativa para WF4 impõe explicitamente requisitos mais altos para o desempenho do tempo de projeto para grandes fluxos de trabalho. O designer de fluxo de trabalho no WF4 tem escalabilidade muito melhor para fluxos de trabalho grandes do que para o WF3. Com o suporte à virtualização da interface do usuário, o designer pode carregar facilmente um grande fluxo de trabalho de 1000 atividades em poucos segundos, enquanto é quase impossível carregar um fluxo de trabalho de algumas centenas de atividades com o designer WF3.

Comparações de desempenho no nível do componente

Esta seção contém dados sobre comparações diretas entre atividades individuais em fluxos de trabalho WF3 e WF4. Áreas-chave como a persistência têm um impacto mais profundo no desempenho do que as componentes individuais da atividade. As melhorias de desempenho em componentes individuais no WF4 são importantes porque os componentes agora são rápidos o suficiente para serem comparados com a lógica de orquestração codificada manualmente. Um exemplo disso é abordado na próxima seção: "Cenário de composição de serviços".

Configuração do Ambiente

Environment setup for workflow performance measurement

A figura acima mostra a configuração da máquina usada para medição de desempenho no nível do componente. Um único servidor e cinco clientes conectados através de uma interface de rede Ethernet de 1 Gbps. Para facilitar as medições, o servidor é configurado para usar um único núcleo de um servidor dual-proc/quad-core que executa o Windows Server 2008 x86. A utilização da CPU do sistema é mantida em quase 100%.

Detalhes do teste

O WF3 CodeActivity é provavelmente a atividade mais simples que pode ser usada em um fluxo de trabalho WF3. A atividade chama um método no code-behind no qual o programador do fluxo de trabalho pode colocar o código personalizado. No WF4, não há nenhum analógico direto para o WF3 CodeActivity que forneça a mesma funcionalidade. Observe que há uma CodeActivity classe base em WF4 que não está relacionada com o WF3 CodeActivity. Os autores de fluxo de trabalho são incentivados a criar atividades personalizadas e criar fluxos de trabalho somente XAML. Nos testes abaixo, uma atividade chamada Comment é usada no lugar de um vazio CodeActivity nos fluxos de trabalho WF4. O código na atividade é o Comment seguinte:

[ContentProperty("Body")]
    public sealed class Comment : CodeActivity
    {
        public Comment()
            : base()
        {
        }

        [DefaultValue(null)]
        public Activity Body
        {
            get;
            set;
        }

        protected override void Execute(CodeActivityContext context)
        {
        }
    }

Fluxo de trabalho vazio

Este teste usa um fluxo de trabalho de sequência sem atividades filhas.

Atividade única

O fluxo de trabalho é um fluxo de trabalho de sequência que contém uma atividade filho. A atividade é uma CodeActivity atividade sem código no caso WF3 e uma Comment atividade no caso WF4.

Enquanto com 1000 iterações

O fluxo de trabalho de sequência contém uma While atividade com uma atividade filho no loop que não executa nenhum trabalho.

Replicador em comparação com ParallelForEach

ReplicatorActivity em WF3 tem modos de execução sequenciais e paralelos. No modo sequencial, o desempenho da atividade é semelhante ao WhileActivity. O ReplicatorActivity é mais útil para execução paralela. O analógico WF4 para isso é a ParallelForEach<T> atividade.

O diagrama a seguir mostra os fluxos de trabalho usados para este teste. O fluxo de trabalho WF3 está à esquerda e o fluxo de trabalho WF4 está à direita.

WF3 ReplicatorActivity and WF4 ParallelForEach

Fluxo de trabalho sequencial com cinco atividades

Este teste destina-se a mostrar o efeito de ter várias atividades executadas em sequência. Há cinco atividades na sequência.

Escopo da transação

O teste de escopo de transação difere ligeiramente dos outros testes porque uma nova instância de fluxo de trabalho não é criada para cada iteração. Em vez disso, o fluxo de trabalho é estruturado com um loop while contendo uma TransactionScope atividade que contém uma única atividade que não funciona. Cada execução de um lote de 50 iterações através do loop while é contada como uma única operação.

Compensação

O fluxo de trabalho WF3 tem uma única atividade compensatória chamada WorkScope. A atividade simplesmente implementa a ICompensatableActivity interface:

class WorkScope :
        CompositeActivity, ICompensatableActivity
    {
        public WorkScope() : base() { }

        public WorkScope(string name)
        {
            this.Name = name;
        }

        public ActivityExecutionStatus Compensate(
            ActivityExecutionContext executionContext)
        {
            return ActivityExecutionStatus.Closed;
        }
    }

O manipulador de falhas tem como alvo a WorkScope atividade. O fluxo de trabalho WF4 é igualmente simplista. A CompensableActivity tem um corpo e um manipulador de compensação. Uma compensação explícita é a próxima na sequência. A atividade corporal e a atividade do manipulador de compensação são ambas implementações vazias:

public sealed class CompensableActivityEmptyCompensation : CodeActivity
    {
        public CompensableActivityEmptyCompensation()
            : base() { }

        public Activity Body { get; set; }

        protected override void Execute(CodeActivityContext context) { }
    }
    public sealed class CompensableActivityEmptyBody : CodeActivity
    {
        public CompensableActivityEmptyBody()
            : base() { }

        public Activity Body { get; set; }

        protected override void Execute(CodeActivityContext context) { }
    }

O diagrama a seguir mostra o fluxo de trabalho de remuneração básica. O fluxo de trabalho WF3 está à esquerda e o fluxo de trabalho WF4 está à direita.

WF3 and WF4 basic compensation workflows

Resultados do teste de desempenho

Table showing performance test results data

Column chart comparing WF3 and WF4 performance test data

Todos os testes são medidos em fluxos de trabalho por segundo, com exceção do teste de escopo de transação. Como pode ser visto acima, o desempenho do tempo de execução do WF melhorou em toda a linha, especialmente em áreas que exigem várias execuções da mesma atividade, como o loop while.

Cenário de composição de serviços

Como é mostrado na seção anterior, "Comparações de desempenho em nível de componente", houve uma redução significativa na sobrecarga entre WF3 e WF4. Os serviços de fluxo de trabalho do WCF agora podem quase corresponder ao desempenho dos serviços WCF codificados manualmente, mas ainda têm todos os benefícios do tempo de execução do WF. Este cenário de teste compara um serviço WCF com um serviço de fluxo de trabalho WCF no WF4.

Serviço de Loja Online

Um dos pontos fortes do Windows Workflow Foundation é a capacidade de compor processos usando vários serviços. Neste exemplo, há um serviço de loja online que orquestra duas chamadas de serviço para comprar um pedido. O primeiro passo é validar o pedido usando um Serviço de Validação de Pedido. O segundo passo é preencher a encomenda utilizando um Serviço de Armazém.

Os dois serviços de back-end, Order Validating Service e Warehouse Service, permanecem os mesmos para ambos os testes. A parte que muda é o Serviço da Loja Online que executa a orquestração. Em um caso, o serviço é codificado manualmente como um serviço WCF. Para o outro caso, o serviço é escrito como um serviço de fluxo de trabalho WCF no WF4. Recursos específicos do WF, como rastreamento e persistência, estão desativados para este teste.

Environment

Environment setup for performance measurement

As solicitações do cliente são feitas ao Serviço da Loja Online via HTTP a partir de vários computadores. Um único computador hospeda os três serviços. A camada de transporte entre o Serviço de Loja Online e os serviços de back-end é TCP ou HTTP. A medição das operações/segundo baseia-se no número de chamadas concluídas PurchaseOrder efetuadas para o Serviço da Loja Online. O pool de canais é um novo recurso disponível no WF4. Na parte WCF deste canal de teste, o pool não é fornecido prontamente, portanto, uma implementação codificada manualmente de uma técnica de pool simples foi usada no Serviço de Loja Online.

Desempenho

Column chart showing online Store Service performance

Conectando-se a serviços TCP de back-end sem pool de canais, o serviço WF tem um impacto de 17,2% na taxa de transferência. Com o pool de canais, a penalidade é de cerca de 23,8%. Para HTTP, o impacto é muito menor: 4,3% sem pooling e 8,1% com pooling. Também é importante notar que o pool de canais fornece muito pouco benefício ao usar HTTP.

Embora haja sobrecarga do tempo de execução do WF4 em comparação com um serviço WCF codificado manualmente neste teste, ele pode ser considerado o pior cenário. Os dois serviços de back-end neste teste fazem muito pouco trabalho. Em um cenário real de ponta a ponta, esses serviços executariam operações mais caras, como chamadas de banco de dados, tornando o impacto no desempenho da camada de transporte menos importante. Isso somado aos benefícios dos recursos disponíveis no WF4 torna o Workflow Foundation uma escolha viável para a criação de serviços de orquestração.

Principais considerações de desempenho

As áreas de recursos nesta seção, com exceção da interoperabilidade, mudaram drasticamente entre WF3 e WF4. Isso afeta o design de aplicativos de fluxo de trabalho, bem como o desempenho.

Latência de ativação do fluxo de trabalho

Em um aplicativo de serviço de fluxo de trabalho WCF, a latência para iniciar um novo fluxo de trabalho ou carregar um fluxo de trabalho existente é importante, pois pode estar bloqueando. Este caso de teste mede um host XOML WF3 em relação a um host XAMLX WF4 em um cenário típico.

Configuração do Ambiente

Environment setup for latency and throughput tests

Configuração de teste

No cenário, um computador cliente contata um serviço de fluxo de trabalho WCF usando correlação baseada em contexto. A correlação de contexto requer uma ligação de contexto especial e usa um cabeçalho de contexto ou cookie para relacionar mensagens à instância de fluxo de trabalho correta. Ele tem um benefício de desempenho na medida em que o ID de correlação está localizado no cabeçalho da mensagem para que o corpo da mensagem não precise ser analisado.

O serviço criará um novo fluxo de trabalho com a solicitação e enviará uma resposta imediata para que a medição da latência não inclua o tempo gasto na execução do fluxo de trabalho. O fluxo de trabalho WF3 é XOML com um code-behind e o fluxo de trabalho WF4 é totalmente XAML. O fluxo de trabalho WF4 tem esta aparência:

WF4 Correlation Scope workflow

A Receive atividade cria a instância do fluxo de trabalho. Um valor passado na mensagem recebida é ecoado na mensagem de resposta. Uma sequência após a resposta contém o restante do fluxo de trabalho. No caso acima, apenas uma atividade de comentário é mostrada. O número de atividades de comentário é alterado para simular a complexidade do fluxo de trabalho. Uma atividade de comentário é equivalente a um WF3 CodeActivity que não executa nenhum trabalho. Para obter mais informações sobre a atividade de comentário, consulte a seção "Comparação de desempenho no nível do componente" anteriormente neste artigo.

Test Results

Latência fria e quente para serviços de fluxo de trabalho WCF:

Column chart showing cold and warm latency for WCF workflow services using WF3 and WF4

No gráfico anterior, cold refere-se ao caso em que não existe um fluxo de trabalho dado WorkflowServiceHost . Em outras palavras, latência fria é quando o fluxo de trabalho está sendo usado pela primeira vez e o XOML ou XAML precisa ser compilado. A latência quente é o momento de criar uma nova instância de fluxo de trabalho quando o tipo de fluxo de trabalho já tiver sido compilado. A complexidade do fluxo de trabalho faz muito pouca diferença no caso WF4, mas tem uma progressão linear no caso WF3.

Taxa de transferência de correlação

O WF4 introduz um novo recurso de correlação baseado em conteúdo. WF3 forneceu apenas correlação baseada no contexto. A correlação baseada no contexto só pode ser feita em ligações de canal WCF específicas. A ID do fluxo de trabalho é inserida no cabeçalho da mensagem ao usar essas associações. O tempo de execução do WF3 só podia identificar um fluxo de trabalho por sua Id. Com a correlação baseada em conteúdo, o autor do fluxo de trabalho pode criar uma chave de correlação a partir de uma parte relevante de dados, como um número de conta ou ID do cliente.

A correlação baseada no contexto tem uma vantagem de desempenho na medida em que a chave de correlação está localizada no cabeçalho da mensagem. A chave pode ser lida a partir da mensagem sem desserialização/cópia de mensagem. Na correlação baseada em conteúdo, a chave de correlação é armazenada no corpo da mensagem. Uma expressão XPath é usada para localizar a chave. O custo desse processamento extra depende do tamanho da mensagem, da profundidade da chave no corpo e do número de chaves. Este teste compara a correlação baseada em contexto e conteúdo e também mostra a degradação do desempenho ao usar várias chaves.

Configuração do Ambiente

Environment setup for workflow performance test

Configuração de teste

Correlation Throughput Workflow Test

O fluxo de trabalho anterior é o mesmo usado na seção Persistência . Para os testes de correlação sem persistência, não há nenhum provedor de persistência instalado no tempo de execução. A correlação ocorre em dois locais: CreateOrder e CompleteOrder.

Test Results

Correlation Throughput

Este gráfico mostra uma diminuição no desempenho à medida que o número de chaves usadas na correlação baseada em conteúdo aumenta. A semelhança nas curvas entre TCP e HTTP indica a sobrecarga associada a esses protocolos.

Correlação com a persistência

Com um fluxo de trabalho persistente, a pressão da CPU da correlação baseada em conteúdo muda do tempo de execução do fluxo de trabalho para o banco de dados SQL. Os procedimentos armazenados no provedor de persistência SQL fazem o trabalho de correspondência das chaves para localizar o fluxo de trabalho apropriado.

Line chart showing correlation and persistence results

A correlação baseada no contexto ainda é mais rápida do que a correlação baseada no conteúdo. No entanto, a diferença é menos pronunciada, pois a persistência tem mais impacto no desempenho do que a correlação.

Taxa de transferência complexa do fluxo de trabalho

A complexidade de um fluxo de trabalho não é medida apenas pelo número de atividades. As atividades compostas podem conter muitas crianças e essas crianças também podem ser atividades compostas. À medida que o número de níveis de aninhamento aumenta, aumenta também o número de atividades que podem estar atualmente no estado de execução e o número de variáveis que podem estar no estado. Este teste compara a taxa de transferência entre WF3 e WF4 ao executar fluxos de trabalho complexos.

Configuração de teste

Esses testes foram executados em um computador Intel Xeon X5355 @ 2.66GHz 4-way com 4GB de RAM executando o Windows Server 2008 x64. O código de teste é executado em um único processo com um thread por núcleo para atingir 100% de utilização da CPU.

Os fluxos de trabalho gerados para este teste têm duas variáveis principais: profundidade e número de atividades em cada sequência. Cada nível de profundidade inclui uma atividade paralela, enquanto loop, decisões, atribuições e sequências. No designer WF4 mostrado abaixo, o fluxograma de nível superior é retratado. Cada atividade de fluxograma se assemelha ao fluxograma principal. Pode ser útil pensar em um fractal ao imaginar este fluxo de trabalho, onde a profundidade é limitada aos parâmetros do teste.

O número de atividades em um determinado teste é determinado pela profundidade e número de atividades por sequência. A equação a seguir calcula o número de atividades no teste WF4:

Equation to compute number of activities

A contagem de atividade do teste WF3 pode ser calculada com uma equação ligeiramente diferente devido a uma sequência extra:

Equation to compute number of WF3 activities

Onde d é a profundidade e a é o número de atividades por sequência. A lógica por trás dessas equações é que a primeira constante, multiplicada por a, é o número de sequências e a segunda constante é o número estático de atividades no nível atual. Há três atividades filhas de fluxograma em cada fluxograma. No nível de profundidade inferior, esses fluxogramas estão vazios, mas nos outros níveis são cópias do fluxograma principal. O número de atividades na definição de fluxo de trabalho de cada variação de teste é indicado na tabela a seguir:

A table that shows the number of activities used in each test

O número de atividades na definição do fluxo de trabalho aumenta acentuadamente a cada nível de profundidade. Mas apenas um caminho por ponto de decisão é executado em uma determinada instância de fluxo de trabalho, portanto, apenas um pequeno subconjunto das atividades reais é executado.

Flowchart of the complex throughput workflow

Um fluxo de trabalho equivalente foi criado para WF3. O designer WF3 mostra todo o fluxo de trabalho na área de design em vez de aninhamento, portanto, é muito grande para ser exibido neste tópico. Um trecho do fluxo de trabalho é mostrado abaixo.

Flowchart snippet of the WF3 workflow

Para exercitar o aninhamento em um caso extremo, outro fluxo de trabalho que faz parte deste teste usa 100 sequências aninhadas. Na sequência mais interna é um único Comment ou CodeActivity.

Flowchart of a nested sequence

O rastreamento e a persistência não são usados como parte deste teste.

Test Results

Column chart showing throughput performance results

Mesmo com fluxos de trabalho complexos com muita profundidade e um alto número de atividades, os resultados de desempenho são consistentes com outros números de taxa de transferência mostrados anteriormente neste artigo. A taxa de transferência do WF4 é ordens de grandeza mais rápidas e tem de ser comparada numa escala logarítmica.

Memória

A sobrecarga de memória do Windows Workflow Foundation é medida em duas áreas principais: complexidade do fluxo de trabalho e número de definições de fluxo de trabalho. As medições de memória foram feitas em uma estação de trabalho Windows 7 de 64 bits. Há muitas maneiras de obter a medição do tamanho do conjunto de trabalho, como monitorar contadores de desempenho, sondar Environment.WorkingSet ou usar uma ferramenta como o VMMap disponível no VMMap. Uma combinação de métodos foi utilizada para obter e verificar os resultados de cada teste.

Teste de complexidade do fluxo de trabalho

O teste de complexidade do fluxo de trabalho mede a diferença do conjunto de trabalho com base na complexidade do fluxo de trabalho. Além dos fluxos de trabalho complexos usados na seção anterior, novas variações são adicionadas para cobrir dois casos básicos: um fluxo de trabalho de atividade única e uma sequência com 1000 atividades. Para esses testes, os fluxos de trabalho são inicializados e executados até a conclusão em um único loop serial por um período de um minuto. Cada variação de teste é executada três vezes e os dados registrados são a média dessas três execuções.

Os dois novos testes básicos têm fluxos de trabalho semelhantes aos mostrados abaixo:

Complex workflow for both WF3 and WF4

No fluxo de trabalho WF3 mostrado acima, atividades vazias CodeActivity são usadas. O fluxo de trabalho WF4 acima usa Comment atividades. A Comment atividade foi descrita na seção Comparações de desempenho no nível do componente anteriormente neste artigo.

Column chart showing complex workflow memory usage for WF3 and WF4 workflows

Uma das tendências claras a serem observadas neste gráfico é que o aninhamento tem um impacto relativamente mínimo no uso de memória em WF3 e WF4. O impacto mais significativo na memória vem do número de atividades em um determinado fluxo de trabalho. Dados os dados da sequência 1000, profundidade complexa 5 sequência 5 e profundidade complexa 7 sequência 1 variações, é claro que, à medida que o número de atividades entra nos milhares, o aumento do uso de memória torna-se mais percetível. No caso extremo (profundidade 7 sequência 1) onde há ~ 29K atividades, WF4 está usando quase 79% menos memória do que WF3.

Teste de várias definições de fluxo de trabalho

A medição de memória por definição de fluxo de trabalho é dividida em dois testes diferentes devido às opções disponíveis para hospedar fluxos de trabalho em WF3 e WF4. Os testes são executados de uma maneira diferente do teste de complexidade do fluxo de trabalho, em que um determinado fluxo de trabalho é instância e executado apenas uma vez por definição. Isso ocorre porque a definição do fluxo de trabalho e seu host permanecem na memória durante o tempo de vida do AppDomain. A memória usada pela execução de uma determinada instância de fluxo de trabalho deve ser limpa durante a coleta de lixo. As diretrizes de migração para WF4 contêm informações mais detalhadas sobre as opções de hospedagem. Para obter mais informações, consulte WF Migration Cookbook: Workflow Hosting.

A criação de muitas definições de fluxo de trabalho para um teste de definição de fluxo de trabalho pode ser feita de várias maneiras. Por exemplo, pode-se usar a geração de código para criar um conjunto de 1000 fluxos de trabalho que são idênticos, exceto no nome, e salvar cada um desses fluxos de trabalho em arquivos separados. Essa abordagem foi adotada para o teste hospedado no console. No WF3, a WorkflowRuntime classe foi usada para executar as definições de fluxo de trabalho. WF4 pode usar WorkflowApplication para criar uma única instância de fluxo de trabalho ou usar WorkflowInvoker diretamente para executar a atividade como se fosse uma chamada de método. WorkflowApplication é um host de uma única instância de fluxo de trabalho e tem paridade de recursos mais próxima à WorkflowRuntime que foi usada neste teste.

Ao hospedar fluxos de trabalho no IIS, é possível usar um VirtualPathProvider para criar um novo WorkflowServiceHost em vez de gerar todos os arquivos XAMLX ou XOML. O VirtualPathProvider lida com a solicitação de entrada e responde com um "arquivo virtual" que pode ser carregado a partir de um banco de dados ou, neste caso, gerado na hora. Portanto, é desnecessário criar 1000 arquivos físicos.

As definições de fluxo de trabalho usadas no teste de console eram fluxos de trabalho sequenciais simples com uma única atividade. A única atividade foi um vazio CodeActivity para o caso WF3 e uma Comment atividade para o caso WF4. O caso hospedado no IIS usou fluxos de trabalho que começam ao receber uma mensagem e terminam ao enviar uma resposta:

A imagem a seguir mostra um fluxo de trabalho WF3 com ReceiveActivity e um fluxo de trabalho WF4 com padrão de solicitação/resposta:

Workflow Services in WF3 and WF4

A tabela a seguir mostra o delta no conjunto de trabalho entre uma única definição de fluxo de trabalho e 1001 definições:

Opções de Alojamento WF3 Conjunto de Trabalho Delta WF4 Conjunto de Trabalho Delta
Fluxos de trabalho hospedados pelo aplicativo de console 18 MB 9 MB
Serviços de fluxo de trabalho hospedados pelo IIS 446 MB 364 MB

Hospedar definições de fluxo de trabalho no IIS consome muito mais memória devido aos WorkflowServiceHostartefatos de serviço WCF detalhados e à lógica de processamento de mensagens associada ao host.

Para hospedagem de console no WF3, os fluxos de trabalho foram implementados em código em vez de XOML. Em WF4, o padrão é usar XAML. O XAML é armazenado como um recurso incorporado no assembly e compilado durante o tempo de execução para fornecer a implementação do fluxo de trabalho. Há alguma sobrecarga associada a este processo. Para fazer uma comparação justa entre WF3 e WF4, fluxos de trabalho codificados foram usados em vez de XAML. Um exemplo de um dos fluxos de trabalho WF4 é mostrado abaixo:

public class Workflow1 : Activity
{
    protected override Func<Activity> Implementation
    {
        get
        {
            return new Func<Activity>(() =>
            {
                return new Sequence
                {
                    Activities = {
                        new Comment()
                    }
                };
            });
        }
        set
        {
            base.Implementation = value;
        }
    }
}

Existem muitos outros fatores que podem afetar o consumo de memória. O mesmo conselho para todos os programas gerenciados ainda se aplica. Em ambientes hospedados no IIS, o WorkflowServiceHost objeto criado para uma definição de fluxo de trabalho permanece na memória até que o pool de aplicativos seja reciclado. Isso deve ser tido em mente ao escrever extensões. Além disso, é melhor evitar variáveis "globais" (variáveis com escopo para todo o fluxo de trabalho) e limitar o escopo de variáveis sempre que possível.

Serviços de tempo de execução do fluxo de trabalho

Persistência

WF3 e WF4 são fornecidos com um provedor de persistência SQL. O provedor de persistência SQL WF3 é uma implementação simples que serializa a instância do fluxo de trabalho e a armazena em um blob. Por esse motivo, o desempenho desse provedor depende muito do tamanho da instância do fluxo de trabalho. No WF3, o tamanho da instância pode aumentar por vários motivos, como é discutido anteriormente neste artigo. Muitos clientes optam por não usar o provedor de persistência SQL padrão porque armazenar uma instância serializada em um banco de dados não dá visibilidade ao estado do fluxo de trabalho. Para encontrar um fluxo de trabalho específico sem saber a ID do fluxo de trabalho, seria necessário desserializar cada instância persistente e examinar o conteúdo. Muitos desenvolvedores preferem escrever seus próprios provedores de persistência para superar esse obstáculo.

O provedor de persistência WF4 SQL tentou resolver algumas dessas preocupações. As tabelas de persistência expõem determinadas informações, como os marcadores ativos e as propriedades promocionais. O novo recurso de correlação baseada em conteúdo no WF4 não teria um bom desempenho usando a abordagem de persistência SQL do WF3, que gerou algumas mudanças na organização da instância de fluxo de trabalho persistente. Isso torna o trabalho do provedor de persistência mais complexo e sobrecarrega o banco de dados.

Configuração do Ambiente

Environment setup for workflow performance test

Configuração de teste

Mesmo com um conjunto de recursos aprimorado e melhor manipulação de simultaneidade, o provedor de persistência SQL no WF4 é mais rápido do que o provedor no WF3. Para mostrar isso, dois fluxos de trabalho que executam essencialmente as mesmas operações em WF3 e WF4 são comparados abaixo.

Persistence workflow in WF3 on left and WF4 on right

Os dois fluxos de trabalho são criados por uma mensagem recebida. Depois de enviar uma resposta inicial, o fluxo de trabalho é mantido. No caso WF3, um vazio TransactionScopeActivity é usado para iniciar a persistência. O mesmo poderia ser alcançado no WF3 marcando uma atividade como "persistir no fechamento". Uma segunda mensagem correlacionada completa o fluxo de trabalho. Os fluxos de trabalho são persistentes, mas não descarregados.

Test Results

Column chart showing throughput persistence

Quando o transporte entre o cliente e a camada intermediária é HTTP, a persistência no WF4 mostra uma melhoria de 2,6 vezes. O transporte TCP aumenta esse fator para 3,0 vezes. Em todos os casos, a utilização da CPU na camada intermediária é de 98% ou mais. A razão pela qual a taxa de transferência do WF4 é maior é devido ao tempo de execução mais rápido do fluxo de trabalho. O tamanho da instância serializada é baixo para ambos os casos e não é um elemento contribuinte importante nessa situação.

Os fluxos de trabalho WF3 e WF4 neste teste usam uma atividade para indicar explicitamente quando a persistência deve ocorrer. Isso tem o benefício de persistir o fluxo de trabalho sem descarregá-lo. No WF3, também é possível persistir usando o TimeToUnload recurso, mas isso descarrega a instância do fluxo de trabalho da memória. Se um desenvolvedor que usa o WF3 quiser garantir que um fluxo de trabalho persista em determinados pontos, ele terá que alterar a definição do fluxo de trabalho ou pagar o custo para descarregar e recarregar a instância do fluxo de trabalho. Um novo recurso no WF4 torna possível persistir sem descarregar: TimeToPersist. Esse recurso permite que a instância do fluxo de trabalho persista ociosa, mas permaneça na memória até que o limite seja atingido ou a TimeToUnload execução seja retomada.

Observe que o provedor de persistência WF4 SQL executa mais trabalho na camada de banco de dados. O banco de dados SQL pode se tornar um gargalo, por isso é importante monitorar o uso da CPU e do disco lá. Certifique-se de incluir os seguintes contadores de desempenho do banco de dados SQL ao testar aplicativos de fluxo de trabalho:

  • PhysicalDisk\%Tempo de leitura do disco

  • PhysicalDisk\% Tempo de disco

  • PhysicalDisk\% Tempo de gravação em disco

  • PhysicalDisk\% Comprimento médio da fila de disco

  • PhysicalDisk\Comprimento médio da fila de leitura de disco

  • PhysicalDisk\Comprimento médio da fila de gravação de disco

  • PhysicalDisk\Comprimento da fila de disco atual

  • Informações do processador\% Tempo do processador

  • SQLServer:Travas\Tempo médio de espera da trava (ms)

  • SQLServer:Travas\Trava Espera/s

Monitorização

O acompanhamento do fluxo de trabalho pode ser usado para acompanhar o progresso de um fluxo de trabalho. As informações incluídas nos eventos de rastreamento são determinadas por um perfil de rastreamento. Quanto mais complexo for o perfil de rastreamento, mais caro se torna o rastreamento.

WF3 fornecido com um serviço de rastreamento baseado em SQL. Este serviço pode funcionar em lotes e sem lotes. No modo sem lotes, os eventos de rastreamento são gravados diretamente no banco de dados. No modo em lote, os eventos de rastreamento são coletados no mesmo lote que o estado da instância do fluxo de trabalho. O modo em lote tem o melhor desempenho para a maior variedade de designs de fluxo de trabalho. No entanto, o processamento em lote pode ter um impacto negativo no desempenho se o fluxo de trabalho executar muitas atividades sem persistir e essas atividades forem rastreadas. Isso normalmente aconteceria em loops e a melhor maneira de evitar esse cenário é projetar loops grandes para conter um ponto de persistência. Introduzir um ponto de persistência em um loop também pode afetar negativamente o desempenho, por isso é importante medir os custos de cada um e chegar a um equilíbrio.

O WF4 não é fornecido com um serviço de rastreamento SQL. A gravação de informações de controle em um banco de dados SQL pode ser tratada melhor a partir de um servidor de aplicativos em vez de incorporada ao .NET Framework. Portanto, o acompanhamento SQL agora é tratado pelo AppFabric. O provedor de rastreamento pronto para uso no WF4 é baseado no Rastreamento de Eventos para Windows (ETW).

O ETW é um sistema de eventos de baixa latência de nível kernel integrado ao Windows. Utiliza um modelo de fornecedor/consumidor que só permite incorrer na penalização pelo rastreio de eventos quando existe efetivamente um consumidor. Além de eventos do kernel, como processador, disco, memória e uso de rede, muitos aplicativos também aproveitam o ETW. Os eventos ETW são mais poderosos do que os contadores de desempenho, pois os eventos podem ser personalizados para o aplicativo. Um evento pode conter texto, como um ID de fluxo de trabalho ou uma mensagem informativa. Além disso, os eventos são categorizados com máscaras de bits para que o consumo de um determinado subconjunto de eventos tenha menos impacto no desempenho do que a captura de todos os eventos.

Os benefícios da abordagem de usar ETW para rastreamento em vez de SQL incluem:

  • A coleta de eventos de rastreamento pode ser separada para outro processo. Isto dá maior flexibilidade na forma como os eventos são registados.

  • Os eventos de rastreamento ETW são facilmente combinados com os eventos ETW do WCF ou outros provedores de ETW, como um provedor do SQL Server ou do kernel.

  • Os autores do fluxo de trabalho não precisam alterar um fluxo de trabalho para trabalhar melhor com uma implementação de rastreamento específica, como o modo em lote do serviço de rastreamento SQL WF3.

  • Um administrador pode ativar ou desativar o rastreamento sem reciclar o processo do host.

Os benefícios de desempenho para o rastreamento ETW vêm com uma desvantagem. Os eventos ETW podem ser perdidos se o sistema estiver sob intensa pressão de recursos. O processamento de eventos não se destina a bloquear a execução normal do programa e, portanto, não é garantido que todos os eventos ETW serão transmitidos para seus assinantes. Isso torna o rastreamento ETW ótimo para monitoramento de integridade, mas não adequado para auditoria.

Enquanto o WF4 não tem um provedor de rastreamento SQL, o AppFabric tem. A abordagem de controle SQL do AppFabric é assinar eventos ETW com um Serviço do Windows que agrupa os eventos em lote e os grava em uma tabela SQL projetada para inserções rápidas. Um trabalho separado drena os dados dessa tabela e os transforma em tabelas de relatórios que podem ser exibidas no painel do AppFabric. Isso significa que um lote de eventos de rastreamento é manipulado independentemente do fluxo de trabalho de onde veio e, portanto, não precisa esperar por um ponto de persistência antes de ser gravado.

Os eventos ETW podem ser gravados com ferramentas como logman ou xperf. O arquivo ETL compacto pode ser visualizado com uma ferramenta como xperfview ou convertido para um formato mais legível, como XML, com tracerpt. No WF3, a única opção para obter eventos de controle sem um banco de dados SQL é criar um serviço de controle personalizado. Para obter mais informações sobre o ETW, consulte Serviços WCF e Rastreamento de Eventos para Windows e Rastreamento de Eventos - Aplicativos do Windows.

Habilitar o acompanhamento do fluxo de trabalho afetará o desempenho em diferentes graus. O benchmark abaixo usa a ferramenta logman para consumir os eventos de rastreamento ETW e gravá-los em um arquivo ETL. O custo do acompanhamento SQL no AppFabric não está no escopo deste artigo. O perfil de acompanhamento básico, também usado no AppFabric, é mostrado neste benchmark. Também está incluído o custo de rastrear apenas eventos de monitoramento de integridade. Esses eventos são úteis para solucionar problemas e determinar a taxa de transferência média do sistema.

Configuração do Ambiente

Environment setup for workflow performance test

Test Results

Column chart showing workflow tracking costs

O monitoramento de integridade tem um impacto de aproximadamente 3% no rendimento. O custo do perfil básico é de cerca de 8%.

Interoperabilidade

WF4 é quase uma reescrita completa do WF e, portanto, fluxos de trabalho e atividades WF3 não são diretamente compatíveis com WF4. Muitos clientes que adotaram o Windows Workflow Foundation antecipadamente terão definições de fluxo de trabalho internas ou de terceiros e atividades personalizadas para o WF3. Uma maneira de facilitar a transição para WF4 é usar a atividade Interop, que pode executar atividades WF3 de dentro de um fluxo de trabalho WF4. Recomenda-se que a Interop atividade só seja utilizada quando necessário. Para obter mais informações sobre como migrar para o WF4, consulte as Diretrizes de migração do WF4.

Configuração do Ambiente

Environment setup for workflow performance test

Test Results

A tabela a seguir mostra os resultados da execução de um fluxo de trabalho contendo cinco atividades em uma sequência em várias configurações.

Teste Taxa de transferência (fluxos de trabalho/seg)
Sequência WF3 em tempo de execução WF3 1,576
Sequência WF3 em tempo de execução WF4 usando Interop 2,745
Sequência WF4 153,582

Há um aumento notável de desempenho no uso do Interop em relação ao WF3 reto. No entanto, quando comparado com as atividades do WF4, o aumento é insignificante.

Resumo

Os pesados investimentos em desempenho para a WF4 valeram a pena em muitas áreas cruciais. O desempenho de componentes de fluxo de trabalho individuais é, em alguns casos, centenas de vezes mais rápido no WF4 em comparação com o WF3 devido a um tempo de execução do WF mais enxuto. Os números de latência também são significativamente melhores. Isso significa que a penalidade de desempenho por usar o WF em oposição aos serviços de orquestração do WCF de codificação manual é muito pequena, considerando os benefícios adicionais do uso do WF. O desempenho de persistência aumentou por um fator de 2,5 - 3,0. O monitoramento da integridade por meio do rastreamento do fluxo de trabalho agora tem muito pouca sobrecarga. Um conjunto abrangente de guias de migração está disponível para aqueles que estão considerando mudar de WF3 para WF4. Tudo isso deve tornar o WF4 uma opção atraente para escrever aplicações complexas.