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

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

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

問(wèn)題

線上程序出現(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工作線程,線程在處理程序的時(shí)候因?yàn)闊o(wú)法在堆中分配更多內(nèi)存出現(xiàn)了OOM,幸好JVM啟動(dòng)參數(shù)配置了-XX:+HeapDumpOnOutOfMemoryError,使用MAT打開(kāi)拿到的hprof文件進(jìn)行分析。

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

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

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

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

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

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

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

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

max-http-header-size: 10000000

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

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

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

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

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

問(wèn)題原型

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

問(wèn)題是:當(dāng)客戶端發(fā)送一個(gè)GET請(qǐng)求,結(jié)果得到400的response,意思是說(shuō)bad request。

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

問(wèn)題解釋

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

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

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

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

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

那為什么之前沒(méi)有出現(xiàn)這個(gè)問(wèn)題呢?

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

那么如何解決這個(gè)問(wèn)題呢?可以從兩個(gè)方面考慮:

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

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

擴(kuò)展

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

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

原因是,每個(gè)web服務(wù)器的http header最大長(zhǎng)度的默認(rèn)值不一樣,同時(shí)隨語(yǔ)言、版本不同也會(huì)不一樣。舉個(gè)例子tomcat 5的http header size的默認(rèn)值是4K。

我找到了其他component中對(duì)于http header size的默認(rèn)值的定義:

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

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

以上兩個(gè)默認(rèn)值都要遠(yuǎn)遠(yuǎn)大于8KB,這也就解釋了沒(méi)什么問(wèn)題出在最后一個(gè)component。

Tomcat修改maxParameterCount配置

問(wèn)題

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部署項(xiàng)目的時(shí)候,可以通過(guò)修改server.xml文件中的Connector節(jié)點(diǎn)maxParameterCount屬性值解決這個(gè)問(wèn)題。

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

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

參考

自定義tomcat配置

創(chuàng)建一個(gè)類并實(shí)現(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());

    /**
     * 單次請(qǐng)求參數(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單次請(qǐng)求參數(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;
    }
}

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

相關(guān)文章

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

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

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

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

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

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

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

    一篇文章解決Java異常處理

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

    如何使用java寫Student類的功能

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

    springboot開(kāi)啟mybatis二級(jí)緩存的步驟詳解

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

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

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

    Java 棧與隊(duì)列超詳細(xì)分析講解

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

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

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

    深度分析java dump文件

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

最新評(píng)論