Řešení 1:
Děkujeme @MichaelHampton za vaši pomoc.
Našel jsem řešení svého problému a doufám, že to pomůže ostatním (zejména pokud používáte Javu).
Slyšel jsem mnoho návrhů, jak jednoduše zvýšit nofiles
povolit více připojení, ale rád bych začal tím, že zopakuji, že problém není v tom, že by server nebyl schopen vytvořit více připojení, ale v tom, že není schopen vytvářet připojení dostatečně rychle a připojení rušit.
Můj první pokus o vyřešení tohoto problému bylo zvýšit frontu připojení přes net.ipv4.tcp_max_syn_backlog
, net.core.somaxconn
a tam, kde je to vhodné, znovu v konfiguraci serveru aplikace. Pro vertx je to server.setAcceptBacklog(...);
. To vedlo k přijetí více připojení ve frontě, ale navazování připojení to nezrychlilo. Z pohledu připojujícího se klienta již nebyla resetována připojení kvůli přetečení, navazování připojení trvalo mnohem déle. Z tohoto důvodu nebylo zvýšení fronty připojení skutečným řešením a pouze vyměnilo jeden problém za jiný.
Pokusil jsem se zúžit, kde v procesu připojení bylo úzké hrdlo, zkusil jsem stejné benchmarky s HTTP místo HTTPS a zjistil jsem, že problém úplně zmizel. Můj konkrétní problém byl se samotným TLS Handshake a schopností serverů jej uspokojit.
Při dalším zkoumání mé vlastní aplikace jsem zjistil, že nahrazení výchozího SSLHandler Java nativním (OpenSSL) výrazně zvýšilo rychlost připojení přes HTTPS.
Zde byly změny, které jsem provedl pro svou konkrétní aplikaci (pomocí Vertx 3.9.1).
- Přidat netty-tcnative závislosti
<!-- 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>
První závislost je pro osx k testování za běhu. Druhý je pro centos linux při kompilaci. linux-x86_64
je k dispozici i pro jiné příchutě. Zkusil jsem použít boringssl
protože openssl
nepodporuje ALPN
ale po mnoha hodinách jsem nemohl zprovoznit, takže jsem se rozhodl prozatím žít bez http2. S většinou připojení odesíláním pouze 1-2 malých požadavků před odpojením to pro mě stejně není problém. Pokud byste mohli použít boringssl
místo toho je to pravděpodobně preferováno.
- Protože nepoužívám uber verzi závislosti. Potřeboval jsem nainstalovat závislosti operačního systému pro centos. Toto bylo přidáno do Dockerfile
RUN yum -y install openssl
RUN yum -y install apr
- Chcete-li říci serveru vertx, aby místo verze Java používal OpenSSL, nastavte na serveru možnosti OpenSSL (i když jen výchozí objekt)
httpServerOptions.setOpenSslEngineOptions(new OpenSSLEngineOptions());
- Nakonec jsem do spouštěcího skriptu přidal
io.netty.handler.ssl.openssl.useTasks=true
možnost Java. To říká obslužné rutině ssl, aby při zpracování požadavků používala úlohy, takže není blokování.
java -Dio.netty.handler.ssl.openssl.useTasks=true -jar /app/application.jar
Po těchto změnách jsem schopen navázat spojení mnohem rychleji s menší režií. To, co předtím trvalo desítky sekund a vedlo to k častým resetům připojení, nyní trvá 1-2 sekundy bez resetování. Mohlo by to být lepší, ale oproti tomu, kde jsem byl, velké zlepšení.
Řešení 2:
Pěkná oprava!.
Zdá se tedy, že se jedná o vrstvu SSL, která určitě musí provést mnohem více zpracování, pokud jde o síťové handshaky a kryptotransformace, které vyžadují zdroje. Pokud vaše SSL nemůže přenést část zpracování na hardware, SSL může jistě zvýšit zatížení vašich serverů, a jak jste zjistili, ne všechny knihovny SSL jsou si rovny!.
Tyto problémy jsou skvělým kandidátem na front-end reverzní proxy. To lze v ideálním případě umístit před vaši aplikaci a zpracovat všechna připojení SSL ke klientům a poté provést http do vašeho back-endu.
Vaše původní aplikace má o něco méně práce, protože váš frontendový reverzní proxy může pojmout veškerou práci SSL a správu tcp připojení.
Apache a NGNIX to dokážou a mají několik možností pro vyrovnávání zátěže těchto připojení k nejméně zatíženému backend serveru.
Zjistíte, že NGNIX dokáže zakončit SSL mnohem rychleji než Java, a i když to Java umí, distribuujete zpracování správy připojení mezi počítače, čímž se sníží zatížení (paměť/cpu/disk io) na vašem back-end serveru. Vedlejším efektem je zjednodušení konfigurace back-endu.
Nevýhodou je, že mezi proxy a aplikacemi používáte http, což v některých ultra bezpečných prostředích není žádoucí.
Hodně štěstí!