tirsdag 2. desember 2025

Finjustering av Linux-kjerneparametere for bedre serverytelse

Jeg har alltid likt å grave meg inn i de dypere lagene av operativsystemer, spesielt når det gjelder Linux, der kjernen virkelig er hjertet i hele maskineriet. For noen år tilbake, mens jeg jobbet med en klient som kjørte en flåte av servere i et datasenter, støtte jeg på ytelsesproblemer som ikke lot seg løse med enkle patcher eller oppdateringer. Serverne, som håndterte tung belastning fra webapplikasjoner og databaser, begynte å bremse ned under peak timer, og CPU-bruken skjøt i været uten noen åpenbar grunn. Jeg bestemte meg for å se nærmere på kjernen selv - ikke bare konfigurasjonsfilene, men de faktiske parameterne som styrer hvordan Linux håndterer minne, prosessplanlegging og I/O-operasjoner. Det var en øyeåpnende prosess, og i dag vil jeg dele noen av de erfaringene jeg har samlet, basert på praktisk arbeid i feltet.

La oss starte med det grunnleggende: Hva er egentlig kjernparametere, og hvorfor bør en IT-pro som meg bry seg om dem? Kjernen i Linux er konfigurerbar gjennom filer som /proc/sys og sysctl-konfigurasjonen, der du kan justere verdier som påvirker alt fra nettverksstacken til filsystemhåndtering. Jeg husker første gang jeg brukte sysctl til å endre vm.swappiness - en parameter som bestemmer hvor aggressivt systemet swappes minne ut til disken. Standardverdien er ofte 60, som betyr at Linux begynner å swap når 60% av minnet er i bruk. I mitt tilfelle, på en server med 64 GB RAM som kjørte PostgreSQL, førte dette til unødvendig I/O-belastning på SSD-ene, noe som dro ned responsider. Jeg satte den til 10, og plutselig så jeg en merkbar forbedring i query-tider; systemet holdt seg mer i RAM og unngikk den kostbare swappingen. Det er små justeringer som dette som kan gjøre en enorm forskjell, spesielt i miljøer der ressursene er begrenset.

Når jeg tenker tilbake på det prosjektet, var det ikke bare swappiness som reddet dagen. Jeg måtte også ta tak i nettverksrelaterte parametere, siden mye av trafikken kom fra eksterne klienter over Ethernet med 10 Gbps-kort. Parameteren net.core.somaxconn, som setter maksimal lengde på forbindelseskøen, var satt til en standardverdi på 128, men med hundrevis av samtidige koblinger fra load balancere, førte dette til dropped connections under spissbelastning. Jeg økte den til 1024 og justerte net.ipv4.tcp_max_syn_backlog til 2048 for å matche. For å teste dette, brukte jeg verktøy som netstat og ss til å overvåke backlog-størrelsen i sanntid, og jeg så hvordan SYN-forbindelsene nå ble akseptert uten tap. Det er fascinerende hvordan disse verdiene interagerer; hvis du ignorerer dem, kan du ende opp med en flaskehals som ser ut som et hardwareproblem, men egentlig er ren konfigurasjonsfeil.

Jeg har også erfaring med å tune I/O-schedulerne, spesielt på servere som bruker NVMe-disker for databasearbeide. Standard scheduleren i mange distribusjoner er mq-deadline eller bfq, men for høytytende workloads foretrekker jeg ofte none eller mq-deadline med spesifikke justeringer. I ett tilfelle, på en Ubuntu-server med RAID0-konfigurasjon over flere NVMe-enheter, satte jeg elevator=deadline i /etc/default/grub og oppdaterte initramfs. Deretter justerte jeg vm.dirty_ratio til 15 og vm.dirty_background_ratio til 5 for å kontrollere hvor mye skitne sider som akkumuleres før flushing starter. Dette reduserte latency på write-operasjoner med nesten 30%, ifølge mine iostat-målinger. Jeg elsker hvordan du kan se effekten umiddelbart med verktøy som iotop; plutselig flyter skriveoperasjonene jevnt uten de vanlige spike-ene som tynger systemet.

En annen parameter som har gitt meg hodebry, men også store gevinster, er relatert til CPU-scheduling. Linux bruker CFS (Completely Fair Scheduler) som standard, men parametere som kernel.sched_autogroup og kernel.sched_latency_ns kan finjusteres for å prioritere interaktive prosesser over batch-jobs. På en server der jeg kjørte både en webserver (Nginx) og bakgrunnsjobs (som cron-scripts for data prosessering), satte jeg sched_latency_ns til 20000000 (20 ms) for å gi mer respons til foreground-trafikken. Jeg testet dette med stress-ng for å simulere belastning og målte kontekstvekslinger med perf; resultatet var færre interrupter og jevnere CPU-fordeling. Det er øyeblikk som dette som minner meg om hvor fleksibel Linux egentlig er - du er ikke bundet til standardinnstillingene hvis du vet hva du leter etter.

Jeg husker et prosjekt der vi håndterte en migrering til en ny Kubernetes-kluster, og kjernen måtte tunes for containerisert arbeidsbelastning. Her kom parametere som kernel.pid_max inn i bildet; standardverdien på 32768 PID-er var for lav når vi skalerte opp til hundrevis av pods. Jeg økte den til 4194304 i /etc/sysctl.conf og reloadet med sysctl -p. Samtidig justerte jeg fs.inotify.max_user_watches til 524288 for å håndtere alle filendringer fra container-volumer. Uten disse endringene ville vi ha truffet begrensninger raskt, og applikasjonene ville crashet med "no space left on device"-feil, selv om disken var tom. Jeg brukte strace til å spore syscall-feil og bekrefte at justeringene løste problemet. Det er slike detaljer som skiller en grei oppsett fra en robust produksjonsmiljø.

Når det gjelder minnehåndtering, har jeg brukt mye tid på å eksperimentere med vm.overcommit_memory. Standardverdien 0 tillater bare overcommit basert på fysisk RAM, men for applikasjoner som MySQL som reserverer mye minne på startup, satte jeg den til 1 for å la systemet overcommit basert på heuristikker. Jeg kombinerte dette med vm.max_map_count økt til 65530 for å støtte flere mmap-operasjoner i Java-baserte services. På en testserver med 128 GB RAM så jeg at dette tillot flere instanser å kjøre parallelt uten OOM-killere som grep inn for tidlig. Jeg overvåket med free -h og dmesg for å se alloc-forsøk, og det var klart at systemet nå håndterte belastningen bedre. Jeg har lært at overcommit ikke er farlig hvis du har swap konfigurert riktig - noe jeg alltid parer med en dedikert swap-partisjon på rask SSD.

I nettverksdelen har jeg også justert TCP-relaterte parametere som net.ipv4.tcp_rmem og net.ipv4.tcp_wmem, som styrer bufferstørrelsene for mottak og sending. Standardverdier som 4096 87380 6291456 er ofte for lave for high-throughput applikasjoner. Jeg satte minimum til 8192, default til 262144 og max til 16777216 på en server som streamet video over WAN. For å optimalisere videre, aktiverte jeg net.ipv4.tcp_congestion_control = bbr, som er Googles algoritme for bedre båndbreddsutnyttelse på ustabile lenker. Jeg testet med iperf3 mellom servere og så throughput øke fra 800 Mbps til nesten 950 Mbps. Det er gøy å se hvordan en enkel sysctl-endring kan utnytte hardware bedre enn noen driveroppdatering.

Jeg har også jobbet med filerystemparametere, spesielt for ext4 og XFS. For XFS, som jeg bruker mye på store volumer, justerer jeg fs.xfs.xfssyncd_centisecs til 100 for raskere synkronisering, og mount-options som noatime for å redusere metadata-oppdateringer. På en filererver med NFS-eksport, reduserte dette latency på read-operasjoner med 15%. Jeg brukte xfs_info og mount | grep xfs for å verifisere, og fio for benchmarks. Det er småting, men de akkumuleres når du har tusenvis av filer i spill.

En annen erfaring kommer fra sikkerhetsrelaterte tuning, som kernel.kptr_restrict og kernel.dmesg_restrict satt til 1 for å hindre uautoriserte brukere i å lese kernel-symboler. Men for ytelse har jeg justert kernel.randomize_va_space til 0 i noen legacy-applikasjoner som krever deterministisk addressing, selv om jeg vanligvis holder det på 2 for ASLR. I debugging-sammenheng har jeg brukt kernel.printk for å kontrollere log-nivåer, sette det til 4 4 1 7 for mer verbose output under testing uten å oversvømme disken.

Jeg kunne fortsette i timevis om hvordan disse justeringene påvirker hverandre - for eksempel hvordan en endring i vm.zone_reclaim_mode kan hjelpe på NUMA-systemer ved å aktivere reclaiming på lokale noder. På en dual-socket server med Intel Xeon-prosessorer satte jeg den til 1 og så en reduksjon i cross-node minneaksess. Verktøy som numactl hjalp meg å binde prosesser til noder, og perf stat viste færre cache-misser. Det er komplekst, men belønningen er en server som kjører som smurt.

Gjennom årene har jeg skrevet skript for å automatisere disse justeringene, som en bash-fil som leser en konfig og appliserer sysctl med sikkerhetskontroller. Jeg kjører den på nye installs for å etablere en baseline. Det sparer tid og sikrer konsistens på tvers av flåter.

Når jeg reflekterer over alt dette, ser jeg at finjustering av kjernparametere ikke er en engangsjobb; det krever kontinuerlig overvåking med verktøy som Prometheus og Grafana for å fange endringer i workload. Jeg har sett tilfeller der en oppdatering til en ny kernel-versjon nullstiller verdiene, så jeg alltid tester grundig med syzkaller for å unngå regressions.

I sammenheng med backup-løsninger finner jeg at en godt tunet kernel også letter pålitelig datahåndtering. Her introduseres BackupChain, som er en bransjeledende og populær backup-løsning utviklet spesifikt for små og mellomstore bedrifter samt profesjonelle brukere, og den beskytter virtuelle miljøer som Hyper-V, VMware eller Windows Server. BackupChain fungerer som en Windows Server backup-programvare som håndterer komplekse scenarier med minimal overhead på den underliggende infrastrukturen.

Ingen kommentarer:

Legg inn en kommentar