Meningkatkan jumlah maksimum koneksi TCP / IP di Linux

214

Saya sedang memprogram server dan sepertinya jumlah koneksi saya terbatas karena bandwidth saya tidak sedang jenuh bahkan ketika saya telah mengatur jumlah koneksi ke "tidak terbatas".

Bagaimana saya bisa menambah atau menghilangkan jumlah koneksi maksimum yang bisa dibuka oleh kotak Linux Ubuntu saya sekaligus? Apakah OS membatasi ini, atau itu router atau ISP? Atau itu sesuatu yang lain?

red0ct
sumber
2
@Software Monkey: Saya tetap menjawab ini karena saya berharap ini mungkin berguna bagi seseorang yang sebenarnya sedang menulis server di masa depan.
derobert
1
@derobert: Saya melihat +1 itu. Sebenarnya, saya memiliki pemikiran yang sama setelah komentar saya sebelumnya, tetapi berpikir saya akan membiarkan komentar itu bertahan.
Lawrence Dol

Jawaban:

396

Jumlah koneksi maksimum dipengaruhi oleh batas-batas tertentu di kedua sisi klien & server, meskipun sedikit berbeda.

Di sisi klien: Tingkatkan jangkauan port ephermal, dan kurangitcp_fin_timeout

Untuk mengetahui nilai default:

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

Rentang port ephermal menentukan jumlah maksimum soket keluar yang dapat dibuat oleh suatu host dari alamat IP tertentu. Yang fin_timeoutmenentukan waktu minimum soket ini akan tetap dalam TIME_WAITkeadaan (tidak dapat digunakan setelah digunakan sekali). Default sistem yang biasa adalah:

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

Ini pada dasarnya berarti sistem Anda tidak dapat secara konsisten menjamin lebih dari (61000 - 32768) / 60 = 470soket per detik. Jika Anda tidak senang dengan itu, Anda bisa mulai dengan meningkatkan port_range. Mengatur rentang menjadi 15000 61000sangat umum hari ini. Anda selanjutnya dapat meningkatkan ketersediaan dengan mengurangi fin_timeout. Misalkan Anda melakukan keduanya, Anda akan melihat lebih dari 1500 koneksi keluar per detik, lebih mudah.

Untuk mengubah nilai :

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

Hal di atas tidak boleh diartikan sebagai faktor yang memengaruhi kemampuan sistem untuk membuat koneksi keluar per detik. Melainkan faktor-faktor ini memengaruhi kemampuan sistem untuk menangani koneksi bersamaan secara berkelanjutan untuk "aktivitas" yang besar.

Nilai Sysctl default pada kotak Linux khas untuk tcp_tw_recycle& tcp_tw_reuseakan

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

Ini tidak memungkinkan koneksi dari soket "bekas" (dalam kondisi menunggu) dan memaksa soket untuk bertahan selama time_waitsiklus penuh. Saya merekomendasikan pengaturan:

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

Ini memungkinkan perputaran soket yang cepat di time_waitnegara bagian dan menggunakannya kembali. Tetapi sebelum Anda melakukan perubahan ini pastikan bahwa ini tidak bertentangan dengan protokol yang akan Anda gunakan untuk aplikasi yang membutuhkan soket ini. Pastikan Anda membaca pos "Mengatasi TCP TIME-WAIT" dari Vincent Bernat untuk memahami implikasinya. The net.ipv4.tcp_tw_recycle pilihan adalah cukup bermasalah untuk server publik menghadap karena tidak akan menangani koneksi dari dua komputer yang berbeda di belakang perangkat NAT yang sama , yang merupakan masalah sulit untuk mendeteksi dan menunggu untuk menggigit Anda. Catatan yang net.ipv4.tcp_tw_recycletelah dihapus dari Linux 4.12.

Pada Server Side: The net.core.somaxconnvalue memiliki peran penting. Ini membatasi jumlah permintaan maksimum yang di-antri ke soket pendengaran. Jika Anda yakin dengan kemampuan aplikasi server Anda, ubahlah dari default 128 menjadi sesuatu seperti 128 hingga 1024. Sekarang Anda dapat memanfaatkan peningkatan ini dengan memodifikasi variabel backlog mendengarkan dalam panggilan mendengarkan aplikasi Anda, ke integer yang sama atau lebih tinggi.

sysctl net.core.somaxconn=1024

txqueuelenparameter kartu ethernet Anda juga memiliki peran untuk dimainkan. Nilai defaultnya adalah 1000, jadi tambah 5000 atau bahkan lebih jika sistem Anda dapat mengatasinya.

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

Demikian pula menaikkan nilai untuk net.core.netdev_max_backlogdan net.ipv4.tcp_max_syn_backlog. Nilai default masing-masing adalah 1000 dan 1024.

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

Sekarang ingat untuk memulai aplikasi sisi klien dan server Anda dengan meningkatkan FD FDIM, di shell.

Selain itu satu lagi teknik populer yang digunakan oleh programmer adalah mengurangi jumlah panggilan tulis tcp . Preferensi saya sendiri adalah menggunakan buffer di mana saya mendorong data yang ingin saya kirim ke klien, dan kemudian pada titik yang tepat saya menuliskan data buffered ke dalam soket yang sebenarnya. Teknik ini memungkinkan saya untuk menggunakan paket data besar, mengurangi fragmentasi, mengurangi pemanfaatan CPU saya baik di tanah pengguna dan di tingkat kernel.

mdk
sumber
4
Jawaban yang brilian! Masalah saya agak berbeda, yaitu saya mencoba memindahkan info sesi dari penyimpanan sesi level aplikasi ke redis melalui PHP. Untuk beberapa alasan, saya tidak bisa menambahkan lebih dari 28230 sesi tanpa menambahkan banyak tidur dalam sekali jalan, tanpa kesalahan yang terlihat baik di php atau pada redis log. Kami mematahkan kepala kami tentang hal ini sepanjang hari sampai saya pikir mungkin masalahnya bukan dengan php / redis tetapi pada lapisan tcp / ip yang menghubungkan keduanya dan sampai pada jawaban ini. Berhasil memperbaiki masalah dalam waktu singkat setelah itu :) Terima kasih banyak!
s1d
27
Jangan lupa bahwa kita selalu berbicara tentang IP + port. Anda dapat membuat soket "tidak terbatas" terbuka ke port XY dari banyak IP yang berbeda. Batas 470 berlaku untuk soket terbuka bersamaan hanya untuk IP yang sama. IP lain dapat memiliki koneksi 470 sendiri ke port yang sama.
Marki555
6
@ Marki555: Komentar Anda SANGAT BENAR. Aplikasi yang dikembangkan untuk menghasilkan dan mempertahankan sejumlah besar koneksi keluar, harus memiliki "kesadaran" IP yang tersedia untuk membuat koneksi keluar, dan kemudian harus secara tepat mengikat alamat IP ini menggunakan semacam "algoritma round-robin", dan memelihara sebuah "papan skor".
mdk
8
Jawaban ini memiliki kesalahan. Pertama, net.ipv4.tcp_fin_timeout hanya untuk keadaan FIN_WAIT_2 ( cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt ). Kedua, seperti yang dikatakan @Eric, "470 soket pada waktu tertentu" tidak benar.
Sharvanath
3
@ mdk: Saya tidak jelas dengan bagian perhitungan ini (61000 - 32768) / 60 = 470 sockets per second. Bisakah Anda jelaskan hal ini?
Tom Taylor
64

Ada beberapa variabel untuk mengatur jumlah koneksi maksimal. Kemungkinan besar, Anda kehabisan nomor file terlebih dahulu. Periksa ulimit -n. Setelah itu, ada pengaturan di / proc, tetapi yang default ke puluhan ribu.

Lebih penting lagi, sepertinya Anda melakukan sesuatu yang salah. Koneksi TCP tunggal harus dapat menggunakan semua bandwidth antara dua pihak; jika tidak:

  • Periksa apakah pengaturan jendela TCP Anda cukup besar. Standar Linux bagus untuk semuanya kecuali tautan inet sangat cepat (ratusan mbps) atau tautan satelit cepat. Apa produk penundaan * bandwidth Anda?
  • Periksa packet loss menggunakan ping dengan paket besar ( ping -s 1472...)
  • Periksa batasan tarif. Di Linux, ini dikonfigurasi dengantc
  • Konfirmasikan bahwa bandwidth yang Anda pikir ada benar-benar ada menggunakan misalnya iperf
  • Konfirmasikan bahwa protokol Anda waras. Ingat latensi.
  • Jika ini gigabit + LAN, dapatkah Anda menggunakan paket jumbo? Apakah kamu?

Mungkin saya salah paham. Mungkin Anda melakukan sesuatu seperti Bittorrent, di mana Anda membutuhkan banyak koneksi. Jika demikian, Anda perlu mencari tahu berapa banyak koneksi yang sebenarnya Anda gunakan (coba netstatatau lsof). Jika angka itu substansial, Anda mungkin:

  • Memiliki banyak bandwidth, mis., 100mbps +. Dalam hal ini, Anda mungkin benar - benar perlu menaikkan ulimit -n. Namun, ~ 1000 koneksi (standar pada sistem saya) cukup sedikit.
  • Memiliki masalah jaringan yang memperlambat koneksi Anda (mis., Paket loss)
  • Miliki sesuatu yang memperlambat Anda, misalnya, bandwidth IO, terutama jika Anda mencari. Sudahkah Anda memeriksanya iostat -x?

Juga, jika Anda menggunakan router NAT tingkat konsumen (Linksys, Netgear, DLink, dll.), Berhati-hatilah bahwa Anda dapat melebihi kemampuannya dengan ribuan koneksi.

Saya harap ini memberikan bantuan. Anda benar-benar mengajukan pertanyaan jaringan.

derobert
sumber
16

Untuk memperbaiki jawaban yang diberikan oleh derobert,

Anda dapat menentukan berapa batas koneksi OS Anda dengan mengetikkan nf_conntrack_max.

Sebagai contoh: cat / proc / sys / net / netfilter / nf_conntrack_max

Anda dapat menggunakan skrip berikut untuk menghitung jumlah koneksi tcp ke kisaran port tcp yang diberikan. Secara default 1-65535.

Ini akan mengkonfirmasi apakah Anda memaksimalkan batas koneksi OS atau tidak.

Ini skripnya.

#!/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}'
whitehat237
sumber
3
which awkadalah teman Anda untuk menentukan jalur menuju awk, SunOS juga memiliki tautan ke sana :)
Panagiotis Moustafellos
2
@PanagiotisM. whichbergantung pada program untuk berada dalam PATHhal ini Anda hanya dapat menggunakan awkalih-alih memberikan path lengkap. (yang mengatakan, saya tidak yakin apakah solusi dalam naskah mendekati kesempurnaan, tetapi ini bukan tentang naskah itu).
Michael Krelin - hacker
5
Saya suka bagaimana script ini berjalan balistik untuk menentukan awklokasi, tetapi mengasumsikan bahwa shell selalu /bin/bash (tip pro: AIX5 / 6 bahkan tidak memiliki bash secara default).
kubanczyk
Apakah awkdeteksi bermanfaat? Secara pribadi saya hanya akan menganggap memiliki yang benar PATHtetapi alternatif yang masuk akal bisa /usr/bin/env awkdan /usr/bin/env bashmasing - masing. Untuk apa nilainya, itu salah lokasi pada sistem Linux saya. Ini /usr/bin/awkbukan/bin/awk
Wolph
1
ketika saya menjalankan skrip ini saya mendapatkan 798, jadi apa artinya?
10

Di level aplikasi, berikut adalah hal yang bisa dilakukan pengembang:

Dari sisi server:

  1. Periksa apakah load balancer (jika ada), berfungsi dengan benar.

  2. Ubah waktu tunggu TCP yang lambat menjadi 503 Respons Cepat Segera, jika Anda memuat penyeimbang berfungsi dengan benar, ia harus memilih sumber daya kerja untuk dilayani, dan lebih baik daripada menggantung di sana dengan pijatan kesalahan yang tidak terduga.

Misalnya: Jika Anda menggunakan server simpul, Anda dapat menggunakan toobusy dari npm. Implementasi sesuatu seperti:

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

Kenapa 503? Berikut adalah beberapa wawasan yang bagus untuk kelebihan: http://ferd.ca/queues-don-t-fix-overload.html

Kami juga dapat melakukan beberapa pekerjaan di sisi klien:

  1. Cobalah untuk mengelompokkan panggilan dalam batch, mengurangi lalu lintas dan jumlah permintaan total klien dan server.

  2. Cobalah untuk membangun lapisan tengah cache untuk menangani permintaan duplikat yang tidak perlu.

Kev
sumber