溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

max-http-header-size引起的oom是什么情況

發(fā)布時間:2021-10-21 13:45:19 來源:億速云 閱讀:532 作者:柒染 欄目:大數(shù)據(jù)

max-http-header-size引起的oom是什么情況,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

記一次線上OOM事故

根據(jù)用戶反饋,某服務(wù)不能提供服務(wù),然后我們進行排查,進程id還在,但日志不輸出。通過jstat -gcutil 查看內(nèi)存使用情況;發(fā)現(xiàn)出現(xiàn)Full GC了。

查看內(nèi)存使用情況
ps -ef | grep --color=auto 項目名 | grep --color=auto -v "grep" | awk '{print $2}' | xargs -i jstat -gcutil {} 2000

max-http-header-size引起的oom是什么情況

S0:幸存1區(qū)當(dāng)前使用比例
S1:幸存2區(qū)當(dāng)前使用比例
E:伊甸園區(qū)使用比例
O:老年代使用比例
M:元數(shù)據(jù)區(qū)使用比例
CCS:壓縮使用比例
YGC:年輕代垃圾回收次數(shù)
FGC:老年代垃圾回收次數(shù)
FGCT:老年代垃圾回收消耗時間
GCT:垃圾回收消耗總時間

當(dāng)年輕代內(nèi)存滿時,會引發(fā)一次普通GC,該GC僅回收年輕代。需要強調(diào)的時,年輕代滿是指Eden代滿,Survivor滿不會引發(fā)GC

當(dāng)年老代滿時會引發(fā)Full GC,F(xiàn)ull GC將會同時回收年輕代、年老代

生成堆的dump文件
jmap -dump:format=b,file=812.hprof 15968
打包文件
tar -czf 814.tar.gz 814.hprof
MAT分析內(nèi)存

一看就有問題了。

max-http-header-size引起的oom是什么情況

查看Histogram

max-http-header-size引起的oom是什么情況

進行引用查看

max-http-header-size引起的oom是什么情況

max-http-header-size引起的oom是什么情況

通過mat分析查看這個對象內(nèi)存占用很大有10M左右,所以重點對這個類分析,看看干了什么。

org.apache.coyote.Response#outputBuffer這個類是tomcat輸出到socket時的類。

max-http-header-size引起的oom是什么情況

問題就在這里了,這里的對象內(nèi)存10m左右?。?!

這個值怎么來的呢?老同事設(shè)置的,也不知道當(dāng)初為啥設(shè)置這個值。這個原因后面給出

server:
  max-http-header-size: 10000000

源碼分析,后方高能!查看tomcat調(diào)用鏈路

max-http-header-size引起的oom是什么情況

org.apache.catalina.connector.CoyoteAdapter#service max-http-header-size引起的oom是什么情況

max-http-header-size引起的oom是什么情況

max-http-header-size引起的oom是什么情況 最后tomcat通過socket返回結(jié)果

org.apache.coyote.http11.Http11OutputBuffer#commit

 protected void commit() throws IOException {
        response.setCommitted(true);

        if (headerBuffer.position() > 0) {
            // Sending the response header buffer
            headerBuffer.flip();
            try {
                socketWrapper.write(isBlocking(), headerBuffer);
            } finally {
                headerBuffer.position(0).limit(headerBuffer.capacity());
            }
        }
    }

也就是一個請求會返回10m數(shù)據(jù)給前端,在用jemter100個并發(fā)測試時,堆內(nèi)存直接打滿。服務(wù)停止。

為什么會設(shè)置這個值 max-http-header-size呢?

由于項目提供的api接口提供給第三方平臺使用,用戶身份校驗是放在header里來做的。當(dāng)?shù)谌狡脚_沒按著規(guī)范來傳值呢?系統(tǒng)發(fā)生錯誤。Error parsing HTTP request header

org.apache.coyote.http11.Http11Processor#service

public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        RequestInfo rp = request.getRequestProcessor();
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

        // Setting up the I/O
        setSocketWrapper(socketWrapper);
        inputBuffer.init(socketWrapper);
        outputBuffer.init(socketWrapper);

        // Flags
        keepAlive = true;
        openSocket = false;
        readComplete = true;
        boolean keptAlive = false;
        SendfileState sendfileState = SendfileState.DONE;

        while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
                sendfileState == SendfileState.DONE && !endpoint.isPaused()) {

            // Parsing the request header
            try {
              	 // 這行代碼報錯
                if (!inputBuffer.parseRequestLine(keptAlive)) {
                    if (inputBuffer.getParsingRequestLinePhase() == -1) {
                        return SocketState.UPGRADING;
                    } else if (handleIncompleteRequestLineRead()) {
                        break;
                    }
                }

               .....
            } catch (IOException e) {
                if (log.isDebugEnabled()) {
                    // 打印錯誤。。。。。。
                    log.debug(sm.getString("http11processor.header.parse"), e);
                }
                setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
                break;
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                UserDataHelper.Mode logMode = userDataHelper.getNextMode();
                if (logMode != null) {
                    String message = sm.getString("http11processor.header.parse");
                    switch (logMode) {
                        case INFO_THEN_DEBUG:
                            message += sm.getString("http11processor.fallToDebug");
                            //$FALL-THROUGH$
                        case INFO:
                            log.info(message, t);
                            break;
                        case DEBUG:
                            log.debug(message, t);
                    }
                }
                // 400 - Bad Request
                response.setStatus(400);
                setErrorState(ErrorState.CLOSE_CLEAN, t);
                getAdapter().log(request, response, 0);
            }

         ......
    }
org.apache.tomcat.util.net.NioChannel#read 報錯地方

org.apache.tomcat.util.net.NioChannel#read

protected SocketChannel sc = null;
@Override
    public int read(ByteBuffer dst) throws IOException {
        return sc.read(dst);
    }

max-http-header-size引起的oom是什么情況

org.apache.coyote.http11.Http11InputBuffer#init max-http-header-size引起的oom是什么情況

報錯原因在于,SocketChannel.read的數(shù)據(jù)大于接受的buffer了。默認buffer的是16kb,如果超出則報錯。而tomcat遇到這個錯誤時并沒有拋出該異常,而是記錄日志;并輸出結(jié)果是code=400;

而老同事通過排查日志發(fā)現(xiàn)Error parsing HTTP request header 百度搜索后,果斷調(diào)整max-http-header-size。當(dāng)把max-http-header-size調(diào)整10m時,第三方平臺調(diào)用接口正常并返回驗證失敗錯誤;第三方平臺發(fā)現(xiàn)后跳轉(zhuǎn)驗證規(guī)則后并未反饋該情況給老同事;則為oom埋下深坑;

關(guān)于max-http-header-size引起的oom是什么情況問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI