国产精品chinese,色综合天天综合精品网国产在线,成午夜免费视频在线观看,清纯女学生被强行糟蹋小说

    <td id="ojr13"><tr id="ojr13"><label id="ojr13"></label></tr></td>
        • <source id="ojr13"></source>
            <td id="ojr13"><ins id="ojr13"><label id="ojr13"></label></ins></td>

            Article / 文章中心

            如何定位并修復(fù) HttpCore5 中的 HTTP2 流量控制問題

            發(fā)布時間:2022-01-11 點擊數(shù):1028

            開篇吹一波阿里云性能測試服務(wù) PTS[1],PTS 在 2021 年 5 月份已經(jīng)上線了對 HTTP2 協(xié)議的支持(底層依賴 httpclient5),在壓測時會通過與服務(wù)端協(xié)商的結(jié)果來決定使用 HTTP1.1 或者 HTTP2 協(xié)議。


            01

            背景

            Cloud Native


            寫這篇文章的原因是某天某個客戶找過來,問我們是不是不支持 HTTP2,因為他在 XX 云上購買了 2 個域名,其中一個開啟了 HTTP2,而在 PTS 壓測過程中,支持 HTTP2 的接口總是報錯:

            HTTP2錯誤碼

            起初懷疑是 HTTP2 支持的問題,通過在本地強制使用 HTTP2 協(xié)議,訪問淘寶主頁,發(fā)現(xiàn)是沒問題的,懷疑是用戶在 XX 云上的配置問題,但緊接著通過在本地 Postman、curl 以及壓測引擎強制使用 HTTP1.1 協(xié)議時都能夠正常訪問該網(wǎng)頁,意識到大概率是 PTS 引擎?zhèn)鹊膯栴}。


            通過本地 debug,看到是因為請求 URL 時,客戶端窗口大小被調(diào)整為大于 2^32 -1 導(dǎo)致的異常。


            客戶端窗口大于2^32 -1導(dǎo)致的異常

            那正好借這個機會看下這里的窗口大小指的是什么。

            02

            HTTP2 流控

            Cloud Native


            提到窗口,就要提到 HTTP2 相比于 HTTP1.1 支持的新特性:流控(Flow Control),其實 HTTP1.1 依賴于傳輸層 TCP 的滑動窗口一樣可以實現(xiàn)流控,那么為什么 HTTP2 要在應(yīng)用層再實現(xiàn)一個流控呢?原因在于 HTTP2 引入了流和多路復(fù)用,通過流控可以達(dá)到使多個流協(xié)同的效果。

            一些流控的基本概念:


            1. 流控是針對連接而言的,不是針對端到端的,而是在兩端中的每一跳;主要指有代理的情況下,代理與兩端都存在流控
            2. 流控是基于WINDOW_UPDATE 幀的,接收者可以通過流控控制發(fā)送者的速度
            3. 流控既可以作用于 stream 也可以作用于 connection
            4. 對于連接與所有新開啟的流而言,流控窗口大小默認(rèn)都是 65535,且最大值為 2^32 - 1
            5. 流控?zé)o法禁用

            為了便于理解,先簡單列一下 HTTP2 幀的類型:

            • DATA:攜帶請求或響應(yīng)中的數(shù)據(jù)
            • HEADERS:用于新建一個流(請求或響應(yīng)),包含對應(yīng)的 Headers
            • PRIORITY:用于配置流的優(yōu)先級
            • RST_STREAM:強制結(jié)束某個流,僅用于某一端取消流,并不適用于正常流的結(jié)束
            • SETTINGS:H2 建聯(lián)的一些配置
            • PUSH_PROMISE:服務(wù)端推送響應(yīng)到客戶端
            • PING:向遠(yuǎn)端發(fā)送一條 PING,遠(yuǎn)端必須返回該 PING
            • GOAWAY:用于某一端將要結(jié)束連接
            • WINDOW_UPDATE:更新流控窗口大小

            • CONTINUATION:如果 headers 過大,單個 HEADERS 幀難以攜帶,通過該幀發(fā)送額外的 headers

            接下來,我們重點看下流控相關(guān)的幀,主要是 SETTING 與 WINDOW_UPDATE,在連接建立時會通過 SETTINGS 幀來調(diào)整對方的窗口大小,之后在傳輸過程中,窗口大小會隨著數(shù)據(jù)的發(fā)送逐漸減小,直到收到對方發(fā)送的 WINDOW_UPDATE 幀,從而更新窗口大小。SETTINGS 幀主要包含以下內(nèi)容:

            • SETTINGS_HEADER_TABLE_SIZE:HPACK(一種header壓縮算法) header 表的最大長度,默認(rèn)值 4096
            • SETTINGS_ENABLE_PUSH:客戶端發(fā)向服務(wù)端的配置,若設(shè)置為 true,客戶端將允許服務(wù)端推送響應(yīng),默認(rèn)值 true
            • SETTINGS_MAX_CONCURRENT_STREAMS:同時打開的 stream 最大數(shù)量,通常意味著同一時刻能夠同時響應(yīng)的請求數(shù)量,默認(rèn)無限
            • SETTINGS_INITIAL_WINDOW_SIZE:流控的初始窗口大小,默認(rèn)值 65535
            • SETTINGS_MAX_FRAME_SIZE:對端能夠接受幀的最大長度,默認(rèn)值16384
            • SETTINGS_MAX_HEADER_LIST_SIZE:對端能夠接受的 header 列表最大長度,默認(rèn)不限制

            流控的實現(xiàn)如上所述,每發(fā)送一批 DATA 幀,即將窗口大小減小。需要注意的是流控僅針對 DATA 幀。

            connection 與 stream

            前面提到流控既可以作用于 stream 又可以作用于 connection,那具體是怎么執(zhí)行的呢?connection 的流控與 上述 stream 流控邏輯類似,每次發(fā)送 DATA 幀,connection 與 stream 窗口都會減小,但不同的是,WINDOW_UPDATE 要么單獨作用于 stream,要么單獨作用于 connection(streamid 為 0 時,表示作用于 connection)。


            03

            問題定位

            Cloud Native


            那么回到開篇的問題,我們以 URL https://www.sysgeek.cn/ 為例,通過在本地做代碼 debug 發(fā)現(xiàn),最終拋異常的原因在于接收到 WINDOW_UPDATE 幀后,更新后窗口大小值大于 2^32 - 1 導(dǎo)致拋異常:

            WINDOW_UPDATE

            而從這里的代碼可以看出,524288 是當(dāng)前窗口大小,而delta是對方告知的 WINDOW_UPDATE 大小,通過分析,發(fā)現(xiàn) 524288 這個值不同于默認(rèn)值 65535,那繼續(xù)看這個值是什么時間改動的:

            SETTINGS 指令

            發(fā)現(xiàn)是接收 SETTINGS 指令后,初始化窗口大小時修改的,但這里與 RFC 7540 [2]的描述(connection 窗口大小僅在接收到 WINDOW_UPDATE 后才可能修改)是沖突的:

            httpcore5 的源代碼

            因此我們斷定是 httpcore5 的源代碼有 bug,在刪除標(biāo)記的這行代碼后,請求可以正常執(zhí)行了。

            遺憾的是在準(zhǔn)備給 httpcore5 提 PR 的過程中發(fā)現(xiàn)這個 bug 已經(jīng)在 commit 中被修復(fù)了。