此為臨時(shí)鏈接更鲁,僅用于預(yù)覽谴蔑,將在短期內(nèi)失效烘豹。[關(guān)閉](javascript:;)
關(guān)于OKHttp的一些經(jīng)驗(yàn)總結(jié)
言錫 [言錫](javascript:void(0);) 7月5日
“ 從問題出發(fā)喂江,學(xué)習(xí)OkHttp。”
這篇文章從問題的背景開始悴能,圍繞OkHttp介紹該問題的解決方案揣钦,OkHttp的部分源碼解讀以及其中涉及的技術(shù)點(diǎn)。
01
—
背景
自己owner的一個(gè)服務(wù)漠酿,在國(guó)外機(jī)房經(jīng)常出現(xiàn)調(diào)用第三方連接超時(shí)的異常冯凹。前段時(shí)間忙于其他工作沒空理它,直到最近收到了用戶的幾例反饋炒嘲,才下決心要解決這個(gè)問題宇姚。
這個(gè)服務(wù)是一個(gè)dubbo服務(wù),為其上層應(yīng)用提供數(shù)據(jù)支持夫凸。數(shù)據(jù)來源于第三方浑劳,服務(wù)中使用了OkHttp框架調(diào)用第3方。服務(wù)的單臺(tái)實(shí)例調(diào)用第3方的qps在5000左右夭拌。
下面是創(chuàng)建OkHttpClient實(shí)例的方法魔熏,httpClient 作為OkHttpClient的單例存在衷咽。
httpClient = new OkHttpClient.Build()
我在日志中發(fā)現(xiàn)的異常信息如下:
可以很明顯的看到,連接超時(shí)了蒜绽。[](http://mp.weixin.qq.com/s?__biz=MjM5NDAwMTA2MA==&mid=2695729815&idx=1&sn=7c7feb801bfb8fcf5dfe4e782a4ba3c1&chksm=83d74b5cb4a0c24a21e621ed3428fd808e80c2c5e806a8162cceee62a5930b0430d5506e0f8c&scene=21#wechat_redirect)
02
—
解決過程
從日志中看到的信息不難得出初步的結(jié)論镶骗,第3方的服務(wù)有問題。所以馬上聯(lián)系了他們躲雅,讓他們排查鼎姊。最后給出的結(jié)論是他們?cè)诤臀覀兿嗤瑱C(jī)器配置下,ab測(cè)試單機(jī)能夠達(dá)到5000qps吏夯,沒有出現(xiàn)我們?nèi)罩局械倪B接超時(shí)錯(cuò)誤此蜈。第3方建議我們自己排查一下即横。
首先噪生,我找運(yùn)維確認(rèn)了我們的vip以及后面的網(wǎng)關(guān)集群有沒有問題,得到的反饋是vip目前負(fù)載較低东囚,沒有出現(xiàn)問題跺嗽。
其次,需要排除下部署服務(wù)的機(jī)器有沒有問題页藻,會(huì)不會(huì)是帶寬不夠桨嫁,因?yàn)榉?wù)不僅要調(diào)第3方,還要接受上層應(yīng)用的請(qǐng)求份帐。我發(fā)現(xiàn)進(jìn)入服務(wù)的單臺(tái)機(jī)器流量在200Mbps左右璃吧,出口流量在50Mbps。也沒有發(fā)現(xiàn)問題废境。
最后畜挨,只能懷疑是自己的代碼方面的問題了。從代碼來看噩凹,只能是網(wǎng)絡(luò)方面的OkHttpClient的參數(shù)配置有問題了巴元。
第一個(gè)發(fā)現(xiàn)的問題是自己沒有指定線程池,而OkHttpClient默認(rèn)的是線程池是:
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
可以看到驮宴,線程池的最大線程數(shù)是Integer的最大值逮刨,意味著可以無限增加線程,顯然是不合理的堵泽。另外再通過查找資料修己,我配置了連接池,最大請(qǐng)求數(shù)等參數(shù)迎罗,最終的OkHttpClient配置如下:
ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
重啟應(yīng)用后睬愤,日志中已經(jīng)沒有看到連接超時(shí)的log了,并且消除了很多TCP中的timewait狀態(tài)佳谦,說明連接得以復(fù)用了戴涝,網(wǎng)絡(luò)性能大幅提升。
03
—
參數(shù)詳解
| 參數(shù)
| 說明
| 備注
|
| executorService
| 執(zhí)行http請(qǐng)求的線程池 | 通過自定義線程池,可以預(yù)估請(qǐng)求量啥刻,從而設(shè)置一個(gè)適合業(yè)務(wù)的值奸鸯。默認(rèn)線程池是可以無限創(chuàng)建線程的,如果把控不好可帽,會(huì)導(dǎo)致系統(tǒng)資源耗盡娄涩。
|
| MAX_IDLE_CONNECTIONS | 連接池的大小
| 默認(rèn)是5,這個(gè)值可以設(shè)置為請(qǐng)求其他系統(tǒng)的qps
|
| KEEP_ALIVE_DURATION | 連接池中的連接的最大時(shí)長(zhǎng)
| 默認(rèn)5分鐘映跟,根據(jù)業(yè)務(wù)場(chǎng)景不同而設(shè)置
|
| DEFAULT_CONNECT_TIMEOUT | 連接超時(shí)時(shí)間
| 默認(rèn)10秒
|
| DEFAULT_READ_TIMEOUT | 讀超市時(shí)間
| 默認(rèn)10秒蓄拣,如果是流式讀,需要設(shè)置長(zhǎng)一點(diǎn)
|
| MAX_REQUEST | OKhttpClient實(shí)例最大的并發(fā)請(qǐng)求數(shù)
| 默認(rèn)64努隙,根據(jù)業(yè)務(wù)需要設(shè)置球恤。一般要大于等于MAX_REQUEST_PER_HOST,如果小于的話,那請(qǐng)求3方的最大并發(fā)不會(huì)超過MAX_REQUEST荸镊。同時(shí)需要考慮線程池的大小
|
| MAX_REQUEST_PER_HOST | 對(duì)單個(gè)被請(qǐng)求方域名的最大請(qǐng)求并發(fā)數(shù)
|
默認(rèn)4咽斧,需要考慮幾點(diǎn):
1,如果被調(diào)用方所支持的最大qps只有500躬存,那么這個(gè)值設(shè)置不要超過500
2张惹,如果okhttpClient實(shí)例只調(diào)用一個(gè)3方服務(wù),那么這個(gè)值建議設(shè)置為和MAX_REQUEST一致
3岭洲,如果okhttpClient要調(diào)用n個(gè)3方宛逗,那么建議n * MAX_REQUEST_PER_HOST接近MAX_REQUEST
同時(shí),需要結(jié)合上述線程池的大小合理設(shè)置
|
04
—
源碼解讀
[圖片上傳失敗...(image-b23fb4-1595856859249)]
微信掃一掃
關(guān)注該公眾號(hào)