摘要:于是提供了機制,使得從中讀往里寫變成異步動作。這是因為客戶端的數據推送速度太慢了,容器先將收回,當容器發現可以讀取到新數據的時候,再分配一個去讀,如此循環直到全部讀完為止。注意和不能同時使用。
Github地址
相關系列文章:
Servlet 3.0 異步處理詳解
Spring MVC異步處理的幾種方式
Servlet Async Processing提供了一種異步請求處理的手段(見我的另一篇文章Servlet 3.0 異步處理詳解),能夠讓你將Http thread從慢速處理中釋放出來出來其他請求,提高系統的響應度。
但是光有Async Processing是不夠的,因為整個請求-響應過程的速度快慢還牽涉到了客戶端的網絡情況,如果客戶端網絡情況糟糕,其上傳和下載速度都很慢,那么同樣也會長時間占用Http Thread使其不能被釋放出來。
于是Servlet 3.1提供了Async IO機制,使得從Request中讀、往Response里寫變成異步動作。
Async Read我們先來一段客戶端上傳速度慢的例子,AsyncReadServlet.java:
@WebServlet(value = "/async-read", asyncSupported = true) public class AsyncReadServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet thread: " + Thread.currentThread().getName()); AsyncContext asyncCtx = req.startAsync(); ServletInputStream is = req.getInputStream(); is.setReadListener(new ReadListener() { private int totalReadBytes = 0; @Override public void onDataAvailable() { System.out.println("ReadListener thread: " + Thread.currentThread().getName()); try { byte buffer[] = new byte[1 * 1024]; int readBytes = 0; while (is.isReady() && !is.isFinished()) { int length = is.read(buffer); if (length == -1 && is.isFinished()) { asyncCtx.complete(); System.out.println("Read: " + readBytes + " bytes"); System.out.println("Total Read: " + totalReadBytes + " bytes"); return; } readBytes += length; totalReadBytes += length; } System.out.println("Read: " + readBytes + " bytes"); } catch (IOException ex) { ex.printStackTrace(); asyncCtx.complete(); } } @Override public void onAllDataRead() { try { System.out.println("Total Read: " + totalReadBytes + " bytes"); asyncCtx.getResponse().getWriter().println("Finished"); } catch (IOException ex) { ex.printStackTrace(); } asyncCtx.complete(); } @Override public void onError(Throwable t) { System.out.println(ExceptionUtils.getStackTrace(t)); asyncCtx.complete(); } }); } }
我們利用curl的--limit-rate選項來模擬慢速上傳curl -X POST -F "bigfile=@src/main/resources/bigfile" --limit-rate 5k http://localhost:8080/async-read
然后觀察服務端的打印輸出:
Servlet thread: http-nio-8080-exec-3 ReadListener thread: http-nio-8080-exec-3 Read: 16538 bytes ReadListener thread: http-nio-8080-exec-4 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-5 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-7 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-6 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-8 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-9 Read: 16384 bytes ReadListener thread: http-nio-8080-exec-10 Read: 2312 bytes ReadListener thread: http-nio-8080-exec-1 Read: 48 bytes Total Read: 117202 bytes
可以從輸出看到除了doGet和第一次進入onDataAvailable是同一個Http thread之外,后面的read動作都發生在另外的Http thread里。
這是因為客戶端的數據推送速度太慢了,容器先將Http thread收回,當容器發現可以讀取到新數據的時候,再分配一個Http thread去讀InputStream,如此循環直到全部讀完為止。
注意:HttpServletRequest.getInputStream()和getParameter*()不能同時使用。
Async Write再來一段客戶端下載慢的例子,AsyncWriteServlet.java:
@WebServlet(value = "/async-write", asyncSupported = true) public class AsyncWriteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet thread: " + Thread.currentThread().getName()); AsyncContext asyncCtx = req.startAsync(); ServletOutputStream os = resp.getOutputStream(); InputStream bigfileInputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("bigfile"); os.setWriteListener(new WriteListener() { @Override public void onWritePossible() throws IOException { int loopCount = 0; System.out.println("WriteListener thread: " + Thread.currentThread().getName()); while (os.isReady()) { loopCount++; System.out.println("Loop Count: " + loopCount); byte[] bytes = readContent(); if (bytes != null) { os.write(bytes); } else { closeInputStream(); asyncCtx.complete(); break; } } } @Override public void onError(Throwable t) { try { os.print("Error happened"); os.print(ExceptionUtils.getStackTrace(t)); } catch (IOException e) { e.printStackTrace(); } finally { closeInputStream(); asyncCtx.complete(); } } private byte[] readContent() throws IOException { byte[] bytes = new byte[1024]; int readLength = IOUtils.read(bigfileInputStream, bytes); if (readLength <= 0) { return null; } return bytes; } private void closeInputStream() { IOUtils.closeQuietly(bigfileInputStream); } }); } }
同樣利用curl做慢速下載,curl --limit-rate 5k http://localhost:8080/async-write
接下來看以下服務端打印輸出:
Servlet thread: http-nio-8080-exec-1 WriteListener thread: http-nio-8080-exec-1 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-2 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-3 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-4 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-5 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-6 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-7 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-8 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-9 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-10 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-1 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-2 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-3 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-4 Write bytes: 8192 WriteListener thread: http-nio-8080-exec-5 Write bytes: 2312
PS. 后發現即使沒有添加--limit-rate參數,也會出現類似于上面的結果。
Jmeter上面兩個例子使用的是curl來模擬,我們也提供了Jmeter的benchmark。
需要注意的是,必須在user.properties文件所在目錄啟動Jmeter,因為這個文件里提供了模擬慢速連接的參數httpclient.socket.http.cps=5120。然后利用Jmeter打開benchmark.xml。
相關資料Java EE 7 Tutorial: Java Servlet Technology - Nonblocking I/O
Slides - Servlet 3.1 Async IO
Non-blocking I/O using Servlet 3.1: Scalable applications using Java EE 7
How to simulate network bandwidth in JMeter?
Configuring JMeter
Servlet 3.1 Asynchronous IO and Jetty-9.1
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/70853.html
摘要:異步處理簡介地址相關系列文章異步處理詳解分析本文講到的所有特性皆是基于的,不是基于的。用于異步返回結果,使用自己的,使用負責處理它。配置執行異步操作需要用到,這個可以在用方法來提供相關文檔。 Spring MVC異步處理簡介 Github地址 相關系列文章: Servlet 3.0 異步處理詳解 Servlet 3.1 Async IO分析 本文講到的所有特性皆是基于Servlet...
摘要:概念響應式編程,異步非阻塞就是響應式編程,與之相對應的是命令式編程。的另外一種實現方式就是消息隊列。非阻塞設計利用規范中的實現實現代碼鏈接 注: 本文是由讀者觀看小馬哥公開課視頻過程中的筆記整理而成。更多Spring Framework文章可參看筆者個人github: spring-framework-lesson 。 0. 編程模型與并發模型 Spring 5實現了一部分Reacti...
摘要:但是這樣依然有一個問題,考慮以下場景有一個容器,線程池大小。這個時候工程師發現了問題,擴展了線程池大小到,但是負載依然持續走高,現在有個到,依然無法響應。你可以修改的線程池大小,把它和比較結果來驗證這一結論。 Github地址 相關系列文章: Servlet 3.1 Async IO分析 Spring MVC異步處理的幾種方式 Servlet 3.0 開始提供了AsyncConte...
摘要:性能會有所降低一點內容,刷新整個頁面用戶的操作頁面會中斷整個頁面被刷新了就是能夠做到局部刷新三對象是中最重要的一個對象。頭信息已經接收,響應數據尚未接收。 一、什么是Ajax Ajax(Asynchronous JavaScript and XML) 異步JavaScript和XML Ajax實際上是下面這幾種技術的融合: (1)XHTML和CSS的基于標準的表示技術 (2)DOM進...
摘要:攔截所有的請求,放行登錄頁面登錄操作請求,其余請求需要在登錄后才可訪問。同時配置參數,指定要放行的路徑和請求的字符集。 Serlvet中WebServlet注解 作用: 用于將一個類聲明為 Servlet 描述: 該注解將會在部署時被容器處理, 容器將根據具體的屬性配置將相應的類部署為 Servlet. 屬性詳解: 該注解具有下表給出的一些常用屬性(以下所有屬性均為可選屬性, 但是 v...
閱讀 3327·2021-11-23 09:51
閱讀 2455·2021-11-09 09:46
閱讀 1488·2019-08-30 15:54
閱讀 3135·2019-08-30 14:22
閱讀 2918·2019-08-29 12:40
閱讀 1640·2019-08-26 10:33
閱讀 1787·2019-08-23 17:09
閱讀 1564·2019-08-23 16:11