欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot?max-http-header-size最大長度的那些事及JVM調(diào)優(yōu)方式

 更新時間:2022年09月30日 12:04:51   作者:菠蘿y  
這篇文章主要介紹了springboot?max-http-header-size最大長度的那些事及JVM調(diào)優(yōu)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

問題

線上程序出現(xiàn)了OOM,程序日志中的輸出為

Exception in thread "http-nio-8080-exec-1027" java.lang.OutOfMemoryError: Java heap space
Exception in thread "http-nio-8080-exec-1031" java.lang.OutOfMemoryError: Java heap space

看線程名稱應(yīng)該是tomcat的nio工作線程,線程在處理程序的時候因為無法在堆中分配更多內(nèi)存出現(xiàn)了OOM,幸好JVM啟動參數(shù)配置了-XX:+HeapDumpOnOutOfMemoryError,使用MAT打開拿到的hprof文件進行分析。

第一步就是打開Histogram看看占用內(nèi)存最大的是什么對象:

可以看到byte數(shù)組占用了接近JVM配置的最大堆的大小也就是8GB,顯然這是OOM的原因。

第二步看一下究竟是哪些byte數(shù)組,數(shù)組是啥內(nèi)容:

可以看到很明顯這和HTTP請求相關(guān),一個數(shù)組大概是10M的大小。

第三步通過查看GC根查看誰持有了數(shù)組的引用:

這符合之前的猜測,是tomcat的線程在處理過程中分配了10M的buffer在堆上。

至此,馬上可以想到一定是什么參數(shù)設(shè)置的不合理導致了這種情況,一般而言tomcat不可能為每一個請求分配如此大的buffer。

第四步就是檢查代碼里是否有tomcat或服務(wù)器相關(guān)配置,看到有這么一個配置:

max-http-header-size: 10000000

至此,基本已經(jīng)確定了八九不離十就是這個不合理的最大http請求頭參數(shù)導致的問題。

關(guān)于http header最大長度的那些事

http協(xié)議,超文本傳輸協(xié)議,HyperText Transfer Protocol,是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議,所有的WWW文件都遵守這個標準。

關(guān)于http協(xié)議消息的格式,大家可以網(wǎng)上自行搜索,這里不再贅述。

本文關(guān)注的是其header部分,如下圖所示(紅框標注部分):

問題原型

有一個web application提供web service,這個web application基于java開發(fā),部署在tomcat容器上。

問題是:當客戶端發(fā)送一個GET請求,結(jié)果得到400的response,意思是說bad request。

檢查了這個request的代碼實現(xiàn)邏輯,并沒有相關(guān)input validation的邏輯,并且檢查server端日志發(fā)現(xiàn),request請求似乎并沒有到達我們自己代碼實現(xiàn)邏輯部分。這是為什么呢?

問題解釋

遇到這個問題時,第一步就是查看server端日志,但是覺得很tricky的是,最開始并沒有發(fā)現(xiàn)相關(guān)的日志,只是發(fā)現(xiàn)request并沒有到達我們自己代碼實現(xiàn)邏輯部分。

后來,mina同學眼神很好,發(fā)現(xiàn)了如下日志:

通過日志note信息發(fā)現(xiàn),該條日志在info級別下只會打印一次,之后都會是debug級別才打印,難怪之前沒有注意到這條日志。

從日志信息可知,request的header部分太大,超過了tomcat允許的最大值。

默認情況下,tomcat(8.0版本)允許的http請求header的最大值是8024個字節(jié)(8KB)。

那為什么之前沒有出現(xiàn)這個問題呢?

原因是,項目遷移到SCP平臺上之后,改成JWT token做權(quán)限校驗,這個JWT token會被添加到request的header,然而JWT token一般來說都很大(平均有6k個字節(jié)左右),所以說在增加了JWT token這個header以及其他一些相關(guān)的headers之后,整個request的header部分就超過8024個字節(jié),于是就出現(xiàn)了這個問題。

那么如何解決這個問題呢?可以從兩個方面考慮:

增加tomcat允許http header最大值。這個配置參數(shù)maxHttpHeaderSize可以設(shè)置tomcat允許的http header最大值。

減少header的size,比如不要添加無關(guān)的header到request。

擴展

在研究這個問題的過程中,其實還有一些其他疑問。首先,一個request的轉(zhuǎn)發(fā)流程大致如下:

那么,在這個流程中,為什么request在前面的部分沒有出現(xiàn)這個問題,而這個問題出現(xiàn)在最后一個技術(shù)棧是java/tomcat的component呢?

原因是,每個web服務(wù)器的http header最大長度的默認值不一樣,同時隨語言、版本不同也會不一樣。舉個例子tomcat 5的http header size的默認值是4K。

我找到了其他component中對于http header size的默認值的定義:

CF Router是用Go語言實現(xiàn),Go語言的http處理模塊對于它的定義是默認值1MB。

App Router是用Nodejs實現(xiàn),Nodejs的http處理模塊對它的定義是默認值80KB。

以上兩個默認值都要遠遠大于8KB,這也就解釋了沒什么問題出在最后一個component。

Tomcat修改maxParameterCount配置

問題

java.lang.IllegalStateException: More than the maximum number of request
 parameters (GET plus POST) for a single request ([10,000]) were detected.
  Any parameters beyond this limit have been ignored.
   To change this limit, set the maxParameterCount attribute
    on the Connector.

解決方案

以前使用外部Tomcat部署項目的時候,可以通過修改server.xml文件中的Connector節(jié)點maxParameterCount屬性值解決這個問題。

<Connector port=“8080” redirectPort=“8443” protocol=“HTTP/1.1” maxParameterCount="-1" />

因為SpringBoot使用的是內(nèi)嵌的Tomcat,無法配置server.xml。經(jīng)過查看相關(guān)API文檔并沒有發(fā)現(xiàn)可以直接在配置文件中配置maxParameterCount屬性,那么我們就在代碼中進行配置,在SpringBoot的API文檔中講解了通過實現(xiàn)WebServerFactoryCustomizer接口可以對Tomcat進行相關(guān)配置。

參考

自定義tomcat配置

創(chuàng)建一個類并實現(xiàn)WebServerFactoryCustomizer接口的customize方法。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

/**
 * 自定義Tomcat容器配置類
 *
 */
@Component
public class MyTomcatWebServerFactoryCustomizer 
        implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    public static final int DEFAULT_MAX_PARAMETER_COUNT = 10000;

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 單次請求參數(shù)最大限制數(shù)
     */
    @Value("${server.tomcat.maxParameterCount}")
    private int maxParameterCount = DEFAULT_MAX_PARAMETER_COUNT;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        if (logger.isDebugEnabled()) {
            logger.debug("MyTomcatWebServerFactoryCustomizer customize");
        }

        PropertyMapper propertyMapper = PropertyMapper.get();

        propertyMapper.from(this::getMaxParameterCount)
                .when((maxParameterCount) -> maxParameterCount != DEFAULT_MAX_PARAMETER_COUNT)
                .to((maxParameterCount) -> customizerMaxParameterCount(factory, maxParameterCount));
    }

    /**
     * 配置內(nèi)置Tomcat單次請求參數(shù)限制
     *
     * @param factory
     * @param maxParameterCount
     */
    private void customizerMaxParameterCount(TomcatServletWebServerFactory factory, 
                                             int maxParameterCount) {
        factory.addConnectorCustomizers(
                connector -> connector.setMaxParameterCount(maxParameterCount));
    }

    public void setMaxParameterCount(int maxParameterCount) {
        this.maxParameterCount = maxParameterCount;
    }

    public int getMaxParameterCount() {
        return maxParameterCount;
    }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 關(guān)于spring.factories失效原因分析及解決

    關(guān)于spring.factories失效原因分析及解決

    這篇文章主要介紹了關(guān)于spring.factories失效原因分析及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • SpringBoot動態(tài)Feign服務(wù)調(diào)用詳解

    SpringBoot動態(tài)Feign服務(wù)調(diào)用詳解

    Feign是Netflix公司開發(fā)的一個聲明式的REST調(diào)用客戶端; Ribbon負載均衡、 Hystrⅸ服務(wù)熔斷是我們Spring Cloud中進行微服務(wù)開發(fā)非?;A(chǔ)的組件,在使用的過程中我們也發(fā)現(xiàn)它們一般都是同時出現(xiàn)的,而且配置也都非常相似
    2022-12-12
  • Spring5新特性之Reactive響應(yīng)式編程

    Spring5新特性之Reactive響應(yīng)式編程

    這篇文章主要介紹了Spring5新特性之Reactive響應(yīng)式編程,響應(yīng)式編程是一種編程范式,通用和專注于數(shù)據(jù)流和變化的,并且是異步的,下文更多詳細內(nèi)容,需要的小伙伴可以參考一下,希望對你有所幫助
    2022-03-03
  • 一篇文章解決Java異常處理

    一篇文章解決Java異常處理

    這篇文章主要給大家介紹了關(guān)于如何通過一篇文章解決Java異常處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • 如何使用java寫Student類的功能

    如何使用java寫Student類的功能

    這篇文章主要介紹了如何使用java寫Student類的功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • springboot開啟mybatis二級緩存的步驟詳解

    springboot開啟mybatis二級緩存的步驟詳解

    這篇文章給大家介紹了springboot開啟mybatis二級緩存的詳細步驟,文中通過代碼示例給大家講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • 解答為什么 Java 線程沒有Running狀態(tài)

    解答為什么 Java 線程沒有Running狀態(tài)

    Java 線程沒有Running狀態(tài)指的是一個在 JVM 中執(zhí)行 的線程處于的狀態(tài),本文小編將為大家詳解一二,需要的朋友可以參考下面文章具體內(nèi)容
    2021-09-09
  • Java 棧與隊列超詳細分析講解

    Java 棧與隊列超詳細分析講解

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)中的棧與隊列,在Java的時候,對于棧與隊列的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學習時候能夠有扎實的基礎(chǔ)能力。本文小編就來詳細說說Java中的棧與隊列,需要的朋友可以參考一下
    2022-04-04
  • Java中實現(xiàn)文件上傳下載的三種解決方案(推薦)

    Java中實現(xiàn)文件上傳下載的三種解決方案(推薦)

    這篇文章主要介紹了Java中實現(xiàn)文件上傳下載的三種解決方案的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • 深度分析java dump文件

    深度分析java dump文件

    java內(nèi)存dump是jvm運行時內(nèi)存的一份快照,利用它可以分析是否存在內(nèi)存浪費,可以檢查內(nèi)存管理是否合理,當發(fā)生OOM的時候,可以找出問題的原因。那么dump文件的內(nèi)容是什么樣的呢?
    2021-05-05

最新評論