Tăng số lượng kết nối TCP / IP tối đa trong Linux


214

Tôi đang lập trình một máy chủ và có vẻ như số lượng kết nối của tôi bị hạn chế do băng thông của tôi không bị bão hòa ngay cả khi tôi đã đặt số lượng kết nối thành "không giới hạn".

Làm cách nào tôi có thể tăng hoặc loại bỏ số lượng kết nối tối đa mà hộp Ubuntu Linux của tôi có thể mở cùng một lúc? Liệu hệ điều hành có giới hạn điều này, hay nó là bộ định tuyến hoặc ISP? Hay nó là cái gì khác?


2
@Software Monkey: Dù sao tôi cũng trả lời vì tôi hy vọng điều này có thể hữu ích với người thực sự đang viết một máy chủ trong tương lai.
derobert

1
@derobert: Tôi đã thấy +1 đó. Trên thực tế, tôi đã có cùng suy nghĩ sau bình luận trước đó của tôi, nhưng nghĩ rằng tôi sẽ để bình luận đứng.
Lawrence Dol

Câu trả lời:


395

Số lượng kết nối tối đa bị ảnh hưởng bởi các giới hạn nhất định ở cả hai phía máy khách và máy chủ, mặc dù có một chút khác biệt.

Về phía khách hàng: Tăng phạm vi cổng ephermal và giảmtcp_fin_timeout

Để tìm ra các giá trị mặc định:

sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.tcp_fin_timeout

Phạm vi cổng ephermal xác định số lượng ổ cắm ngoài tối đa mà máy chủ có thể tạo từ một địa chỉ IP cụ thể. Việc fin_timeoutxác định thời gian tối thiểu các ổ cắm này sẽ ở TIME_WAITtrạng thái (không sử dụng được sau khi được sử dụng một lần). Mặc định hệ thống thông thường là:

  • net.ipv4.ip_local_port_range = 32768 61000
  • net.ipv4.tcp_fin_timeout = 60

Điều này về cơ bản có nghĩa là hệ thống của bạn không thể đảm bảo nhất quán nhiều hơn (61000 - 32768) / 60 = 470ổ cắm mỗi giây. Nếu bạn không hài lòng với điều đó, bạn có thể bắt đầu với việc tăng port_range. Thiết lập phạm vi 15000 61000là khá phổ biến những ngày này. Bạn có thể tăng thêm tính khả dụng bằng cách giảm fin_timeout. Giả sử bạn làm cả hai, bạn sẽ thấy hơn 1500 kết nối ra ngoài mỗi giây, dễ dàng hơn.

Để thay đổi các giá trị :

sysctl net.ipv4.ip_local_port_range="15000 61000"
sysctl net.ipv4.tcp_fin_timeout=30

Trên đây không nên được hiểu là các yếu tố ảnh hưởng đến khả năng hệ thống để thực hiện các kết nối ra ngoài mỗi giây. Nhưng thay vào đó, các yếu tố này ảnh hưởng đến khả năng xử lý các kết nối đồng thời của hệ thống một cách bền vững trong các "hoạt động" lớn.

Giá trị Sysctl mặc định trên hộp Linux điển hình cho tcp_tw_recycle& tcp_tw_reusesẽ là

net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=0

Những thứ này không cho phép kết nối từ ổ cắm "đã sử dụng" (ở trạng thái chờ) và buộc các ổ cắm phải kéo dài time_waitchu kỳ hoàn chỉnh . Tôi khuyên bạn nên cài đặt:

sysctl net.ipv4.tcp_tw_recycle=1
sysctl net.ipv4.tcp_tw_reuse=1 

Điều này cho phép đạp xe nhanh chóng trong time_waittrạng thái và sử dụng lại chúng. Nhưng trước khi bạn thực hiện thay đổi này, hãy đảm bảo rằng điều này không xung đột với các giao thức mà bạn sẽ sử dụng cho ứng dụng cần các ổ cắm này. Đảm bảo đọc bài "Đối phó với TCP TIME-WAIT" từ Vincent Bernat để hiểu ý nghĩa này. Các net.ipv4.tcp_tw_recycle tùy chọn là khá nhiều vấn đề cho các máy chủ dạng công khai vì nó sẽ không xử lý các kết nối từ hai máy tính khác nhau đằng sau thiết bị NAT cùng , mà là một vấn đề khó khăn để phát hiện và chờ đợi để cắn bạn. Lưu ý rằng net.ipv4.tcp_tw_recycleđã bị xóa khỏi Linux 4.12.

Trên Server Side: Các net.core.somaxconngiá trị có vai trò quan trọng. Nó giới hạn số lượng yêu cầu tối đa được xếp hàng vào một ổ cắm nghe. Nếu bạn chắc chắn về khả năng của ứng dụng máy chủ của mình, hãy nâng nó từ 128 mặc định lên 128 đến 1024. Bây giờ bạn có thể tận dụng mức tăng này bằng cách sửa đổi biến nghe tồn đọng trong cuộc gọi nghe của ứng dụng, thành số nguyên bằng hoặc cao hơn.

sysctl net.core.somaxconn=1024

txqueuelentham số của thẻ ethernet của bạn cũng có vai trò. Giá trị mặc định là 1000, vì vậy hãy nâng chúng lên tới 5000 hoặc thậm chí nhiều hơn nếu hệ thống của bạn có thể xử lý nó.

ifconfig eth0 txqueuelen 5000
echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local

Tương tự tăng giá trị cho net.core.netdev_max_backlognet.ipv4.tcp_max_syn_backlog. Giá trị mặc định của chúng lần lượt là 1000 và 1024.

sysctl net.core.netdev_max_backlog=2000
sysctl net.ipv4.tcp_max_syn_backlog=2048

Bây giờ hãy nhớ bắt đầu cả ứng dụng phía máy khách và máy chủ của bạn bằng cách tăng các ulimts FD, trong shell.

Bên cạnh một kỹ thuật phổ biến hơn được các lập trình viên sử dụng là giảm số lượng cuộc gọi ghi tcp . Sở thích của tôi là sử dụng bộ đệm trong đó tôi đẩy dữ liệu tôi muốn gửi cho khách hàng, và sau đó tại các điểm thích hợp tôi ghi dữ liệu được đệm vào ổ cắm thực tế. Kỹ thuật này cho phép tôi sử dụng các gói dữ liệu lớn, giảm phân mảnh, giảm mức sử dụng CPU của tôi cả ở vùng đất người dùng và ở cấp độ kernel.


4
Câu trả lời rực rỡ! Vấn đề của tôi hơi khác một chút, tức là tôi đã cố gắng chuyển thông tin phiên từ bộ lưu trữ phiên cấp ứng dụng sang redis qua PHP. Vì một số lý do, tôi không thể thêm hơn 28230 phiên mà không thêm nhiều giấc ngủ trong một lần, không có lỗi nào được nhìn thấy trong php hoặc trên nhật ký redis. Chúng tôi đã suy nghĩ về điều này trong cả ngày cho đến khi tôi nghĩ có lẽ vấn đề không nằm ở php / redis mà là ở lớp tcp / ip kết nối cả hai và đi đến câu trả lời này. Quản lý để khắc phục sự cố trong thời gian không lâu sau đó :) Cảm ơn rất nhiều!
s1d

27
Đừng quên rằng chúng ta luôn nói về cổng IP +. Bạn có thể có các ổ cắm "không giới hạn" mở tới cổng XY từ nhiều IP khác nhau. Giới hạn 470 chỉ áp dụng cho các ổ cắm mở đồng thời cho cùng một IP. Một IP khác có thể có 470 kết nối riêng đến các cổng tương tự.
Marki555

6
@ Marki555: Nhận xét của bạn RẤT ĐÚNG. Các ứng dụng được phát triển để tạo và duy trì một số lượng lớn các kết nối ra ngoài, phải có "nhận thức" về các IP có sẵn để tạo các kết nối ra ngoài, và sau đó phải liên kết một cách thích hợp với các địa chỉ IP này bằng cách sử dụng một loại "thuật toán quay vòng" và duy trì một "bảng điểm".
mdk

8
Câu trả lời này có sai lầm. Đầu tiên, net.ipv4.tcp_fin_timeout chỉ dành cho trạng thái FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). Thứ hai, như @Eric đã nói, "470 ổ cắm tại bất kỳ thời điểm nào" là không chính xác.
Sharvanath

3
@mdk: Tôi không rõ với phần tính toán này (61000 - 32768) / 60 = 470 sockets per second. Bạn có thể vui lòng giải thích điều này?
Tom Taylor

64

Có một vài biến để đặt số lượng kết nối tối đa. Rất có thể, bạn sắp hết số tập tin. Kiểm tra ulimit -n. Sau đó, có các cài đặt trong / Proc, nhưng các cài đặt mặc định là hàng chục nghìn.

Quan trọng hơn, có vẻ như bạn đang làm gì đó sai. Một kết nối TCP phải có khả năng sử dụng tất cả băng thông giữa hai bên; nếu không:

  • Kiểm tra xem cài đặt cửa sổ TCP của bạn có đủ lớn không. Mặc định của Linux là tốt cho mọi thứ trừ liên kết inet thực sự nhanh (hàng trăm mbps) hoặc liên kết vệ tinh nhanh. Băng thông * sản phẩm chậm trễ của bạn là gì?
  • Kiểm tra mất gói bằng cách sử dụng ping với các gói lớn ( ping -s 1472...)
  • Kiểm tra giới hạn tỷ lệ. Trên Linux, cái này được cấu hình vớitc
  • Xác nhận rằng băng thông bạn nghĩ tồn tại thực sự tồn tại bằng cách sử dụng, ví dụ: iperf
  • Xác nhận rằng giao thức của bạn là lành mạnh. Nhớ độ trễ.
  • Nếu đây là gigabit + LAN, bạn có thể sử dụng các gói jumbo không? Bạn có phải?

Có thể tôi đã hiểu lầm. Có lẽ bạn đang làm một cái gì đó như Bittorrent, nơi bạn cần rất nhiều kết nối. Nếu vậy, bạn cần tìm hiểu có bao nhiêu kết nối bạn thực sự sử dụng (thử netstathoặc lsof). Nếu con số đó là đáng kể, bạn có thể:

  • Có nhiều băng thông, ví dụ: 100mbps +. Trong trường hợp này, bạn thực sự có thể cần phải lên ulimit -n. Tuy nhiên, ~ 1000 kết nối (mặc định trên hệ thống của tôi) là khá ít.
  • Có vấn đề về mạng đang làm chậm kết nối của bạn (ví dụ: mất gói)
  • Có một cái gì đó làm bạn chậm lại, ví dụ, băng thông IO, đặc biệt nếu bạn đang tìm kiếm. Bạn đã kiểm tra iostat -xchưa

Ngoài ra, nếu bạn đang sử dụng bộ định tuyến NAT cấp tiêu dùng (Linksys, Netgear, DLink, v.v.), hãy cẩn thận rằng bạn có thể vượt quá khả năng của nó với hàng ngàn kết nối.

Tôi hy vọng điều này cung cấp một số trợ giúp. Bạn đang thực sự hỏi một câu hỏi mạng.


16

Để cải thiện câu trả lời của derobert,

Bạn có thể xác định giới hạn kết nối hệ điều hành của mình là gì bằng cách trích dẫn nf_conntrack_max.

Ví dụ: cat / Proc / sys / net / netfilter / nf_conntrack_max

Bạn có thể sử dụng tập lệnh sau để đếm số lượng kết nối tcp vào một phạm vi cổng tcp nhất định. Theo mặc định 1-65535.

Điều này sẽ xác nhận xem bạn có đạt tối đa giới hạn kết nối hệ điều hành hay không.

Đây là kịch bản.

#!/bin/bash
OS=$(uname)

case "$OS" in
    'SunOS')
            AWK=/usr/bin/nawk
            ;;
    'Linux')
            AWK=/bin/awk
            ;;
    'AIX')
            AWK=/usr/bin/awk
            ;;
esac

netstat -an | $AWK -v start=1 -v end=65535 ' $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ {
    if ($1 ~ /\./)
            {sip=$1}
    else {sip=$4}

    if ( sip ~ /:/ )
            {d=2}
    else {d=5}

    split( sip, a, /:|\./ )

    if ( a[d] >= start && a[d] <= end ) {
            ++connections;
            }
    }
    END {print connections}'

3
which awklà bạn của bạn để xác định đường dẫn đến awk, SunOS cũng có một liên kết đến nó :)
Panagiotis Moustafellos

2
@PanagiotisM. whichdựa vào chương trình PATHtrong trường hợp bạn chỉ có thể sử dụng awkthay vì cung cấp đường dẫn đầy đủ. (điều đó nói rằng, tôi không chắc liệu giải pháp trong kịch bản có gần với sự hoàn hảo hơn không, nhưng đây không phải là những gì kịch bản nói về).
Michael Krelin - hacker

5
Tôi thích cách tập lệnh này đi theo đường đạn đạo để xác định awkvị trí, nhưng giả sử rằng shell luôn luôn /bin/bash (mẹo chuyên nghiệp: AIX5 / 6 thậm chí không có bash theo mặc định).
kubanchot

awkphát hiện hữu ích? Cá nhân tôi chỉ đơn giản là sẽ giả định để có một đúng PATHnhưng một sự thay thế hợp lý có thể /usr/bin/env awk/usr/bin/env bashtương ứng. Đối với những gì nó có giá trị, nó đã nhận vị trí sai trên hệ thống Linux của tôi. Không /usr/bin/awkphải thế/bin/awk
Wolph

1
Khi tôi chạy tập lệnh này, tôi nhận được 798, vậy nó có nghĩa là gì?

10

Ở cấp độ ứng dụng, đây là điều mà nhà phát triển có thể làm:

Từ phía máy chủ:

  1. Kiểm tra nếu cân bằng tải (nếu bạn có), hoạt động chính xác.

  2. Biến thời gian chờ TCP chậm thành 503 Phản hồi tức thì nhanh, nếu bạn tải bộ cân bằng hoạt động chính xác, nên chọn tài nguyên làm việc để phục vụ và tốt hơn là treo ở đó với các lỗi mát xa không mong muốn.

Ví dụ: Nếu bạn đang sử dụng máy chủ nút, bạn có thể sử dụng toobusy từ npm. Thực hiện một cái gì đó như:

var toobusy = require('toobusy');
app.use(function(req, res, next) {
  if (toobusy()) res.send(503, "I'm busy right now, sorry.");
  else next();
});

Tại sao 503? Dưới đây là một số hiểu biết tốt cho tình trạng quá tải: http://ferd.ca/queues-don-t-fix-overload.html

Chúng tôi cũng có thể làm một số công việc ở phía khách hàng:

  1. Cố gắng nhóm các cuộc gọi theo đợt, giảm lưu lượng và tổng số yêu cầu b / w máy khách và máy chủ.

  2. Cố gắng xây dựng một lớp giữa bộ đệm để xử lý các yêu cầu trùng lặp không cần thiết.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.