linux中Cannot assign requested address的問題處理

參考:https://www.phpmianshi.com/?id=109

問題描述:

最近系統報警有類型如下錯誤:Cannot assign requested address  主要是連接mysql時產生的錯誤。

 

分析原因:

客戶端與服務端每建立一個連接,客戶端一側都會佔用一個本地端口(假設沒有啓用SO_REUSEADDR選項),本地端口數量是有限制的(默認是net.ipv4.ip_local_port_range=32768 61000),也就是說在沒設置socket的SO_REUSEADDR選項時,一臺Linux服務器作爲客戶端(注意是作爲客戶端)默認只能建立大概3萬個TCP連接(服務端沒有這個限制),可以更改net.ipv4.ip_local_port_range增大作爲客戶端可發起的併發連接數,但最多不會超過65535個(服務端沒有這個限制)。

當Linux服務器作爲客戶端頻繁建立TCP短連接時,本地會可能會產生很多TIME_WAIT狀態的連接,客戶端側的TIME_WAIT狀態的連接會佔用一個本地端口直到達到2MSL(最長分解生命期)的時間,這樣會導致本地端口被暫時佔用,當短連接建立速度過快時(例如做壓測時),會導致Cannot assign requested address錯誤

 

當系統的內核版本小於 3.2 時:

ip_local_port_range 決定了客戶端的一個 ip 可用的端口數量,即一個 ip 最多隻能創建61000-32768個連接,如果要突破這個限制需要客戶端機器綁定多個 ip

當系統的內核版本大於等於 3.2 時:

ip_local_port_range 決定的是 socket 四元組中的本地端口數量,即一個 ip 對同一個目標 ip+port 最多可以創建61000-32768個連接,只要目標 ip或端口不一樣就可以使用相同的本地端口,不一定需要多個客戶端 ip 就可以突破端口數量限制。

 

解決方法:

設置端口複用(複用TIME_WAIT狀態的連接,稍微調大端口範圍)。

打開文件 /etc/sysctl.conf,增加以下設置

net.ipv4.ip_forward = 1

net.ipv4.tcp_timestamps = 1

net.ipv4.tcp_tw_recycle=1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_fin_timeout = 10

net.ipv4.ip_local_port_range = 20000 61000

net.ipv4.tcp_max_tw_buckets = 200000

net.nf_conntrack_max = 524288

net.netfilter.nf_conntrack_max = 524288

net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60

net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120

net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120

net.netfilter.nf_conntrack_tcp_timeout_established = 3600

fs.file-max=100001

 

運行 sysctl -p即可生效

 

有可能產生的問題

稍微調大端口範圍,有可能會跟系統服務預留的監聽端口衝突

我們可以將服務監聽的端口以逗號分隔全部添加到ip_local_reserved_ports中,TCP/IP協議棧從ip_local_port_range中隨機選取源端口時,會排除ip_local_reserved_ports中定義的端口,因此就不會出現端口被佔用了服務無法啓動。注意他的格式可以是這種:1,2-4,10-10 詳細介紹下面解釋。

2個參數的官方解釋

ip_local_port_range - 2 INTEGERS
	Defines the local port range that is used by TCP and UDP to
	choose the local port. The first number is the first, the
	second the last local port number.
	If possible, it is better these numbers have different parity
	(one even and one odd value).
	Must be greater than or equal to ip_unprivileged_port_start.
	The default values are 32768 and 60999 respectively.

ip_local_reserved_ports - list of comma separated ranges
	Specify the ports which are reserved for known third-party
	applications. These ports will not be used by automatic port
	assignments (e.g. when calling connect() or bind() with port
	number 0). Explicit port allocation behavior is unchanged.

	The format used for both input and output is a comma separated
	list of ranges (e.g. "1,2-4,10-10" for ports 1, 2, 3, 4 and
	10). Writing to the file will clear all previously reserved
	ports and update the current list with the one given in the
	input.

	Note that ip_local_port_range and ip_local_reserved_ports
	settings are independent and both are considered by the kernel
	when determining which ports are available for automatic port
	assignments.

	You can reserve ports which are not in the current
	ip_local_port_range, e.g.:

	$ cat /proc/sys/net/ipv4/ip_local_port_range
	32000	60999
	$ cat /proc/sys/net/ipv4/ip_local_reserved_ports
	8080,9148

	although this is redundant. However such a setting is useful
	if later the port range is changed to a value that will
	include the reserved ports.

	Default: Empty

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章