Dez principais maneiras de melhorar o desempenho de aplicativos ASP.Net
Autor:Eve Cole
Data da Última Atualização:2009-06-30 15:49:49
Este artigo discute:
Mitos comumente contados sobre como melhorar o desempenho de aplicativos asp.net Dicas úteis para melhorar o desempenho de aplicativos asp.net
Recomendações para operar bancos de dados com aplicações Asp.net
Cache e processamento em segundo plano no Asp.net
Hoje em dia, escrever uma aplicação web ASP.NET tornou-se muito simples e muitos programadores não estão dispostos a perder tempo construindo uma aplicação com bom desempenho. Este artigo discutirá as dez principais maneiras de melhorar o desempenho de aplicativos da web. Não limitarei minha discussão apenas a aplicativos ASP.NET, pois eles são apenas um subconjunto de aplicativos Web. Este artigo também não pode fornecer um guia completo para melhorar o desempenho de aplicativos da web, pois isso exigiria o tamanho de um livro. Este artigo fornece apenas um bom ponto de partida para melhorar o desempenho de aplicativos web. (Só falta estudar devagar sozinhos).
Fora do trabalho, costumo praticar escalada. Antes de cada escalada, revisarei o mapa da rota da escalada e lerei os conselhos de alpinistas anteriores bem-sucedidos. Porque precisamos de sua experiência de sucesso. Da mesma forma, quando você precisa modificar um programa com problemas de desempenho ou desenvolver um site de alto desempenho, também precisa aprender a escrever uma aplicação web de alto desempenho.
Minha experiência pessoal vem principalmente de trabalhar como gerente de programas no grupo asp.net da Microsoft, executando e gerenciando o site www.asp.net e auxiliando no desenvolvimento do Community Server (que é uma versão integrada e atualizada dos Fóruns asp.net , .Text e software nGallery). Acho que essas experiências podem me ajudar.
Você pode pensar em dividir seu aplicativo em diferentes camadas lógicas. Você também deve ter ouvido falar de arquitetura física de três camadas ou arquitetura de N camadas, que é o modelo de arquitetura mais comumente usado. Ela atribui fisicamente diferentes funções de programa a vários hardwares para execução. Desta forma, se quisermos melhorar o desempenho da aplicação, adicionar algum hardware pode atingir o objetivo. É lógico que este método pode melhorar o desempenho do aplicativo, mas devemos evitar usá-lo. Portanto, sempre que possível, devemos colocar a página ASP.NET e os componentes que ela utiliza em uma aplicação.
Devido à implantação distribuída e ao uso de serviços da Web ou comunicação remota, isso reduzirá o desempenho do aplicativo em 20% ou mais.
A camada de dados é um pouco diferente. É melhor implantá-la de forma independente e usar um hardware separado para executá-la. Apesar disso, o banco de dados ainda é o gargalo do desempenho da aplicação. Portanto, quando você deseja otimizar seu programa, o primeiro lugar que vem à mente deve ser a otimização da camada de dados.
Antes de modificar uma área do seu aplicativo que está causando problemas de desempenho, você vai querer ter certeza de que o programa que está causando o problema parece apertado. Os perfis de desempenho são muito úteis para descobrir onde está demorando em seu aplicativo. São lugares que não podemos sentir intuitivamente.
Este artigo discute dois tipos de otimizações de desempenho: uma é a grande otimização de desempenho (grande otimização), como o uso do cache do asp.net, a outra é a pequena otimização de desempenho (pequena otimização). Às vezes, pequenas otimizações de desempenho podem ser muito úteis. Você faz uma pequena alteração no seu código e o chama mil ou dez mil vezes por vez. Faça uma grande otimização de desempenho e você verá uma grande melhoria na velocidade da sua aplicação. Uma pequena otimização de desempenho pode melhorar apenas um microssegundo por solicitação, mas se o número de solicitações por dia for grande, a aplicação terá uma melhoria significativa de desempenho.
Desempenho da camada de dados
Quando você deseja otimizar o desempenho de uma aplicação, você pode trabalhar na seguinte ordem: Seu código precisa acessar o banco de dados? Se sim, com que frequência o banco de dados deve ser acessado? Da mesma forma, este método de teste também pode ser usado em código de programa que usa serviços da web ou comunicação remota. Este artigo não discutirá a questão da otimização de programas usando serviços da Web e comunicação remota.
Se houver uma solicitação em seu código que deve acessar o banco de dados e você vir um código que implementa a mesma função em outro lugar, será necessário otimizá-lo primeiro. Modifique, melhore e continue testando. A menos que você tenha um problema de desempenho muito grande, seu tempo será melhor gasto na otimização de consultas, na conexão ao banco de dados, no retorno do tamanho do conjunto de dados e no tempo que leva para retornar uma consulta.
Com base no resumo da experiência, vamos dar uma olhada em dez experiências que podem ajudá-lo a melhorar o desempenho da sua aplicação. Vou explicá-las da maior para a menor em termos de quanto elas melhoram a eficiência.
1. Retorne vários conjuntos de dados
Verifique seu código de acesso ao banco de dados para ver se há alguma solicitação que retorna diversas vezes. Cada viagem de ida e volta reduz o número de solicitações por segundo às quais seu aplicativo pode responder. Ao retornar vários conjuntos de resultados em uma única solicitação de banco de dados, você reduz o tempo necessário para se comunicar com o banco de dados, torna seu sistema escalonável e reduz a carga de trabalho no servidor de banco de dados para responder às solicitações.
Se você estiver usando instruções SQL dinâmicas para retornar vários conjuntos de dados, recomendo usar procedimentos armazenados em vez de instruções SQL dinâmicas. Escrever lógica de negócios em procedimentos armazenados é um pouco controverso. Mas acho que escrever lógica de negócios em procedimentos armazenados pode limitar o tamanho do conjunto de resultados retornado, reduzir o tráfego de dados da rede e eliminar a necessidade de filtrar dados na camada lógica.
Use o método ExecuteReader do objeto SqlCommand para retornar um objeto de negócios com rigidez de tipos e, em seguida, chame o método NextResult para mover o ponteiro do conjunto de dados para localizar o conjunto de dados. O Exemplo 1 demonstra um exemplo de retorno de vários objetos de tipo forte ArrayList. Retornar apenas os dados necessários do banco de dados pode reduzir bastante o consumo de memória do seu servidor.
2. Paginação dos dados
ASP. O DataGrid da NET possui um recurso muito útil: paginação. Se o DataGrid permitir paginação, ele só fará o download dos dados de uma determinada página em um determinado momento. Além disso, possui uma barra de navegação para paginação de dados, que permite optar por navegar em uma determinada página, e baixar apenas uma página. dados por vez.
Mas tem uma pequena desvantagem, ou seja, você deve vincular todos os dados ao DataGrid. Em outras palavras, sua camada de dados deve retornar todos os dados e, em seguida, o DataGrid filtra os dados exigidos pela página atual e os exibe. Se houver um conjunto de resultados de 10.000 registros que precisam ser paginados usando o DataGrid, assumindo que o DataGrid exibe apenas 25 dados por página, isso significa que 9.975 dados serão descartados em cada solicitação. Cada solicitação deve retornar um grande conjunto de dados, o que tem um enorme impacto no desempenho do aplicativo.
Uma boa solução é escrever um procedimento armazenado de paginação. O exemplo 2 é um procedimento armazenado de paginação para a tabela de pedidos do banco de dados Northwind. Você só precisa passar o número da página atual e o número de itens exibidos em cada página, e o procedimento armazenado retornará os resultados correspondentes.
No lado do servidor, escrevi especialmente um controle de paginação para lidar com a paginação de dados. Aqui, usei o primeiro método e retornei dois conjuntos de resultados em um procedimento armazenado: o número total de registros de dados e o conjunto de resultados necessário.
O número total de registros retornados depende da consulta que está sendo executada. Por exemplo, uma condição where pode limitar o tamanho do conjunto de resultados retornado. Como o número total de páginas deve ser calculado com base no tamanho dos registros do conjunto de dados na interface de paginação, o número de registros no conjunto de resultados deve ser retornado. Por exemplo, se houver 1.000.000 registros no total, se você usar a condição where, poderá filtrar para retornar apenas 1.000 registros. A lógica de paginação do procedimento armazenado deve saber como retornar os dados que precisam ser exibidos.
3. Conjunto de conexões
Usar TCP para conectar seu aplicativo ao banco de dados é caro (e demorado). Os desenvolvedores da Microsoft podem usar pools de conexões para reutilizar conexões de banco de dados. Em vez de usar o TCP para conectar-se ao banco de dados para cada solicitação, o pool de conexões apenas cria uma nova conexão TCP quando não há nenhuma conexão válida. Quando uma conexão é fechada, ela será colocada no pool e ainda manterá uma conexão com o banco de dados, reduzindo assim o número de conexões TCP com o banco de dados.
Claro, você deve prestar atenção às conexões que esqueceu de fechar. Você deve fechá-las imediatamente após cada uso. O que quero enfatizar é: não importa o que digam, o GC (coletor de lixo) no framework .net sempre chamará o método Close ou Dispose do objeto de conexão para fechar explicitamente sua conexão depois que você terminar de usar o objeto de conexão. Não espere que o CLR feche a conexão dentro do tempo que você imagina. Embora o CLR acabe destruindo o objeto e fechando a conexão, não temos certeza de quando ele fará essas coisas.
Para usar a otimização do pool de conexões, existem duas regras: primeiro, abra a conexão, processe os dados e depois feche a conexão. Se você precisar abrir ou fechar a conexão várias vezes por solicitação, é melhor do que abrir uma conexão lateral o tempo todo e passá-la para cada método. Segundo, use a mesma cadeia de conexão (ou o mesmo ID de usuário, ao usar autenticação integrada). Se você não estiver usando a mesma cadeia de conexão, por exemplo, se estiver usando uma cadeia de conexão baseada no usuário conectado, isso não aproveitará os recursos de otimização do pool de conexões. Se você estiver usando argumentos integrados, não poderá aproveitar totalmente a função de otimização do conjunto de conexões porque há muitos usuários. O .NET CLR fornece um contador de desempenho de dados, que é muito útil quando precisamos rastrear as características de desempenho do programa, incluindo o rastreamento do pool de conexões.
Sempre que seu aplicativo se conectar a um recurso em outra máquina, como um banco de dados, você deve se concentrar em otimizar o tempo que leva para se conectar ao recurso, o tempo que leva para receber e enviar dados e o número de vezes que você retorna. . Otimizar cada processo do seu aplicativo é o ponto de partida para melhorar o desempenho do seu aplicativo.
A camada de aplicação contém a lógica para conectar-se à camada de dados, transferir dados para instâncias das classes correspondentes e processar negócios. Por exemplo, no Community Server, você precisa montar uma coleção de Fóruns ou Threads e, em seguida, aplicar a lógica de negócios, como autorização. Mais importante ainda, você precisa concluir a lógica de cache aqui.
4. ASP. API de cache NET
Antes de escrever um aplicativo, a primeira coisa que você precisa fazer é fazer com que o aplicativo maximize o uso dos recursos de cache do ASP.NET.
Se o seu componente for executado em um aplicativo Asp.net, você só precisará referenciar System.Web.dll em seu projeto. Em seguida, utilize a propriedade HttpRuntime.Cache para acessar o Cache (também pode ser acessado através de Page.Cache ou HttpContext.Cache).
Existem várias regras para armazenar dados em cache. Primeiro, os dados podem ser usados com frequência e podem ser armazenados em cache. Em segundo lugar, a frequência de acesso aos dados é muito alta, ou a frequência de acesso de um dado não é alta, mas seu ciclo de vida é muito longo. É melhor armazenar esses dados em cache. O terceiro é um problema que muitas vezes é ignorado. Às vezes, armazenamos muitos dados em cache. Geralmente, em uma máquina X86, se os dados que você deseja armazenar em cache excederem 800M, ocorrerá um erro de estouro de memória. Portanto, o cache é limitado. Em outras palavras, você deve estimar o tamanho do conjunto de cache e limitar o tamanho do conjunto de cache a menos de 10, caso contrário, poderá causar problemas. No Asp.net, se o cache for muito grande, um erro de estouro de memória será relatado, especialmente se um objeto DataSet grande estiver armazenado em cache.
Aqui estão alguns mecanismos de cache importantes que você deve entender. Primeiro, o cache implementa o princípio "usado mais recentemente" (um algoritmo usado menos recentemente). Quando há poucos caches, ele limpará automaticamente os caches inúteis. Em segundo lugar, o princípio das "dependências condicionais" forçou a eliminação (dependências de expiração), as condições podem ser tempo, palavras-chave e arquivos. O tempo como condição é o mais comumente usado. Uma condição mais forte é adicionada no asp.net2.0, que é a condição do banco de dados. Quando os dados no banco de dados são alterados, o cache é forçado a ser limpo. Para uma análise mais aprofundada das dependências condicionais do banco de dados, consulte a coluna Cutting Edge de Dino Esposito na edição de julho de 2004 da MSDN Magazine. A arquitetura de cache do Asp.net é mostrada na figura abaixo:
5. Pré-solicitação de cache
Mencionei anteriormente que mesmo que façamos apenas uma pequena melhoria de desempenho em alguns lugares, podemos obter uma grande melhoria de desempenho. Eu realmente gosto de usar o cache de pré-solicitação para melhorar o desempenho do programa.
Embora a API Cache seja projetada para salvar dados por um determinado período de tempo, o cache de pré-solicitação salva apenas o conteúdo de uma determinada solicitação por um determinado período de tempo. Se a frequência de acesso de uma determinada solicitação for alta, esta solicitação só precisa extrair, aplicar, modificar ou atualizar os dados uma vez. Então a solicitação pode ser pré-armazenada em cache. Vamos dar um exemplo para ilustrar.
No aplicativo CS forum, o controle do servidor de cada página requer dados personalizados para determinar sua aparência, para determinar qual folha de estilo usar e outras coisas personalizadas. Alguns dos dados aqui podem precisar ser salvos por um longo período, mas algumas vezes não. Por exemplo, os dados de skin de um controle só precisam ser aplicados uma vez e podem ser usados o tempo todo.
Para implementar o cache de pré-solicitação, use a classe HttpContext do Asp.net. Uma instância da classe HttpContext é criada em cada solicitação e pode ser acessada por meio da propriedade HttpContext.Current em qualquer lugar durante a solicitação. A classe HttpContext possui uma propriedade de coleção Items e todos os objetos e dados são adicionados a esta coleção e armazenados em cache durante a solicitação. Assim como você usa Cache para armazenar em cache dados acessados com frequência, você pode usar HttpContext.Items para armazenar em cache dados básicos usados em cada solicitação. A lógica por trás disso é simples: adicionamos dados a HttpContext.Items e, em seguida, lemos os dados dele.
6. Processamento em segundo plano
Com o método acima seu aplicativo deve rodar muito rápido, certo? Mas em algum momento, uma tarefa muito demorada pode ser executada em uma solicitação do programa. Como enviar e-mails ou verificar a exatidão dos dados enviados, etc.
Quando integramos o asp.net Forums 1.0 ao CS, descobrimos que enviar uma nova postagem seria muito lento. Cada vez que uma nova postagem é adicionada, o aplicativo deve primeiro verificar se a postagem é duplicada, depois filtrá-la usando o filtro "palavrão", verificar o código do anexo da imagem, indexar a postagem e adicioná-la à fila apropriada, validar. seu anexo e, por fim, enviar o e-mail para a caixa postal do assinante. Obviamente, isso dá muito trabalho.
O resultado é que ele gasta muito tempo indexando e enviando e-mails. A indexação de postagens é uma operação demorada e o envio de e-mails aos assinantes requer conexão com o serviço SMTP e, em seguida, envio de um e-mail para cada assinante, o tempo necessário para enviar e-mails aumentará.
A indexação e o envio de emails não precisam ser acionados a cada solicitação. Idealmente, gostaríamos de processar essas operações em lotes, enviando apenas 25 emails por vez ou todos os novos emails a serem enviados a cada 5 minutos. Decidimos usar o mesmo código do cache do protótipo do banco de dados, mas ele falhou, então tivemos que voltar ao VS.NET 2005.
Encontramos a classe Timer no namespace System.Threading. Esta classe é muito útil, mas poucas pessoas a conhecem, e menos ainda os desenvolvedores web a conhecem. Depois que ele criar uma instância dessa classe, a classe Timer chamará a função de retorno de chamada especificada de um thread no pool de threads a cada horário especificado. Isso significa que seu aplicativo ASP.NET pode ser executado mesmo quando não há solicitações. Esta é a solução a ser tratada posteriormente. Você pode fazer com que o trabalho de indexação e envio de e-mail seja executado em segundo plano, em vez de executá-lo em todas as solicitações.
Existem dois problemas com a tecnologia de execução em segundo plano. O primeiro é que quando o domínio do seu aplicativo for desinstalado, a instância da classe Timer irá parar de funcionar. Ou seja, o método de retorno de chamada não será chamado. Além disso, como existem muitos threads em execução em cada processo do CLR, será difícil para você conseguir um thread para o Timer executá-lo, ou ele conseguirá executá-lo, mas será atrasado. A camada Asp.net deve usar essa técnica o mínimo possível para reduzir o número de threads no processo, ou permitir apenas que as solicitações utilizem uma pequena parte dos threads. Claro, você só pode usá-lo se tiver muito trabalho assíncrono.
Não há espaço suficiente para postar o código aqui. Você pode baixar o programa de exemplo em http://www.rob-howard.net/ . Faça download do programa de exemplo Blackbelt TechEd 2004.
7. Cache de saída de página e serviços de proxy
Asp.net é a sua camada de interface (ou deveria ser), ele contém páginas, controles de usuário, controles de servidor (HttpHandlers e HttpModules) e o conteúdo que eles geram. Se você tiver uma página Asp.net que gera dados HTML, XML, imgae ou outros dados e usar código para gerar o mesmo conteúdo de saída para cada solicitação, será necessário considerar o uso do cache de saída da página.
Você pode fazer isso simplesmente copiando a seguinte linha de código em sua página:
<%@ PageOutputCache VaryByParams=”nenhum” Duração=”60” %>
Você pode usar efetivamente a página gerada na primeira solicitação para gerar o conteúdo em cache e regenerar o conteúdo da página após 60 segundos. Na verdade, essa tecnologia é implementada usando alguma API de cache de baixo nível. Existem vários parâmetros que podem ser configurados para cache de saída de página, como o parâmetro VaryByParams mencionado acima. Este parâmetro indica quando acionar condições de nova saída. Você também pode especificar o cache de saída no modo de solicitação Http Get ou Http Post. Por exemplo, quando definimos este parâmetro como VaryByParams="Report", a saída solicitada por default.aspx?Report=1 ou default.aspx?Report=2 será armazenada em cache. O valor de um parâmetro pode ser vários parâmetros separados por ponto e vírgula.
Muitas pessoas não percebem que, ao usar o cache de saída de página, o ASP.NET também gera um conjunto de cabeçalhos HTTP (cabeçalho HTTP) e o salva no servidor de cache downstream. Essas informações podem ser usadas para segurança da Internet da Microsoft e para acelerar o processo. velocidade de resposta do servidor. Quando o cabeçalho do cache HTTP for redefinido, o conteúdo solicitado será armazenado em cache no recurso de rede. Quando o cliente solicitar o conteúdo novamente, ele não obterá mais o conteúdo do servidor de origem, mas obterá diretamente o conteúdo do cache.
Embora o uso do cache de saída de página não melhore o desempenho do seu aplicativo, ele reduz o número de vezes que o conteúdo da página armazenada em cache é carregado do servidor. Obviamente, isso se limita ao cache de páginas acessíveis a usuários anônimos. Porque depois que a página é armazenada em cache, as operações de autorização não podem mais ser executadas.
8. Use o cache do kernel do IIS6.0
Se o seu aplicativo não estiver sendo executado no IIS 6.0 (Windows Server 2003), você terá perdido algumas ótimas maneiras de melhorar o desempenho do aplicativo. No sétimo método, falei sobre como usar o cache de saída de página para melhorar o desempenho do aplicativo. No IIS5.0, quando uma solicitação chega ao IIS, o IIS a transfere para o asp.net. Quando o cache de saída da página é aplicado, o HttpHandler no ASP.NET receberá a solicitação e o HttpHandler transferirá o conteúdo do cache. Retire e devolva.
Se você estiver usando o IIS6.0, ele possui um recurso muito bom chamado Kernel Caching e você não precisa modificar nenhum código no programa asp.net. Quando o asp.net recebe uma solicitação em cache, o cache do kernel do IIS obterá uma cópia dela do cache. Quando uma solicitação vem da rede, a camada Kernel receberá a solicitação. Se a solicitação for armazenada em cache, ela retornará diretamente os dados armazenados em cache e pronto. Isso significa que ao usar o cache do kernel do IIS para armazenar em cache a saída da página, você obterá melhorias de desempenho incríveis. Ao desenvolver o asp.net para o VS.NET 2005, fui um gerente de programa especificamente responsável pelo desempenho do asp.net. Meus programadores usaram esse método. Analisei todos os dados do relatório diário e encontrei os resultados do uso do cache do modelo do kernel. mais rápido. Uma característica comum deles é que as solicitações e respostas da rede são grandes, mas o IIS ocupa apenas 5% dos recursos da CPU. Isso é incrível. Há muitos motivos para você usar o IIS 6.0, mas o cashing do kernel é o melhor.
9. Compactar dados com Gzip
A menos que o uso da CPU seja muito alto, é necessário utilizar técnicas para melhorar o desempenho do servidor. Usar gzip para compactar dados pode reduzir a quantidade de dados enviados ao servidor, melhorar a velocidade de execução da página e também reduzir o tráfego de rede. A melhor forma de compactar os dados depende dos dados que você deseja enviar e se o navegador do cliente os suporta (o IIS envia dados compactados com gzip para o cliente, e o cliente deve suportar gzip para analisá-los, IE6.0 e Firefox). Dessa forma, seu servidor pode responder a mais solicitações por segundo. Da mesma forma, você também reduz a quantidade de dados enviados na resposta e pode enviar mais solicitações.
Boas notícias, a compactação gzip foi integrada no IIS6.0, é melhor que o gzip no IIS5.0. Infelizmente, para ativar a compactação gzip no IIS 6.0, você não pode defini-la na caixa de diálogo de propriedades do IIS 6.0. A equipe de desenvolvimento do IIS desenvolveu a função de compactação gzip, mas se esqueceu de facilitar aos administradores a habilitação na janela do administrador. Para ativar a compactação gzip, você só pode modificar sua configuração no arquivo de configuração xml do IIS6.0.
Além de ler este artigo, tenho que ler o artigo <<IIS6 Compression>> escrito por Brad Wilson ( http://www.dotnetdevs.com/articles/IIS6compression.aspx ); da compactação aspx. Habilite a compactação ASPX no IIS. Mas esteja ciente de que a compactação dinâmica e o cashing do kernel são mutuamente exclusivos no IIS6.
10. ViewState dos controles do servidor
ViewState é um recurso do asp.net usado para salvar um valor de estado usado para gerar uma página em um campo oculto. Quando a página é postada de volta no servidor, o servidor analisa, verifica e aplica os dados no ViewState para restaurar a árvore de controle da página. ViewState é um recurso muito útil que pode persistir o estado do cliente sem usar cookies ou memória do servidor. A maioria dos controles de servidor usa ViewState para persistir os valores de estado dos elementos que interagem com o usuário na página. Por exemplo, para salvar o número da página atual para paginação.
Usar ViewState trará alguns efeitos negativos. Primeiro, aumenta os tempos de resposta e solicitação do servidor. Em segundo lugar, cada postback adiciona tempo para serializar e desserializar os dados. Por fim, também consome mais memória do servidor.
Muitos controles de servidor tendem a usar ViewState, como o conhecido DataGrid, e às vezes não há necessidade de usá-lo. ViewState está habilitado por padrão. Se você não quiser usar ViewState, poderá desativá-lo no nível de controle ou de página. No controle, você só precisa definir a propriedade EnableViewState como False, você também pode configurá-la na página para estender seu escopo para a página inteira:
<%@Página EnableViewState=”falso”%>
Se a página não exigir postback ou se a página for apenas renderizada com controles sempre que for solicitada. Você deve desativar o ViewState no nível da página.
Resumir
Apenas forneço algumas dicas que acredito que ajudarão a melhorar a gravação de aplicativos ASP.NET de alto desempenho. As dicas para melhorar o desempenho do ASP.NET mencionadas neste artigo são apenas um ponto de partida. Livro "Desempenho" da NET. Somente através da sua própria prática você poderá encontrar as técnicas que serão mais úteis para o seu projeto. No entanto, essas dicas podem servir de guia em sua jornada de desenvolvimento. No desenvolvimento de software, nada disso é absolutamente útil porque cada projeto é diferente.