Prefácio
Este artigo apresenta principalmente as armadilhas de @scheduled e httpclient na primavera. Vamos compartilhá -los para sua referência e aprendizado. Não vou dizer muito abaixo, vamos dar uma olhada na introdução detalhada juntos.
Uma vez pisei em um grande poço:
Devido à particularidade dos negócios, muitas tarefas cronometradas serão executadas regularmente e compensadas por dados de negócios.
Durante o uso da primavera, podemos usar a anotação @Scheduled para implementar facilmente tarefas de tempo.
Uma manhã, de repente percebi que, a partir de um certo momento na noite anterior, todas as tarefas cronometradas estavam presas e pararam de correr.
@ScheduledDefault único Tópico
Após a investigação, verificou -se que, se usarmos a anotação @Scheduled para explicar a configuração padrão, todas as tarefas serão executadas por um único thread. Depois de escrever uma tarefa de teste para dormir, é fácil descobrir que todas as outras tarefas não são acionadas quando chegar a hora.
Se você precisar ativar o multi-threading, precisará executar a seguinte configuração e definir o número de threads:
@ConfigurationPublic Class ScheduleConfig implementa o SchedulingConfigurer {@Override public void ConfigureTasks (ScheduledTaskRegistrar TaskReGistrar) {TaskRegistrar.SetScheduler (Executores.NewSchedulEdThreadpool (5)); }}Isso resolve o problema de que, se uma tarefa estiver presa, fará com que todas as tarefas fiquem presas.
Mas por que há tarefas presas?
Configuração de parâmetros padrão httpclient
Acontece que algumas tarefas solicitarão a interface RESTful de serviços externos regularmente, e a configuração do httpclient é a seguinte:
PoolingHttpClientConnectionManager ConnManager = new PoolingHttpClientConnectionManager (); ConnManager.Setmaxtotal (MaxConnection); httpClient = httpclients.custom () .setConnectionManager (ConnManager) .build ();
Quando usei o HTTPClient pela primeira vez, não pensei muito nisso e basicamente usei a configuração padrão.
O rastreamento do código -fonte pode descobrir que, ao configurar usando o método acima, o tempo de tempo limite do HTTPClient é na verdade -1, o que significa que, se houver um problema com o serviço da outra parte, a solicitação de httpclient nunca ficará em tempo e esperará. O código -fonte é o seguinte:
Construtor () {super (); this.staleconnectionCheckenabled = false; this.redirectSenabled = true; this.maxRedirects = 50; this.RelativeRedirects inallowed = true; this.authenticationEnabled = true; this.ConnectionRequestTimeout = -1; this.ConnectTimeout = -1; this.sockettimeout = -1; this.ContentCompressionEnabled = true;}Portanto, devemos especificar manualmente o horário do tempo limite neste momento, e o problema é resolvido. Por exemplo:
PoolingHttpClientConnectionManager ConnManager = new PoolingHttpClientConnectionManager (); ConnManager.Setmaxtotal (MaxConnection); Requestconfig defaultRequeSconfig = requestconfig.custom () .SetSockettimeout (3000) .SetConnectTimeout (3000) .SetConnectionRequestTimeout (3000) .build (); httpClient = httpclients.custom () .setDefaultReCeStConfig (DefaultRequeSconfig) .SetConnectionManager (ConnManager) .build ();
Lembre de outro problema
De fato, outro problema de configuração encontrado durante o uso do httpclient, que é o parâmetro DefaultMaxPerroute.
Não prestei atenção a esse parâmetro quando o usei pela primeira vez, mas apenas defini o número máximo de conexões no pool de conexão Maxtotal.
O parâmetro DefaultMaxPerRoute realmente representa o número máximo de conexões por rota. Por exemplo, seu sistema precisa acessar outros dois serviços: google.com e bing.com. Se o seu Maxtotal estiver definido como 100 e o DefaultMaxPerRoute estiver definido como 50, o número máximo de solicitações para cada serviço poderá ser 50.
Portanto, se o defaultmaxperroute não estiver definido, rastreie o código -fonte:
public PoolingHttpClientConnectionManager (Final HttpClientConnectionOperator HttpClientConnectionOperator, final httpConnectionFactory <httproute, gerenciadohttpclientConnection> Confactory, final de tempo final, timetolivo final) {(); this.configData = new configData (); // O método do construtor CPOOL usado aqui, o segundo parâmetro é defaultMaxPerroute, que é o padrão é 2. This.pool = new cpool (novo internalconnectionFactory (this.configData, confactory), 2, 20, timetolive, tunit); this.pool.setValidateAdterinActivity (2000); this.ConnectionOperator = args.notNull (httpclientConnectionOperator, "httpclientConnectionOperator"); this.ISSHUTDOWN = new AtomicBoolean (false);}Verificou -se aqui que o valor padrão era de apenas 2. Não é de admirar que sempre houvesse um tempo limite em situações de alta concorrência naquele momento, Maxtotal estava claramente definido muito alto.
Portanto, se o seu serviço acessar muitos serviços externos diferentes e tiver uma grande simultaneidade, você deverá configurar os dois parâmetros Maxtotal e DefaultMaxPerroute.
Então, quando você usar coisas novas mais tarde, você dará uma boa olhada em quais configurações você tem. Se você tiver alguma dúvida, deve verificar primeiro. Não copie um pedaço de código on -line e use -o diretamente. Pode ser bom naquele momento, mas talvez eu seja enganado no futuro.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.