Om servern är långsam, öka trådarna?
När jag först gick med i företaget, saktade Spring Boot API-servern som jag var ansvarig för ner när det var mycket trafik. Eftersom jag inte visste orsaken började jag med att googla.
”Spring Boot server långsam respons” ”Tomcat prestandajustering”
Som ett resultat av sökningen var de vanligaste råden på bloggar och gemenskaper enkla. ’Öka Trådpoolstorleken på Tomcat. Din förfrågan väntar eftersom det inte finns tillräckligt med arbetare.’
Jag tänkte: ”Aha, vi har ont om arbetare!” Jag tänkte helt enkelt. Jag öppnade omedelbart inställningarna för application.yml och ökade antalet trådar från standardvärdet 200 till 2 000. Enligt mina beräkningar ökade antalet arbetare 10 gånger, så bearbetningshastigheten måste vara snabbare.
Men efter att ha sett övervakningsskärmen efter implementeringen frös jag. Servern rörde sig faktiskt långsammare, CPU-användningen steg i höjden, men antalet förfrågningar som behandlades minskade faktiskt. Det verkade som om arbetarna bara skottade i luften utan att göra något arbete.
Varför i hela friden ökade antalet arbetare, men fabriken blev långsammare? När jag grävde i orsaken kom jag över den dyraste kostnaden för operativsystemet, ”Kontextväxling”.

Recension: Trådar, minns du?
För de som läser den här artikeln för första gången, eller för de som inte känner till innehållet i föregående artikel (Del 4: Processer och trådar), låt oss spola tillbaka en stund.
I vårt ”digitala logistikcenter” världsbild:
Spring Boot är i princip fletrådad. Varje gång en förfrågan kommer in tilldelas en arbetare (tråd) att utföra arbetet. Så jag tänkte helt enkelt: ”Om det finns fler arbetare kommer fler förfrågningar att behandlas samtidigt, eller hur?”
Men det var något jag förbisåg. Det är antalet CPU-kärnor, nyckelarbetarna i vår fabrik.
skiftarbete i ett digitalt distributionscenter
Faktum är att CPU-kärnan, kärnan i en dator, bara kan utföra en uppgift åt gången. (Baserat på singelkärna) Men vi lyssnar på låtar, kodar och använder KakaoTalk samtidigt. Hur är detta möjligt?
Detta beror på att fabrikschefen (OS) beordrar arbetarna (CPU:erna) att ”skifta arbete” i en otroligt snabb hastighet. ”Spela låten i 0,001 sekunder och sluta! Skicka KakaoTalk i nästa 0,001 sekunder och sluta!”
Detta är ”Time Sharing”, och processen där arbetaren lägger ner verktyget och hämtar ett nytt verktyg är ”Context Switching”.
Priset för uppgiftsbyte: dags att byta kläder
Det här är vad som hände när jag ökade antalet trådar till 2 000.
CPU:n är en enda kropp, med 2 000 trådarbetare som ropar ”Bli av med det!” CPU:n möter 2 000 personer kontinuerligt i tur och ordning för att bearbeta arbetet rättvist.
Problemet är att ”förberedelsetid” behövs när man går från arbetstagare A:s arbete till arbetare B:s arbete.
Denna ”tid att spela in, lägga undan och läsa” kallas ”kostnad för sammanhangsbyte (overhead)”. När det finns tillräckligt med arbetskraft är denna kostnad försumbar. Men vad händer om det finns för många arbetare? CPU hamnar i en situation där den organiserar arbetsbok hela dagen, men inte kan utföra något ”faktiskt arbete (beräkning)”. Detta var den verkliga anledningen till att min server var långsam.

[Kodverifiering] Är det nödvändigtvis snabbare bara för att det finns många trådar?
Se är värt att höra. Låt oss bevisa det med kod. Låt oss jämföra hastigheten för att utföra samma mängd additionsoperationer med en tråd och dela upp den i 1 miljon trådar. Sunt förnuft tyder på att 1 miljon enheter borde vara snabbare, men verkligheten är annorlunda.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ContextSwitchingTest {
private static final int TASK_COUNT = 1_000_000;
public static void main(String[] args) throws InterruptedException {
// 1. Bearbeta med en enda trad (ingen skiftarbete)
long start = System.currentTimeMillis();
for (int i = 0; i < TASK_COUNT; i++) {
simpleTask();
}
System.out.println("Enkel trad tid: " + (System.currentTimeMillis() - start) + "ms");
// 2. Bearbeta med massor av tradar (utloser kontextvaxling)
// Skapa en obegransad tradpool (varning: datorn kan frysa)
ExecutorService executor = Executors.newCachedThreadPool();
start = System.currentTimeMillis();
for (int i = 0; i < TASK_COUNT; i++) {
executor.submit(() -> simpleTask());
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);
System.out.println("Multi-trad tid: " + (System.currentTimeMillis() - start) + "ms");
}
private static void simpleTask() {
int a = 1 + 1; // Mycket latt arbete
}
}
Exempel på resultat (varierar beroende på miljö):
Analys: Själva uppgiften (1+1) är så enkel att den kan slutföras på ett ögonblick. Men i den flertrådiga metoden är kostnaden för att skapa en miljon trådar och låta operativsystemet växla fram och tillbaka mellan dem tusentals gånger dyrare än driftstiden. Naveln är större än magen
Lärdomar från praktiken: Hitta rätt ställe
Hur många trådar är då lämpliga för en Spring Boot-server? Svaret beror på ”vad servern gör.”
Men, precis som den situation jag upplevde, är det för mycket att blint öka antalet till 2 000. Detta beror på att när antalet trådar ökar, förbrukas mer minne (stack) och CPU:n överbelastas på grund av kostnader för kontextbyte.
Nyligen har icke-blockerande tekniker som Node.js och Springs WebFlux uppmärksammats för att lösa detta problem. De använder strategin ”öka inte antalet trådar, låt en person bearbeta snabbt utan att stanna.”

Stänger: Det finns ingen gratis lunch
Vi tror ofta felaktigt att ”att bearbeta saker samtidigt är snabbare.” Men i en värld av datorer är ”samtidigt” faktiskt bara höghastighetsskiftarbete, vilket nästan är ett trick.
När du förstår kontextväxling kommer du att se varför serverjustering inte bara handlar om att ”pumpa upp siffrorna”. Urskillningslöst ökade trådar kan faktiskt bli ett gift som kväver servern.
Nu verkar datorns interna fabriker (CPU, RAM, Process) fungera ganska bra. Nu, låt oss öppna fabriksdörren och gå ut. Hur skickar vi data som skapats i vår fabrik till en annan fabrik (kund) långt borta?
Nästa gång kommer vi att prata om nätverk, HTTP och det osynliga vägnätet.