问题描述
我已将嵌入tomcat服务器的春季启动中的保持活动超时"设置为30秒.所以我在下面的Application.java中使用
I have set the keep alive timeout in spring boot embeded tomcat server to 30 seconds. So i use below in the Application.java,
@Bean
public EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory containerFactory = new TomcatEmbeddedServletContainerFactory();
containerFactory
.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
((AbstractProtocol) connector.getProtocolHandler())
.setKeepAliveTimeout(30000);
}
});
return containerFactory;
}
然后,我从我的rest控制器休眠一个请求线程40秒钟.但是,当我通过邮递员发出请求时,它会成功返回HTTP状态代码200,而应返回网关超时错误.
Then i sleep a request thread for 40 seconds from my rest controller. But when i make a request via postman it successfully return HTTP status code 200 instead it should return gateway timeout error.
我同时尝试了setConnectionTimeout和setKeepAliveTimeout,但是它没有用.
I try both setConnectionTimeout and setKeepAliveTimeout and it did not work.
我在这里想念什么?
编辑问题:我最初的问题
让我解释一下我的原始问题,这使我提出了上述问题.
Let me explain the original question of mine, which lead me to ask above question.
好吧,我的投票过程很漫长,通常运行5多个minits.
因此,当我为longpoll调用Rest API时,发生了什么情况,在经过2.2次minist之后,我在浏览器中收到504 http错误.
So what happen is when i call the Rest API for longpoll, After 2.2 minits i get a 504 http error in browser.
我正在使用一个AWS环境,其中有一个ELB和一个安装在AWS EC2实例中的HAProxy.
I am using a AWS environment, where i have a ELB and a HAProxy which is installed in AWS EC2 instance.
根据AWS文档,它说 ELB的默认空闲连接超时为60秒.因此,我将其增加到最多30分钟.
As per AWS doc, it says the default Idle Connection Timeout of ELB is 60 seconds. So i have increase it to up to 30 mins.
此外,它说,
因此,将上述代码段之类的嵌入式tomcat保持活动超时时间增加到30.2分钟
So have increase the embedded tomcat keep-alive timeout like above code snippet to 30.2 mins
所以现在我希望我的长时间轮询请求能够完成,并且不会出现504错误.但是我在浏览器中仍然会收到504错误吗?
So now i expect my long poll request to be completed, with out getting a 504 error. But still i get 504 error in browser?
参考: AWS开发人员指南
推荐答案
您似乎想要关闭移动设备上可能发生的废弃HTTP连接.
It looks like you want to close abandoned HTTP connections which might occur on mobile devices.
@RestController
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory containerFactory = new TomcatEmbeddedServletContainerFactory();
containerFactory
.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
((AbstractProtocol) connector.getProtocolHandler()).setConnectionTimeout(100);
}
});
return containerFactory;
}
@RequestMapping
public String echo(@RequestBody String body) {
return body;
}
}
连接超时已设置为100毫秒,以便快速运行我的测试.数据以数据块发送.在每个块之间,正在运行的线程被暂停x毫秒.
Connection timeout has been set to 100 millisencods in order to run my tests fast. Data is sent in chunks. Between every chunk the running thread is suspended for x milliseconds.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = DemoApplication.class)
@WebIntegrationTest("server.port:19000")
public class DemoApplicationTests {
private static final int CHUNK_SIZE = 1;
private static final String HOST = "http://localhost:19000/echo";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void slowConnection() throws Exception {
final HttpURLConnection connection = openChunkedConnection();
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
writeAndWait(500, out, "chunk1");
writeAndWait(1, out, "chunk2");
out.close();
expectedException.expect(IOException.class);
expectedException.expectMessage("Server returned HTTP response code: 400 for URL: " + HOST);
assertResponse("chunk1chunk2=", connection);
}
@Test
public void fastConnection() throws Exception {
final HttpURLConnection connection = openChunkedConnection();
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
writeAndWait(1, out, "chunk1");
writeAndWait(1, out, "chunk2");
out.close();
assertResponse("chunk1chunk2=", connection);
}
private void assertResponse(String expected, HttpURLConnection connection) throws IOException {
Scanner scanner = new Scanner(connection.getInputStream()).useDelimiter("\\A");
Assert.assertEquals(expected, scanner.next());
}
private void writeAndWait(int millis, OutputStreamWriter out, String body) throws IOException, InterruptedException {
out.write(body);
Thread.sleep(millis);
}
private HttpURLConnection openChunkedConnection() throws IOException {
final URL url = new URL(HOST);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setChunkedStreamingMode(CHUNK_SIZE);
return connection;
}
}
将程序包org.apache.catalina.core
的日志级别设置为DEBUG
Set log level for package org.apache.catalina.core
to DEBUG
logging.level.org.apache.catalina.core=DEBUG
,您会看到SocketTimeoutException
用于slowConnection
测试.
我不知道为什么要使用HTTP状态代码502作为错误响应状态. HTTP 502 说:
I don't know why you want HTTP status code 502 as error response status. HTTP 502 says:
客户端Postman
调用您的服务器应用程序.我看不到两者之间的任何网关或代理.
The client Postman
calls your server application. I don't see any gateway or proxy in between.
如果您只是将问题压缩到最低限度,而实际上您想自己构建一个代理,则可以考虑使用 Netflix Zuul .
If you just condensed your question to a bare minimum and in reality you want to build a proxy on your own, you might consider using Netflix Zuul.
更新2016年3月23日:
这是OP关于Stackoverflow的问题的根本原因:
That is the root cause for OP's question on Stackoverflow:
该实现实际上阻止了Tomcat工作线程处理新的HTTP请求.结果,每增加一个长时间运行的操作,您的请求吞吐量就会降低.
That implementation actually prevents the Tomcat worker thread from processing new HTTP requests. As a result your request throughput reduces with every additional long running operation.
我建议将长时间运行的操作卸载到单独的线程中.客户端(浏览器)启动一个新请求以获取结果.根据处理状态,服务器将返回结果或通知/错误/警告/.
I propose to offload the long running operation into a separate thread. The client (browser) initiates a new request to fetch the result.Depending on the processing status, server returns either the result or a notification/error/warning/.
这是一个非常简单的示例:
Here's a very simple example :
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
@RestController
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
private ExecutorService executorService = Executors.newFixedThreadPool(10);
private Map<String, String> results = new ConcurrentHashMap<>();
@RequestMapping(path = "put/{key}", method = RequestMethod.POST)
public ResponseEntity<Void> put(@PathVariable String key) {
executorService.submit(() -> {
try {
//simulate a long running process
Thread.sleep(10000);
results.put(key, "success");
} catch (InterruptedException e) {
results.put(key, "error " + e.getMessage());
Thread.currentThread().interrupt();
}
});
return new ResponseEntity<>(CREATED);
}
@RequestMapping(path = "get/{key}", method = RequestMethod.GET)
public ResponseEntity<String> get(@PathVariable String key) {
final String result = results.get(key);
return new ResponseEntity<>(result, result == null ? NOT_FOUND : OK);
}
}
这篇关于Springboot TomcatEmbeddedServletContainer KeepAliveTimeout不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!