jodd-http實現細節的一點思考

  jodd-http是一個很是輕巧的http客戶端工具,使用起來簡單便利、容易上手。常見的http請求方式都能很好地支持,包括文件的上傳下載、chunk響應模式,還必定程度上支持長連接、模擬瀏覽器、隧道等特性。下文中將使用jodd指代jodd-http。java

   最近部門有個項目使用該技術實現了一個輕量級的網關代理層,前幾天在和帥哥排查問題時注意到jodd實現上的兩個細節,若使用不當會致使服務端的性能和內存空間方面產生問題。web

第一,jodd自動處理chunk響應會形成內存開銷較大

  在處理服務端的chunk響應時,jodd採用自循環的方式,直到接收徹底部數據爲止(見代碼一)。假設系統須要處理不少大響應體的請求時,這種方式便會佔用過多的內存空間,甚至有OOM的風險。另外,衡量web性能的衆多指標中有一個叫作TTFB的重要指標,即 Time To First Byte,它表示客戶端自請求發出直至接收到響應的第一個字節時所經歷的時間延遲,顯然,在網關代理層的場景中,jodd拼裝好完整響應後再返回給客戶端的時間消耗會對該指標產生較大的不利影響。數組

// 如下是jodd.http.HttpBase#readBody方法中的讀取chunk數據的代碼段
if (isChunked) {
   FastCharArrayWriter fastCharArrayWriter = new FastCharArrayWriter();
   try {
      while (true) {
         String line = reader.readLine();
         int len = Integer.parseInt(line, 16);
         if (len > 0) {
            StreamUtil.copy(reader, fastCharArrayWriter, len);
            reader.readLine();
         } else {
            // end reached, read trailing headers, if there is any
            readHeaders(reader);
            break;
         }
      }
   } catch (IOException ioex) {
      throw new HttpException(ioex);
   }
   bodyString = fastCharArrayWriter.toString();
}
複製代碼

代碼一瀏覽器

第二,jodd會自動將響應體中原始的byte數組轉換成字符串(見代碼二),該操做不少時候會形成沒必要要的資源浪費

// 在jodd.http.HttpBase#readBody方法中,使用以下語句從包裝了輸入流的Reader中讀取字符數據至Writer中
StreamUtil.copy(reader, fastCharArrayWriter, contentLenValue);
複製代碼

代碼二工具

  首先這種轉換操做須要進行CPU運算,其次,轉換結果的char數組也須要佔用相應大小的內存空間,關鍵是這種自動轉換不少時候是徒勞的,緣由有二:性能

  1. 若是響應體中的數據自己就是二進制的,好比文件下載,則系統還須要從字符串轉回byte數組編碼

  2. 自動轉換固定採用了ISO-8859-1字符集,該字符集在不少國家和地區並不能知足當地的文字編碼需求,東亞字符更是如此,所以須要將ISO字符串轉回byte數組,以後再轉換成對應字符集的字符串,好比UTF-8spa

  jodd爲何要使用字符串存儲響應體數據,目前還沒有可知,但有一個比較明顯的好處是,在使用ISO-8859-1字符集的系統中,該方式能夠避免存放響應體二進制數據的額外內存佔用。代理

  經過對以上兩個實現細節的分析,在使用jodd時還需考慮具體的應用場景,避免引發沒必要要的內存和性能問題。code

文末彩蛋

  在將響應體數據轉換爲字符串時,jodd爲何選擇了ISO-8859-1字符集,而不是其餘字符集呢?

  ISO-8859-1是一種基礎字符集,包含的字符都是單字節編碼,取值範圍是0x00~0xFF,一共256個編碼。所以,該字符集自然具有一種特性,任何的二進制值都能轉換成相應的字符編碼。也就是說,若是採用了該字符集,任何二進制數據均可以和ISO字符串之間進行無損的雙向轉換。jodd正是利用了這種性質巧妙地實現了使用字符串存儲響應體而且不會丟失數據。

相關文章
相關標籤/搜索