天啦嚕!生產機器鏈接數飆升到上萬,背後發生了什麼?

我的博客地址 studyidea.cn,點擊查看更多原創文章

0x00. 翻車現場

那是個月黑風高的夜晚,小黑哥成功將新版本發佈到了生產,當心翼翼檢查了應用日誌,後續測試小姐姐驗收成功。html

恩,小黑哥我仍是一如既往的穩~java

接着小黑哥就跑到樓下食堂吃個夜宵,誰知正吃到一半,線上運維同窗發來幾條告警信息,服務器鏈接數過多警告,鏈接數已經飆升到上萬。apache

天啦擼,趕忙放下正在啃的雞腿,火速跑到工位上查看問題。編程

0x01. 歷盡艱辛,深刻排查

打開電腦,首先確認生產交易一切還正常。查看這段時間日誌,發現並無什麼異常狀況,日誌都是正常輸出。沒辦法只好再次走查這次改動的代碼,發現全是業務代碼,並無任何與網絡鏈接有關的代碼改動。segmentfault

問題真的請奇怪,一時半會想不到解決方案,只好先實施重啓大法。重啓事後,鏈接數降低了,到達了正常閾值。可是不一會鏈接數持續升高,不一會仍是升到上萬。數組

這下重啓解決不了辦法,只好從應用出發,找找到底什麼問題。服務器

這個應用是一個路由服務,會根據上游系統指定路由編碼,將交易分發到下游子系統。架構圖以下:網絡

以前在這篇文章路由系統演化史講過,路由系統使用 Dubbo API ,代碼以下:架構

因爲咱們還有另一套系統,也部署這個應用,可是該系統生產機器鏈接數卻不多。交叉比對了兩套系統應用的系統配置值,只有 connections 設置不同,當前有問題的系統設置爲 1000,另一個系統爲 10併發

大體找到緣由,也將 connections 設置爲 10,重啓應用,生產機器鏈接數恢復正常。

0x02. 抽絲剝繭,還原通過

首先咱們來看下 connections 這個配置的做用,能夠直接查看官方文檔http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-reference.html

下面配置來源於:dubbo:reference

總共能夠在三個地方配置 connections 參數,分別爲:dubbo:referencedubbo:consumerdubbo:provider

注意:圖中標示地方實際上與源碼存在出入。截止 Dubbo 2.7.3 版本,圖中 ① 處, dubbo:consumer 文檔上顯示爲 100,實際源碼默認配置爲 0,這點須要注意。另外 ② 處文字描述存在問題,目前 connections 參數主要對 dubbo 協議有用, http 短鏈接協議還未使用該配置

其中 reference.connections 爲服務級別的配置,若未配置將會使用 consumer.connections 配置值。另外這個參數若在 provider.connections 配置,其對服務提供者無效,參數將經過註冊中心傳遞給消費者成爲其默認配置。三者實際做用順序以下:

Debug 源碼,connections 最終會在 DubboProtocol#getClients 被使用,方法源碼以下:

Dubbo 協議默認將會使用 Netty 與服務提供者創建長鏈接

首先將會獲取 connections 配置,規則如上圖,若其大於 0,創建 connections 數量的長鏈接。

若是一個提供者對外暴露 10 個接口,且其有兩個節點。消費者端引入提供者全部服務,配置 connections=1000。當消費者啓動以後,將會馬上建立 1000x2x10=20000 鏈接。這就是生產機器鏈接數飆升的根本緣由

路由服務使用 Dubbo API 編程,服務啓動成功以後,只有上游系統調用路由服務時, Dubbo 纔會與與下游服務提供者創建鏈接,因此現象看起來服務鏈接數是慢慢激增。

若是未設置 connections 參數,Dubbo 將會建立共享鏈接(shareconnections)。消費者調用的服務若爲同一個服務提供者(IP+PORT 區分),這些服務接口將會共享這些鏈接。

shareconnections 能夠在 dubbo:consumer 配置中配置,也能夠在啓動 JVM 參數加入以下配置:

-Dshareconnections=10

若是消費者須要調用同個服務提供者應用的 10 個服務接口,服務提供者提供兩個節點,shareconnections=1000,消費者服務啓動以後,僅會建立 1000*2=2000 鏈接。

這麼對比,shareconnectionsconnections 創建連不是一個量級。

2.1 使用鏈接

消費者調用服務時,將會隨機從鏈接數組中取一個鏈接使用,代碼位於 DubboInvoker#doInvoke

2.2 如何正確配置鏈接數

首先咱們來看下單一長鏈接性能,文檔地址:http://dubbo.apache.org/zh-cn/docs/user/references/protocol/dubbo.html

對於只有少數消費者場景,咱們可使用默認配置,即不配置 connections 參數 。若調用同一個提供者服務過多,能夠考慮適當多配增長 shareconnections。最後若某一服務接口調用量特別大,能夠考慮爲這個服務單獨配置 connections

0x03. 觸類旁通,聊聊其餘配置

Dubbo 還有不少配置項,下面着重介紹一些配置參數。

3.1 dubbo.provider.executes

該參數用來控制每一個方法最大並行數。若是該值設置爲 10 ,每一個服務方法若已有 10 個請求正在處理,第 11 個服務請求將會拋出異常,直到以前服務調用完成,正在請求數量小於 10 未知。

一旦設置 executes>0,Dubbo 將會經過 SPI 機制啓用 ExecuteLimitFilter,源碼仍是比較簡單。

3.2 dubbo.reference.actives

這個參數將會控制消費者每一個服務每一個方法最大併發數。能夠經過 dubbo:method.actives 單獨爲服務方法設置。若是該值爲 10,一旦某個服務某個方法併發數超過 10,第 11 個服務將會等待,若在超時時間內其餘請求執行結束,計數值減值小於閾值,第 11 個請求將會被執行,否者將會拋錯。

dubbo.provider 上也能夠配置這個值,其將會與 connections 同樣,將會傳遞給消費者。

原理等同上面方法,將會啓用 ActiveLimitFilter,源碼以下 :

這裏須要注意 actives 引發超時與服務端超時區別。

3.3 dubbo.protocol.accepts

服務提供者最大鏈接數,若是設置 accepts=10,一旦服務提供者鏈接數大於 10,其他新增鏈接將會被拒絕。

方法源碼以下:

服務提供者斷開鏈接,消費端將會打印鏈接斷開日誌。另外消費者會定時檢查長鏈接可用性,若不可用,將會從新發起鏈接。因此在消費者端就會看到鏈接斷開,重連,而後又被服務提供者斷開的現象。

0x04. 總結

本文經過一次生產鏈接數過多的現象,詳細剖析定位問題的緣由。做爲一個合格的開發,對於開源框架,咱們不只要會熟練使用,也要了解其底層實現,相關參數設置。一旦參數設置不合理就可能引起生產事故。

另外對於生產系統,監控系統很是重要。好比上面的問題,若是沒有監控發現,小黑哥可能一時半會都不知道有這個問題存在,畢竟平時也不會太關注鏈接數這個指標。


好快,已經在家呆了兩週了。哎,出不去,又進不來。之後回想,2020 真是一個使人難忘的一年。。。好了,10 號要正視開工了。

歡迎關注個人公衆號:程序通事,得到平常乾貨推送。若是您對個人專題內容感興趣,也能夠關注個人博客: studyidea.cn

相關文章
相關標籤/搜索