問題
因為業(yè)務(wù)需求把所有業(yè)務(wù)的域名都搞成相同的砸民,導(dǎo)致Cronet在底層連接出錯的判斷邏輯也跟著出錯了。原因是域名相同后,假如某個業(yè)務(wù)域名所建立的連接一直出錯,但是該連接的端口有1-3個的話榄审,出錯后cronet會記錄內(nèi)存、本地馆衔,后續(xù)有其他業(yè)務(wù)域名命中這個1-3個端口的話瘟判,就會導(dǎo)致一直命中跳過quic連接的邏輯怨绣。本章節(jié)主要分析quic連接出錯狀態(tài)后續(xù)會導(dǎo)致其他連接被誤認為是需要跳過的角溃。
Quic Job創(chuàng)建流程
-
要解決問題,我們首先要弄清楚整個quic job的創(chuàng)建流程篮撑,首先是job_controller控制所有http請求的Job創(chuàng)建减细,來到http_stream_factory_job時候,里面就根據(jù)邏輯判斷來決定走h2還是h3的job赢笨,這里流程圖只涉及Quic job相關(guān)未蝌,具體可以看圖一。
Quic broken邏輯
-
quic創(chuàng)建連接跳過邏輯在http_stream_factory_job_controller.cc里的GetAlternativeServiceInfoInternal函數(shù)里茧妒,在返回AlternativeServiceInfo時候會判斷該域名和端口等元素組合而成的Key是否在broken的數(shù)組里萧吠,如果存在就跳過此次循環(huán),那么就會返回一個默認值的first_alternative_service_info桐筏。源碼如下圖二所示
-
is_broken的判斷邏輯又涉及到broken_alternative_services.cc里面的數(shù)據(jù)儲存了纸型,其中有個儲存broken數(shù)據(jù)的在Quic Job確定連接失敗發(fā)生下面3個錯誤情況下,會將當前host梅忌、port記錄到broken數(shù)組里狰腌。QuicStreamRequest的創(chuàng)建可以由圖一看出在Job::DoInitConnectionImplQuic函數(shù)創(chuàng)建的,那么我們回去看callback函數(shù)即可牧氮。源碼如下圖三所示
DoInitConnectionImplQuic的構(gòu)造函數(shù)再經(jīng)過delegate->onFailedOnDefaultNetwork回調(diào)給上層琼腔,即回調(diào)http_stream_factory_job_controller.cc里,可以看出其中回調(diào)后會把一個標識位置設(shè)置成true踱葛,那么我們繼續(xù)跟著標識位的判斷可以發(fā)現(xiàn)最后走到MaybeReportBrokenAlternativeService函數(shù)里丹莲,而函數(shù)里的MarkAlternativeServiceBrokenUntilDefaultNetworkChanges就會把數(shù)據(jù)記錄到broken_alternative_services.cc里。
//來源于:http_stream_factory_job_controller.cc
void HttpStreamFactory::JobController::OnFailedOnDefaultNetwork(Job* job) {
DCHECK_EQ(job->job_type(), ALTERNATIVE);
alternative_job_failed_on_default_network_ = true;
}
//請求結(jié)束
void HttpStreamFactory::JobController::OnRequestComplete() {
……
MaybeNotifyFactoryOfCompletion();
}
//主要是MarkAlternativeServiceBrokenUntilDefaultNetworkChanges尸诽,他會把host和port信息記錄到broken數(shù)組里
void HttpStreamFactory::JobController::MaybeReportBrokenAlternativeService() {
if (alternative_job_net_error_ == OK &&
!alternative_job_failed_on_default_network_)
return;
……
if (alternative_job_failed_on_default_network_ &&
alternative_job_net_error_ == OK) {
session_->http_server_properties()
->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
alternative_service_info_.alternative_service(),
request_info_.network_isolation_key);
// Reset error status for Jobs after reporting brokenness.
ResetErrorStatusForJobs();
return;
}
……
}
解決問題思路
因為host被業(yè)務(wù)需要改成相同的了甥材,那我們只需要在is_broken基礎(chǔ)上新增一個值來判斷當前的host和port是否為同一條連接即可,因為只有當連接相同情況下并且失敗過才要跳過quic的創(chuàng)建逊谋,如果不是相同的一條連接應(yīng)該嘗試創(chuàng)建quic job擂达。(涉及業(yè)務(wù)代碼的保密性我就不貼出來了)
注意: 不能重載AlternativeService的<、==、!=等符號板鬓,因為這個類很多邏輯都共用到的悲敷,如果修改后原本判斷相同的處理因為新增值就判斷不相同了。所以需要做的工作是在取的時候新增個&&判斷來解決問題俭令。
總結(jié)
- 遇到相關(guān)開發(fā)問題后德,要嘗試理解源碼設(shè)計后再去改動,不要盲目去大改抄腔,畢竟已經(jīng)上線存在那么久了瓢湃,沒有把握情況下盡量小改解決問題。
- 發(fā)現(xiàn)Cronet開源項目做的非常棒赫蛇,不是說能力上(我太菜還沒能全部讀懂)绵患,而是說查詢代碼的體驗上,你點擊函數(shù)還能跳轉(zhuǎn)進具體函數(shù)悟耘,像ide一樣了落蝙。Cronet的源碼鏈接(翻墻)
- broken邏輯還涉及本地序列化和反序列化,這里涉及的代碼和邏輯我會在下一個篇章分析(如果我有時間的話)暂幼。