Estamos lidando com um problema interessante no StackOverflow.
Temos um monte de pequenas tarefas "precisam ser feitas em breve". Um exemplo está atualizando as listas "Perguntas relacionadas". O que fizemos no passado é retroceder essas tarefas nas cargas de página de alguns usuários.
Isso nunca foi o ideal, mas não era realmente perceptível. Agora que o SO ultrapassou os 1.000.000 pontos de interrogação, esses infelizes usuários estão começando a sentir isso.
A solução natural é realmente colocar essas tarefas em segundo plano. Estou pensando em duas maneiras amplas de fazer isso.
1. No IIS como um Thread-Pool / Work-Queue personalizado
Basicamente, criamos alguns threads (não ThreadPool , para não interferir no IIS) e os serviços de algumas coleções nas quais estamos inserindo Funcs .
O grande profissional aqui é a simplicidade. Não precisamos nos preocupar em organizar nada, nem precisamos garantir que algum serviço externo esteja pronto e respondendo.
Também temos acesso a todo o nosso código comum.
O golpe é, bem, que não devemos usar threads de segundo plano. As objeções que eu conheço estão todas centradas no IIS faminto (se você usa o ThreadPool) e os threads morrem aleatoriamente (devido à reciclagem do AppPool).
Temos a infraestrutura existente para tornar a morte aleatória do encadeamento um problema (é possível detectar uma tarefa foi basicamente abandonada) e limitar o número de encadeamentos (e usar encadeamentos que não sejam do ThreadPool) também não é difícil.
Movido para StackOverflow , pois não foi realmente abordado aqui.
2. Como serviço
Alguma solução de terceiros ou uma solução personalizada.
Basicamente, organizávamos uma tarefa através do limite do processo para algum serviço e simplesmente a esquecíamos. Presumivelmente, estamos vinculando algum código ou restritos ao SQL bruto + uma cadeia de conexão.
O profissional é que é o "caminho certo" para fazer isso.
Os contras são que somos muito restritos no que podemos fazer ou teremos que elaborar algum sistema para manter esse serviço sincronizado com nossa base de códigos. Também precisamos conectar todo o nosso monitoramento e registro de erros de alguma forma, que obtemos gratuitamente com a opção "No IIS".
Existem outros benefícios ou problemas com a abordagem de serviço?
Em poucas palavras, existem problemas imprevisíveis e intransponíveis que tornam a abordagem nº 1 impraticável? Em caso afirmativo, existem bons serviços de terceiros nos quais devemos procurar a abordagem nº 2?
fonte
Respostas:
Algumas semanas atrás, fiz uma pergunta semelhante no SO. Em uma casca de noz, minha abordagem já há algum tempo foi desenvolver um serviço do Windows. Eu usaria o NServiceBus (essencialmente MSMQ nos bastidores) para reunir solicitações do meu aplicativo da web para o meu serviço. Eu costumava usar o WCF, mas fazer com que uma transação distribuída funcionasse corretamente no WCF sempre parecia uma chatice. O NServiceBus fez o truque, eu poderia confirmar dados e criar tarefas em uma transação e não me preocupar se meu serviço estava funcionando naquele momento. Como um exemplo simples, se eu precisasse enviar um email (por exemplo, um email de registro), criaria a conta do usuário e dispararia um sinal para o meu Serviço Windows (para enviar o email) em uma transação. O manipulador de mensagens no lado do serviço captaria a mensagem e processaria adequadamente.
Desde que o ASP .NET 4.0 e o AppFabric foram lançados, existem várias alternativas viáveis para o mecanismo acima. Voltando à pergunta mencionada acima, agora temos o AppInitialize do AppFabric (via net.pipe) e o recurso Auto-Start do ASP .NET 4.0, que tornam o desenvolvimento do Windows Services como aplicativos da Web uma alternativa viável. Comecei a fazer isso agora por várias razões (a maior delas sendo a implantação não é mais um pé no saco):
Se você seguir esse caminho (perdoe-me por copiar e colar da minha postagem original), eu definitivamente consideraria executar a lógica de segundo plano em um aplicativo Web separado. Existem várias razões para isso:
Fazer isso volta ao aspecto empacotamento. WCF, NServiceBus / RabbitMQ / ActiveMQ etc., MSMQ de baunilha, API RESTful (pense MVC) são todas as opções. Se você estiver usando o Windows Workflow 4.0, poderá expor um ponto de extremidade do host que seu aplicativo Web possa consumir.
A abordagem de hospedagem na web para serviços ainda é relativamente nova para mim, apenas o tempo dirá se foi a escolha correta. Até agora está bom. A propósito, se você não quiser usar o AppFabric (eu não poderia, por algum motivo bizarro, o Windows Server Web Edition não é suportado), o recurso de Inicialização Automática mencionado na publicação do Gu funciona bem. Porém, fique longe do arquivo applicationhost.config, é possível configurar tudo nesse post através do console do IIS (Editor de Configuração no nível do servidor principal).
Nota: Originalmente, eu havia postado mais alguns links nesta mensagem, mas, infelizmente, este é o meu primeiro post nesta troca e apenas um link é suportado! Havia basicamente dois outros, para obter o Google "Death to Windows Services ... Long Live AppFabric!" e "auto-start-asp-net-applications". Me desculpe por isso.
fonte
Na verdade, existe uma terceira maneira no Windows de executar serviços em segundo plano, e isso é muito comum no mundo UNIX. A terceira maneira é um
CRON
trabalho que executa uma parte da sua infraestrutura. No Windows, isso é conhecido comotask scheduler
e é muito comum para executar código de forma programada. Para usar isso, você criaria um aplicativo de linha de comando que é executado em um agendamento predefinido. A vantagem disso é que você não precisa se preocupar se o processo permanecer ativo e funcionando como um serviço, porque, se por algum motivo falhar, será iniciado na próxima vez.Quanto à organização de tarefas específicas, você realmente só precisa armazenar essas tarefas em um armazenamento binário persistente. Até que o aplicativo da linha de comando os retire do armazenamento e os execute. Eu fiz isso no passado usando o banco de dados do Cassandra como um provedor de estado de sessão para preencher tarefas em segundo plano para usuários específicos no banco de dados do Cassandra e depois fazer com que a linha de comando os escolha e execute-os para o usuário.
Essa pode não ter sido a solução típica de empacotamento, mas funcionou muito bem para mim e acabou sendo uma solução muito elegante, porque as tarefas agendadas sobreviveram a desligamentos, problemas de rede e qualquer máquina poderia executar a tarefa, pois estava centralmente armazenado.
Promoção vergonhosa, mas este é o meu projeto e a solução que acabei de detalhar brevemente é por que criei o projeto: http://github.com/managedfusion/fluentcassandra/
fonte
Aplicativo Cron + Web
Esse é um design testado em batalha que se adapta horizontalmente ao seu web farm e garante que você esteja usando a pilha de tecnologias da web que você já conhece.
Veja como funciona:
http://mydomain.com/system/cron
.Viva! Agora você tem uma rota que será chamada a cada 30 segundos. E se a solicitação demorar 5 minutos para processar, ninguém se importará, porque não faz parte da solicitação de página do usuário.
A
cron
ação acaba parecendo muito simples: ele tem uma lista de métodos para executar em uma determinada frequência. Quando uma solicitação chega, ele vê se existe um método que precisa ser executado e chama o método apropriado. Isso significa que você pode controlar o agendamento em seu banco de dados , onde provavelmente já possui muitos outros dados de configuração importantes para o seu site.Mais importante (para você), isso significa que seus trabalhos não precisam ser chamados em um horário fixo. Você pode escrever qualquer lógica que desejar para determinar quando executar um método.
Prós e contras
PrósNota: Se houver alguma dúvida ou preocupação, adicione um comentário . Fico feliz em elaborar.
fonte
Eu tentei e usei praticamente todas as maneiras possíveis de fazer isso no meu aplicativo atual. Comecei a fazer a mesma coisa que você faz atualmente, seguindo uma solicitação do usuário para preencher os dados e depois armazená-los em cache. Percebi que isso também era uma má ideia (especialmente quando você escala em vários servidores da Web, mais usuários sofrem).
Também tive um trabalho agendado que atinge uma URL no aplicativo ASP.NET - esta é uma solução decente, mas começa a quebrar no minuto em que você passa de 1 servidor da web.
Atualmente, eu uso dois métodos diferentes, ambos usando o Quartz.NET, que é uma ótima e pequena biblioteca. O primeiro é o Quartz.NET em execução no ASP.NET, é configurado no global.asax e é executado a cada dois minutos. Eu uso isso para atualizar o cache do ASP.NET fora da banda, que é a única razão pela qual ele é executado como parte do ASP.NET.
A segunda é que eu escrevi uma biblioteca para agrupar o Quartz.NET chamado DaemonMaster - facilita colocar uma DLL em um diretório e executá-lo em um serviço do Windows. Achei que isso ajuda a evitar algumas das partes irritantes do trabalho com um Serviço Windows e também limpa a API do Quartz.NET. Os serviços executados no DaemonMaster são de dois tipos diferentes, o primeiro são trabalhos que precisam ser executados todas as noites ou a cada X minuto. Os outros trabalhos funcionam fora de uma fila com base nos dados provenientes do aplicativo ASP.NET. O aplicativo ASP.NET descarta objetos JSON no RabbitMQ e a pesquisa de serviços RabbitMQ processa os dados.
Com base nisso, sugiro que você use um serviço do Windows (e confira o DaemonMaster) e, se necessário, use uma fila como o RabbitMQ para passar os dados do aplicativo ASP.NET para os serviços - ele funcionou da melhor maneira possível em todas essas soluções . Se você estiver carregando o cache, a execução no ASP.NET faz sentido; caso contrário, acho que não.
fonte
Eu faria da maneira certa e teria um serviço do Windows em execução que monitora uma "fila". Eu digo "fila" porque a programação w / MSMQ é semelhante a furar jogadores quentes em seus olhos.
Eu me apaixonei pela simplicidade do Delayed :: Job in Rails, e algo semelhante poderia ser feito facilmente no .NET.
Basicamente, você adiciona qualquer tipo de
SomethingOperation
(algo que possui umPerform()
método). Em seguida, basta serializar os parâmetros relevantes, dar prioridade a ele, algum tipo de comportamento de nova tentativa padrão e colocá-lo em um banco de dados.Seu serviço apenas monitoraria isso e trabalharia os trabalhos na fila.
fonte
Ficamos muito felizes com a abordagem do Barramento de Serviço / Fila de Mensagens / Serviço. A arquitetura básica é essa.
O site envia mensagem para a fila
O serviço Windows recebe e processa mensagens em seu próprio tempo
A vantagem é que não há atraso para o serviço front-end ao qual os usuários também estão conectados. O serviço do Windows pode ser desligado e atualizado sem interrupção para o site principal. Além disso, é extremamente rápido .
Se você não conseguir armazenar todos os seus dados na mensagem, sempre poderá armazená-los e recuperá-los mais tarde. Sugiro usar um mecanismo de armazenamento de documentos como: RavenDB ou MongoDB, onde é muito simples armazenar suas classes sem alterações.
O site envia mensagem para a fila
O serviço Windows recebe e processa mensagens em seu próprio tempo
Para simplificar, usamos: Rhino ESB e Topshelf . A configuração é extremamente simples e colocar isso em prática para um aplicativo existente provou levar muito pouco tempo.
fonte
Estou curioso para saber por que uma combinação dos dois não é uma opção viável. No momento, você aciona trabalhos nas exibições de página, com alguma seiva infeliz aguardando 10 segundos para que a página seja exibida. Pelo menos essa é a minha compreensão do seu método atual.
No entanto, esses trabalhos estão demorando mais e mais para serem executados à medida que o site cresce, e você não deseja prejudicar a experiência do usuário no site. Nem mesmo para alguns (ou talvez muito) usuários azarados ao longo do dia, agora você está pensando em agendar trabalhos em segundo plano.
Não vejo por que um trabalho em segundo plano executado em intervalos regulares não pode imitar um visitante. Agora não sou programador do Windows, mas no mundo Linux eu configuraria um trabalho cron que é executado em intervalos regulares e teria duas linhas de código.
Combina os profissionais de ambos os sistemas. É feito em segundo plano. Não afeta os usuários. Ele ainda usa uma visualização de página para iniciar o trabalho. Eu já vi essa abordagem usada antes. Tende a ser o meio termo entre os modos simples da antiguidade e os modos mais complexos que aparecem na estrada.
Atualizar
Acho que você pode solucionar o problema de balanceamento de carga executando os executores de tarefas nos próprios servidores da web. O executor de tarefas extrai uma URL da fila de tarefas e a executa da seguinte maneira:
Devido à natureza das filas de tarefas / mensagens, as tarefas serão distribuídas igualmente entre os executores de tarefas, o que significa que a URL especialmente criada é eventualmente distribuída entre os servidores da Web.
fonte
specially_crafted_url
é proveniente de um IP conhecido, você pode adicionar uma regra ao seu balanceador de carga para executar round-robin apenas para solicitações desse IP.Eu acho que o golpe com a abordagem de serviço puro é que você tem código espalhado no serviço e longe do aplicativo principal.
Aqui está o que fizemos com grandes trabalhos em segundo plano, que não são sensíveis ao tempo, que mantêm o código unido e simplificam o serviço:
Ainda mais simples, basta fazer a chamada em um aplicativo de console e usar o Agendador de tarefas ou o VisualCron para transformá-lo em um "serviço".
fonte
Eu gostei do TopShelf. Mantém a simplicidade, mas ainda assim o executa da maneira correta como um serviço do Windows. Basicamente, crie um aplicativo de console, adicione de 15 a 20 linhas de código e ele será instalado como um serviço.
http://code.google.com/p/topshelf/
fonte
Que tal ter um serviço Windows muito simples que é executado no servidor da Web e periodicamente atinge uma URL de manutenção que executa suas tarefas diversas. Faça com que ele reduza a quantidade de trabalho que faz em qualquer solicitação.
fonte
Vou reverter a tendência aparente aqui e sugerir o uso do modelo no IIS. Eu mesmo usei e funciona muito bem. Realmente não é tão difícil implementar uma classe de pool de encadeamentos decente (ao longo dos anos, estendi minha classe de pool de encadeamentos para oferecer suporte à criação e destruição dinâmicas de encadeamentos, nova tentativa de tarefas e assim por diante). As vantagens são:
Na minha opinião, uma solução no IIS é simplesmente o "próximo passo" de pegar o trabalho em exibições de página aleatórias.
fonte
Resque é bom. Ou mesmo Kthxbye, se você precisar ser notificado sobre o valor resultante depois que ele for concluído.
Ambos Redis / Ruby baseados em tho.
Honestamente, se você está adotando uma abordagem baseada em serviços, ela realmente não precisa ser superintegrada à sua plataforma atual, o que eu acho que é uma vantagem. Eu esperava que pudesse ser um sistema de esquecer e executar (com algum tipo de monitoramento) e concluir tarefas. Não tenho certeza de que ele precise ser executado na mesma plataforma, pois apenas atualiza / modifica as informações do banco de dados.
Certamente você poderia se dar bem com muito mais por muito menos se você trabalhasse com esse tipo de trabalho em uma entidade separada, especialmente porque parece que você está lidando com problemas de segmentação. Ambos Resque e kthxbye mover o processamento fora de processos separados para permitir que o SO para lidar com a simultaneidade.
Resque
Kthxbye
fonte
Eu usaria um serviço WCF hospedado pelo WAS ouvindo uma fila do MSMQ.
Pro's
Dispare e esqueça mensagens unidirecionais do aplicativo Web
Limitação e nova tentativa do MSMQ / WCF
Entrega garantida; D
Dead Letter management
Processo de distribuição
Ativação WAS / MSMQ
Con's
Os recursos do MSMQ no WCF tornam o uso do MSMQ muito bom. Sim, você sangrará na configuração, mas os benefícios serão superiores ao sacrifício.
fonte
Eu me deparei com isso algumas vezes ao desenvolver aplicativos da web. Resolvemos isso criando um aplicativo de console do Windows que executa a tarefa e criando uma tarefa agendada que é executada de vez em quando para realmente executar a tarefa.
fonte
Você pode desviar o trabalho para um encadeamento em segundo plano (ou muitos encadeamentos em segundo plano) usando Rx e algo como o seguinte:
Usar:
Hospede tudo isso dentro de uma classe da qual existe apenas um (também conhecido como singleton, mas faça-o corretamente - use seu contêiner de IoC para determinar o estilo de vida).
Você pode controlar o tamanho do conjunto de encadeamentos etc. escrevendo um agendador personalizado no lugar do EventLoopScheduler (que executa um único encadeamento).
fonte
Eu implementei esse tipo de coisa algumas vezes. No Windows, configurei um programa de linha de comando python que faz algo em vários momentos. Este programa também expõe uma interface xmlrpc em uma porta. Em seguida, um trabalho de tarefa agendada é executado a cada minuto e consulta as interfaces xmlrpc. Se eles não estiverem ativos, ele tenta iniciá-los. Se não puder, ele me envia um e-mail.
A vantagem é que o trabalho executado não é cron ou agendado. Eu tenho um trabalho de processo que é executado a cada segundo, mas aguarda mais e mais tempo entre iniciar um novo trabalho, dependendo se ele tem trabalho a ser feito. Além disso, ele pode ser usado para agir de forma inteligente com base no resultado. Tem um erro de 500? Tem um atraso muito longo? Faça outra coisa. Notifique outro serviço. Etc.
E o mesmo sistema funciona em unix, com pequenas modificações.
fonte
Eu não tenho uma resposta para você, mas o problema tocou um sino - lembro-me de alguns caras aleatórios discutindo isso em um podcast uma vez .
fonte
Visão geral da API Java da fila de tarefas
Conceitos de tarefas
No processamento em segundo plano do App Engine, uma tarefa é uma descrição completa de uma pequena unidade de trabalho. Esta descrição consiste em duas partes:
Tarefas como ganchos offline da Web
Felizmente, a Internet já oferece essa solução, na forma de uma solicitação HTTP e sua resposta. A carga útil dos dados é o conteúdo da solicitação HTTP, como variáveis de formulário da web, XML, JSON ou dados binários codificados. A referência do código é o próprio URL; o código real é a lógica que o servidor executa ao preparar a resposta.
fonte
Faz ambos
Adicione um parâmetro opcional ao caminho da pergunta que executa o trabalho que você está pegando carona nas solicitações do usuário:
Manutenção de tarefas em segundo plano em um site grande
Crie um aplicativo de console que seja executado em cada servidor, abra o binário compartilhado do log do IIS e o leia no final atual do arquivo. Use um observador de sistema de arquivos ou um intervalo de tempo para ler a frente e coletar atualizações enquanto o IIS descarregava o log.
Use essas informações para determinar quais páginas foram exibidas no momento.
Use os URLs da página do log analisado para chamar a versão "extrastuff" do URL no host local com um objeto de cliente da web.
Adicione algum código para alternar arquivos no final de cada período de log ou reinicie o processo a cada período de log.
fonte