Solusi 1:
Terima kasih @MichaelHampton atas bantuan Anda.
Saya menemukan solusi untuk masalah saya, dan mudah-mudahan dapat membantu orang lain (terutama jika Anda menggunakan Java).
Saya telah mendengar banyak saran untuk meningkatkan nofiles
untuk mengizinkan lebih banyak koneksi, tetapi saya ingin memulai dengan menegaskan kembali bahwa masalahnya bukan karena server tidak dapat membuat lebih banyak koneksi, tetapi server tidak dapat membuat koneksi dengan cukup cepat dan memutuskan koneksi.
Upaya pertama saya untuk mengatasi masalah ini adalah dengan menambah antrean koneksi melalui net.ipv4.tcp_max_syn_backlog
, net.core.somaxconn
dan lagi di konfigurasi server aplikasi jika perlu. Untuk vertx ini adalah server.setAcceptBacklog(...);
. Hal ini mengakibatkan menerima lebih banyak koneksi dalam antrean, tetapi tidak mempercepat pembuatan koneksi. Dari sudut pandang klien yang menghubungkan, mereka tidak lagi mengatur ulang koneksi karena luapan, membuat koneksi hanya membutuhkan waktu lebih lama. Karena alasan ini, menambah antrean koneksi bukanlah solusi nyata dan hanya menukar satu masalah dengan masalah lainnya.
Mencoba mempersempit di mana dalam proses koneksi hambatannya, saya mencoba tolok ukur yang sama dengan HTTP alih-alih HTTPS dan menemukan bahwa masalahnya hilang sepenuhnya. Masalah khusus saya adalah dengan TLS Handshake itu sendiri dan kemampuan server untuk memuaskannya.
Dengan menggali lebih dalam aplikasi saya sendiri, saya menemukan bahwa mengganti SSLHandler default Java dengan yang asli (OpenSSL) sangat meningkatkan kecepatan koneksi melalui HTTPS.
Berikut adalah perubahan yang saya buat untuk aplikasi khusus saya (menggunakan Vertx 3.9.1).
- Tambahkan dependensi netty-tcnative
<!-- https://mvnrepository.com/artifact/io.netty/netty-tcnative -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative</artifactId>
<version>2.0.31.Final</version>
<classifier>osx-x86_64</classifier>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-tcnative -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative</artifactId>
<version>2.0.31.Final</version>
<classifier>linux-x86_64-fedora</classifier>
<scope>compile</scope>
</dependency>
Ketergantungan pertama adalah untuk osx untuk menguji saat runtime. Yang kedua adalah untuk centos linux saat dikompilasi. linux-x86_64
tersedia juga untuk rasa lainnya. Saya mencoba menggunakan boringssl
karena openssl
tidak mendukung ALPN
tetapi setelah berjam-jam saya tidak dapat membuatnya berfungsi, jadi saya memutuskan untuk hidup tanpa http2 untuk saat ini. Dengan sebagian besar koneksi hanya mengirim 1-2 permintaan kecil sebelum memutuskan sambungan, ini sebenarnya bukan masalah bagi saya. Jika Anda bisa menggunakan boringssl
sebaliknya, itu mungkin lebih disukai.
- Karena saya tidak menggunakan ketergantungan versi uber. Saya perlu menginstal dependensi os untuk centos. Ini telah ditambahkan ke Dockerfile
RUN yum -y install openssl
RUN yum -y install apr
- Untuk memberi tahu server vertx agar menggunakan OpenSSL alih-alih versi Java, setel opsi OpenSSL di server (meskipun hanya objek default)
httpServerOptions.setOpenSslEngineOptions(new OpenSSLEngineOptions());
- Akhirnya, di skrip run saya, saya menambahkan
io.netty.handler.ssl.openssl.useTasks=true
pilihan ke Jawa. Ini memberi tahu penangan ssl untuk menggunakan tugas saat menangani permintaan sehingga tidak memblokir.
java -Dio.netty.handler.ssl.openssl.useTasks=true -jar /app/application.jar
Setelah perubahan ini, saya dapat membuat koneksi lebih cepat dengan lebih sedikit overhead. Apa yang memakan waktu puluhan detik sebelumnya dan mengakibatkan seringnya reset koneksi sekarang membutuhkan 1-2 detik tanpa reset. Bisa jadi lebih baik, tetapi peningkatan besar dari tempat saya sebelumnya.
Solusi 2:
Perbaikan yang bagus!.
Jadi sepertinya lapisan SSL, tentu harus melakukan lebih banyak pemrosesan, dalam hal jabat tangan jaringan, dan transformasi kripto yang memakan sumber daya. Kecuali jika SSL Anda dapat memindahkan beberapa pemrosesan ke perangkat keras, SSL pasti dapat menambah beban pada server Anda, dan seperti yang Anda ketahui, tidak semua pustaka SSL dibuat sama!.
Masalah-masalah ini adalah kandidat yang bagus untuk proxy balik ujung depan. Ini idealnya dapat ditempatkan sebelum aplikasi Anda, dan menangani semua koneksi SSL ke klien, lalu melakukan http ke backend Anda.
Aplikasi asli Anda memiliki sedikit hal yang harus dilakukan, karena proksi terbalik ujung depan Anda dapat menyerap semua pekerjaan SSL, dan manajemen koneksi tcp.
Apache dan NGNIX dapat melakukan ini, dan memiliki beberapa opsi untuk menyeimbangkan beban koneksi tersebut ke server backend yang memuat paling sedikit.
Anda akan menemukan bahwa NGNIX dapat melakukan terminasi SSL jauh lebih cepat daripada java, dan bahkan jika java bisa, Anda mendistribusikan pemrosesan manajemen koneksi ke seluruh mesin, sehingga mengurangi beban (memori/cpu/disk io) di server back end Anda. Anda mendapatkan efek samping dengan membuat konfigurasi bagian belakang menjadi lebih sederhana.
Kelemahannya adalah Anda menggunakan http antara proxy dan aplikasi Anda, yang di beberapa lingkungan yang sangat aman tidak diinginkan.
Semoga Sukses!