公司內部容器平臺,接入層用nginx作LB,用戶有grpc協議需求,因此在lb層支持grcp反向代理,nginx從1.13開始支持grpc反向代理,將公司使用的nginx包從1.12升級到1.14.0後,增長grpc反向代理配置。配置完成後,打壓力測試時,發現接入層機器端口占滿而致使服務異常,開始追查問題。html
從上述描述能夠看出grpc基於http2,client到server應該保持長鏈接,理論上不該該出現端口占滿的問題linux
Configures the 「TCP keepalive」 behavior for outgoing connections to a gRPC server. By default, the operating system’s settings are in effect for the socket. If the directive is set to the value 「on」, the SO_KEEPALIVE socket option is turned on for the socket.nginx
參考nginx長鏈接相關文檔作了配置調整以後,發現nginx到server依然是短鏈接git
將nginx升級到nginx1.15.6(升級過程當中因爲線上的nginx用到了lua模塊,碰到了lua模塊不適配問題,解決方案見連接lua模塊適配問題)配置grpc_socket_keepalive on,抓包發現,會有少許處理多個請求的長鏈接存在,但大部分依然是短鏈接。github
從debug日誌來看nginx確實嘗試重用連接,可是從實際抓包看,nginx的連接重用的狀況很是少,大部分都是請求處理完以後連接斷開,懷疑nginx對grpc反向代理支持的不夠理想。後端
回到問題自己,要解決的問題是接入層端口占滿,各類調整nginx的長鏈接配置並不能解決這個問題,就嘗試從tcp連接端口回收方面解決,大部分的tcp連接都處於TIME_WAIT狀態。框架
TIME_WAIT狀態的時間是2倍的MSL(linux裏一個MSL爲30s,是不可配置的),在TIME_WAIT狀態TCP鏈接實際上已經斷掉,可是該端口又不能被新的鏈接實例使用。這種狀況通常都是程序中創建了大量的短鏈接,而操做系統中對使用端口數量作了限制最大能支持65535個,TIME_WAIT過多很是容易出現鏈接數佔滿的異常。對TIME_WATI的優化有兩個系統參數可配置:tcp_tw_reuse,tcp_tw_recycle 這兩個參數在網上都有詳細介紹,這是就不展開來說socket
tcp_tw_reuse參考連接tcp
tcp_tw_recycle(Enable fast recycling TIME-WAIT sockets)參考連接post
測試來看,開啓tcp_tw_reuse並無解決端口被佔滿的問題,因此開啓了更激進的tcp_tw_recycle,至此端口占用顯著下降,問題解決,因爲咱們接入層並非用的NAT,因此這個配置不會影響服務。