max-http-header-size引起的oom是什么情況,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
創(chuàng)新互聯(lián)致力于互聯(lián)網(wǎng)網(wǎng)站建設(shè)與網(wǎng)站營銷,提供網(wǎng)站制作、成都網(wǎng)站建設(shè)、網(wǎng)站開發(fā)、seo優(yōu)化、網(wǎng)站排名、互聯(lián)網(wǎng)營銷、成都小程序開發(fā)、公眾號商城、等建站開發(fā),創(chuàng)新互聯(lián)網(wǎng)站建設(shè)策劃專家,為不同類型的客戶提供良好的互聯(lián)網(wǎng)應(yīng)用定制解決方案,幫助客戶在新的全球化互聯(lián)網(wǎng)環(huán)境中保持優(yōu)勢。
記一次線上OOM事故
根據(jù)用戶反饋,某服務(wù)不能提供服務(wù),然后我們進(jìn)行排查,進(jìn)程id還在,但日志不輸出。通過jstat -gcutil 查看內(nèi)存使用情況;發(fā)現(xiàn)出現(xiàn)Full GC了。
ps -ef | grep --color=auto 項(xiàng)目名 | grep --color=auto -v "grep" | awk '{print $2}' | xargs -i jstat -gcutil {} 2000
S0:幸存1區(qū)當(dāng)前使用比例 S1:幸存2區(qū)當(dāng)前使用比例 E:伊甸園區(qū)使用比例 O:老年代使用比例 M:元數(shù)據(jù)區(qū)使用比例 CCS:壓縮使用比例 YGC:年輕代垃圾回收次數(shù) FGC:老年代垃圾回收次數(shù) FGCT:老年代垃圾回收消耗時(shí)間 GCT:垃圾回收消耗總時(shí)間
當(dāng)年輕代內(nèi)存滿時(shí),會引發(fā)一次普通GC,該GC僅回收年輕代。需要強(qiáng)調(diào)的時(shí),年輕代滿是指Eden代滿,Survivor滿不會引發(fā)GC
當(dāng)年老代滿時(shí)會引發(fā)Full GC,F(xiàn)ull GC將會同時(shí)回收年輕代、年老代
jmap -dump:format=b,file=812.hprof 15968
tar -czf 814.tar.gz 814.hprof
一看就有問題了。
查看Histogram
進(jìn)行引用查看
通過mat分析查看這個(gè)對象內(nèi)存占用很大有10M左右,所以重點(diǎn)對這個(gè)類分析,看看干了什么。
org.apache.coyote.Response#outputBuffer這個(gè)類是tomcat輸出到socket時(shí)的類。
問題就在這里了,這里的對象內(nèi)存10m左右!?。?/p>
這個(gè)值怎么來的呢?老同事設(shè)置的,也不知道當(dāng)初為啥設(shè)置這個(gè)值。這個(gè)原因后面給出
server: max-http-header-size: 10000000
源碼分析,后方高能!查看tomcat調(diào)用鏈路
org.apache.catalina.connector.CoyoteAdapter#service
最后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()); } } }
也就是一個(gè)請求會返回10m數(shù)據(jù)給前端,在用jemter100個(gè)并發(fā)測試時(shí),堆內(nèi)存直接打滿。服務(wù)停止。
由于項(xiàng)目提供的api接口提供給第三方平臺使用,用戶身份校驗(yàn)是放在header里來做的。當(dāng)?shù)谌狡脚_沒按著規(guī)范來傳值呢?系統(tǒng)發(fā)生錯(cuò)誤。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 { // 這行代碼報(bào)錯(cuò) if (!inputBuffer.parseRequestLine(keptAlive)) { if (inputBuffer.getParsingRequestLinePhase() == -1) { return SocketState.UPGRADING; } else if (handleIncompleteRequestLineRead()) { break; } } ..... } catch (IOException e) { if (log.isDebugEnabled()) { // 打印錯(cuò)誤。。。。。。 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
protected SocketChannel sc = null; @Override public int read(ByteBuffer dst) throws IOException { return sc.read(dst); }
org.apache.coyote.http11.Http11InputBuffer#init
報(bào)錯(cuò)原因在于,SocketChannel.read的數(shù)據(jù)大于接受的buffer了。默認(rèn)buffer的是16kb,如果超出則報(bào)錯(cuò)。而tomcat遇到這個(gè)錯(cuò)誤時(shí)并沒有拋出該異常,而是記錄日志;并輸出結(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時(shí),第三方平臺調(diào)用接口正常并返回驗(yàn)證失敗錯(cuò)誤;第三方平臺發(fā)現(xiàn)后跳轉(zhuǎn)驗(yàn)證規(guī)則后并未反饋該情況給老同事;則為oom埋下深坑;
關(guān)于max-http-header-size引起的oom是什么情況問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。