[OS/Linux] Linux核心引數:net.core.somaxconn(高並行場景核心引數)

2023-05-12 12:00:34

0 序言

  • 近期工作在搞壓力測試,我負責開發維護的、基於sring-cloud-gateway巨量資料閘道器微服務,其底層是基於spring-webflux-->reactor-netty-->netty
  • 在壓測過程中(200並行),發現巨量資料閘道器屢報ConnectException: finishConnect(..) failed: Connection refused錯誤。
Caused by: java.net.ConnectException: finishConnect(..) failed: Connection refused
	at io.netty.channel.unix.Errors.newConnectException0(Errors.java:155) ~[netty-transport-native-unix-common-4.1.65.Final.jar!/:4.1.65.Final]
	at io.netty.channel.unix.Errors.handleConnectErrno(Errors.java:128) ~[netty-transport-native-unix-common-4.1.65.Final.jar!/:4.1.65.Final]
	at io.netty.channel.unix.Socket.finishConnect(Socket.java:278) ~[netty-transport-native-unix-common-4.1.65.Final.jar!/:4.1.65.Final]
	at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.doFinishConnect(AbstractEpollChannel.java:710) [netty-transport-native-epoll-4.1.65.Final-linux-x86_64.jar!/:4.1.65.Final]

關鍵行:io.netty.channel.unix.Socket.finishConnect(Socket.java:278) ~[netty-transport-native-unix-common-4.1.65.Final.jar!/:4.1.65.Final]

  • 經過長時間、大量的分析(Debug spring-cloud-gateway 原始碼、觀測服務所屬主機資源),傾向於本微服務所屬主機的net.core.somaxconn不足這種原因。

博主的做法:128 --> 1024

1 引數定義

  • net.core.somaxconn
  • Linux 作業系統全域性引數,每個 TCP連線 監聽埠的佇列長度

somaxconn - INTEGER

  • Limit of socket listen() backlog,在使用者空間中稱為 SOMAXCONN。
  • 預設值為 4096。(在 linux-128.5 之前是 4)
  • 另請參閱tcp_max_syn_backlog,瞭解 TCP 通訊端的其他調整。
  • CentOS/RHEL 7.9 中,預設值為128,對於高並行場景都建議調大該值。
  • 在RHEL 6和RHEL 7中,socket結構的sk_max_ack_backlog欄位被定義為無符號短整型,它將值限制為16位元,最大值為65535。
  • 在 RHEL 8 中,socket結構的sk_max_ack_backlog欄位定義為 u32,它將值限制為 32 位,最大值為 2147483647。

2 檢視方法

2.1 Linux

  • 方法1
cat /proc/sys/net/core/somaxconn
  • 方法2
sysctl -a | grep somaxconn

3 不同應用的設定建議

3.1 Oracle WebLogic Server

https://docs.oracle.com/communications/E96856-01/doc.74/e96850/installing-and-configuring-weblogic-server-cluster1.htm

  • 使用者端數:設定 somaxconn 應至少設定為 1024,以 允許大量使用者端伺服器連線。

排隊的封包數:將netdev_max_backlog設定為至少 32768,以最大程度地減少封包丟失。

3.2 Apache Zookeeper

Configurable listen socket backlog for the client port - issues.apache.org/zookeeper

在 Linux 上,以下引數: net.core.somaxconn 需要大於「使用者端埠積壓工作」以上才能正確設定偵聽通訊端積壓工作

3.3 TiDB

https://blog.csdn.net/weixin_43700866/articTiDBle/details/125667286
核心引數 - pingcap.com

  • 核心引數
檢查各項核心引數的值:
…
`net.core.somaxconn: 32768`

3.4 Nginx

Tuning the Operating System - Nginx.com

net.core.somaxconn 核心引數的值從其預設值 (128) 增加到足以容納大量流量突發的值。在此範例中,它增加到 4096

sudo sysctl -w net.core.somaxconn=4096
...

3.5 Netty

推薦文獻

Caused by: io.netty.channel.ChannelException: Unable to create Channel from class class io.netty.channel.socket.nio.NioSocketChannel
...

優化建議

  • 在面對高並行場景下時,應當適當增大BACKLOG的值,使埠可以同時建立更多的TCP請求
  • 當服務的QPS不高,且伺服器端程序響應請求的時間較長時,可以適當減小BACKLOG的值,避免大量連線佔據系統記憶體資源
  • 在設定BACKLOG引數時,還需要記得修改somaxconn引數,若設定的BACKLOG引數超過了系統somaxconn引數的值時,則無法生效。

netty 原始碼

netty : 4.1.65

  • 預設: ChannelOption.SO_BACKLOG = io.netty.util.NetUtil#SOMAXCONN = /proc/sys/net/core/somaxconn(Windows中預設值:200,Linux中預設值:128)
io.netty.util.NetUtil
	SOMAXCONN
		https://github.com/netty/netty/issues/4936
		/proc/sys/net/core/somaxconn

io.netty.channel.epoll.EpollServerChannelConfig extends EpollChannelConfig implements ServerSocketChannelConfig
	private volatile int backlog = NetUtil.SOMAXCONN;

D:/Program_Data/maven_repository/io/netty/netty-common/4.1.65.Final/netty-common-4.1.65.Final-sources.jar!/io/netty/util/NetUtil.java:134
    io.netty.util.NetUtil#SOMAXCONN
    static {
    	...
                int somaxconn = PlatformDependent.isWindows() ? 200 : 128;
                File file = new File("/proc/sys/net/core/somaxconn");
    	...
	}

    //io.netty.util.internal.logging.InternalLogger | 如何將 netty 紀錄檔開關開啟?

如下是:gateway-service [Debug 原始碼分析] 以本地電腦(8 core cpu)在啟動後的1次請求呼叫為例(與 somaxcon 無關,僅是記錄;NioEventLoop 取決於 CPU 核數)

io.netty.bootstrap.Bootstrap#config

reactor.netty.resources.DefaultLoopResources#cacheNioServerLoops

D:/Program_Data/maven_repository/io/projectreactor/netty/reactor-netty/0.9.20.RELEASE/reactor-netty-0.9.20.RELEASE-sources.jar!/reactor/netty/resources/DefaultLoopResources.java:195
	reactor.netty.resources.DefaultLoopResources#cacheNioServerLoops	
	watch reactor.netty.resources.DefaultLoopResources cacheNioServerLoops returnObj	
io.netty.channel.nio.NioEventLoopGroup
io.netty.channel.nio.NioEventLoop


4 設定方法

4.1.臨時生效

sysctl -w net.core.somaxconn=10240

4.2.永久生效

echo "net.core.somaxconn = 10240" >>/etc/sysctl.conf
sysctl -p

X 參考文獻

/**
 * *******************************************************************
 * 如果不設定超時,連線會一直佔用本地執行緒,埠,連線使用者端一多,阻塞在那裡,會導致本地埠用盡及CPU壓力
 */
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);

未設定超時:
30
io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.1.1:8866
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe$1.run(AbstractNioChannel.java:206)
at io.netty.util.concurrent.PromiseTask$RunnableAdapter.call(PromiseTask.java:38)
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:123)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
at java.lang.Thread.run(Thread.java:745)
Process finished with exit code 0


設定後:
5
io.netty.channel.ConnectTimeoutException: connection timed out: /192.168.1.1:8866
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe$1.run(AbstractNioChannel.java:206)
at io.netty.util.concurrent.PromiseTask$RunnableAdapter.call(PromiseTask.java:38)
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:123)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:353)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
at java.lang.Thread.run(Thread.java:745)
Process finished with exit code 0