上传多部分文件和连接中断时,Jetty占用100%的CPU

时间:2016-01-26 20:36:25

标签: java spring jetty embedded-jetty

Jetty在上传多部分文件和连接中断时占用100%的CPU

我们目前正在使用嵌入式Jetty Server + Spring MVC上传文件。 当我使用curl手动上传文件并使用Ctrl ^ C故意破坏它时,CPU在服务器上达到100%并且仅重新启动应用程序将完成此问题。

  

curl -i -X POST -H“Content-Type:multipart / form-data”-F“param1 = bla”-F“file = @ a_file”http://myserver/bla/submit

我已经检查过这个问题的其他帖子,但通常它会通过更新Jetty API版本和Java 8来解决。我已经这样做了,但同样的问题正在发生。可能与春天有关吗?

的API:

  • Jetty:9.3.6.v20151106
  • JRE:1.8_65(我没有使用JDK来运行应用程序)
  • Spring MVC:3.2.15

以下是该方法的代码段:

@RequestMapping(
            value = MY_PATH,
            method = RequestMethod.POST)
    public
    @ResponseBody
    void submitFile(
            @NotNull @RequestParam("param1") String param1,
            @NotNull @RequestParam("file") MultipartFile file) {
            //No code gets executed
            }

我已经使用Java Visual VM监视并找到导致问题的那个的转储:

"qtp529864074-68" - Thread t@68
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
    at sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:51)
    at sun.nio.ch.IOUtil.write(IOUtil.java:148)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:504)
    - locked <6ddac168> (a java.lang.Object)
    at org.eclipse.jetty.io.ChannelEndPoint.flush(ChannelEndPoint.java:177)
    at org.eclipse.jetty.io.WriteFlusher.flush(WriteFlusher.java:419)
    at org.eclipse.jetty.io.WriteFlusher.write(WriteFlusher.java:313)
    at org.eclipse.jetty.io.AbstractEndPoint.write(AbstractEndPoint.java:141)
    at org.eclipse.jetty.server.HttpConnection$SendCallback.process(HttpConnection.java:735)
    at org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:241)
    at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:224)
    at org.eclipse.jetty.server.HttpConnection.send(HttpConnection.java:509)
    at org.eclipse.jetty.server.HttpChannel.sendResponse(HttpChannel.java:668)
    at org.eclipse.jetty.server.HttpChannel.write(HttpChannel.java:722)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:177)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:163)
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:441)
    at org.eclipse.jetty.util.ByteArrayISO8859Writer.writeTo(ByteArrayISO8859Writer.java:109)
    at org.eclipse.jetty.server.Response.sendError(Response.java:606)
    at org.eclipse.jetty.server.Response.sendError(Response.java:512)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:650)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1160)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1090)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:213)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:119)
    at org.eclipse.jetty.server.Server.handle(Server.java:517)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:308)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:242)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:261)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
    at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:75)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
    at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:147)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
    at java.lang.Thread.run(Thread.java:745)

1 个答案:

答案 0 :(得分:0)

查看密码转换文件,您会看到来自.flush()电话的Response.sendError()来电。这可能意味着您的POST失败(无论出于何种原因)并且尝试发送错误响应,但要么尚未完成,要么客户端尚未完成读取错误。 它甚至可能是sendError循环的结果(查找错误页面,使用/分派错误页面,并且错误页面本身有错误导致另一个sendError触发)

至于Multipart方面,您的SpringMVC设置似乎存在问题,因为Jetty在处理Multipart上传内容方面没有问题。

  

在Github上为这个问题创建了这个答案的示例项目。

     

请参阅https://github.com/jetty-project/multipartconfig-example

使用Servlet API在Jetty中执行此操作的示例。

@MultipartConfig(location="/tmp/upload", 
                 fileSizeThreshold=1024*1024, 
                 maxFileSize=1024*1024*50)
@WebServlet(urlPatterns={"/upload"}, name="upload")
public class UploadServlet extends HttpServlet
{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    {
        resp.setContentType("text/plain");
        PrintWriter out = resp.getWriter();

        int i=0;
        for(Part part: req.getParts())
        {
            out.printf("Got part: name=%s, size=%d%n",part.getName(), part.getSize());
            part.write(String.format("part-%02d.dat",i++));
        }
    }
}

如果我们在Jetty发行版中部署的war文件中运行它,然后使用Curl测试它,您将看到以下内容......

$ curl -i -X POST -H "Content-Type: multipart/form-data" \
  -F "param1=bla" -F "file=@big.tar.gz" \
  http://localhost:8080/upload
HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Content-Type: text/plain;charset=iso-8859-1
Content-Length: 65
Server: Jetty(9.3.6.v20151106)

Got part: name=file, size=23597555
Got part: name=param1, size=3

$ ls -la /tmp/upload/
total 23052
drwxrwxr-x.  2 joakim joakim       80 Jan 26 14:19 .
drwxrwxrwt. 20 root   root        500 Jan 26 14:19 ..
-rw-rw-r--.  1 joakim joakim 23597555 Jan 26 14:19 part-00.dat
-rw-rw-r--.  1 joakim joakim        3 Jan 26 14:19 part-01.dat

$ sha1sum /tmp/upload/part-00.dat big.tar.gz 
13be13872d0203bae2f8a83ad457f8a0d259a2db  /tmp/upload/part-00.dat
13be13872d0203bae2f8a83ad457f8a0d259a2db  big.tar.gz

$ file /tmp/upload/part-01.dat 
/tmp/upload/part-01.dat: ASCII text, with no line terminators

$ cat /tmp/upload/part-01.dat 
bla