Skip to content

Minnetak på et nettstedsbygg på en server med 1,7 GB

Dette nettstedet bygger seg selv på en server med én CPU og 1,7 GB minne. Uten tak toppet bygget på 677–689 MiB; et systemd-tak på 450 MiB kostet ingenting målbart. Hva de to minnetallene betyr, og hva som ikke virket.

  • Linux
  • systemd
  • Selvhostet
  • Utrulling

Dette nettstedet rulles ut med en push. En Gitea-webhook skriver en triggerfil, en systemd path-enhet plukker den opp, og en oneshot-tjeneste kjører npm ci, astro build inn i en fersk releases/<sha>-<tid>/-katalog og bytter dist-symlenken med én rename. Et bygg som feiler, lar den kjørende utgaven stå. Serveren er den samme som kjører e-posten, wikien og to produkter: én CPU, 1707 MiB minne, og rundt 1 GB av det i swap en vanlig dag.

To tall, ikke ett

Utrullingsskriptet logger to minnetall per kjøring. Nedre grense er maks RSS for den største prosessen, astro build, fra /usr/bin/time. Øvre grense er hele jobbens cgroup memory.peak, som teller alle prosessene i enheten og sidebufferet bygget tar i bruk. På de to kjøringene uten tak 2026-10-13 toppet astro-prosessen på 296,6 og 284,3 MiB; cgroupen på 676,8 og 688,8 MiB. Gapet er npm ci og buffer, og cgroup-tallet er det kjernen vil handle på.

Taket

Enheten har nå MemoryHigh=450M, MemoryMax=700M, Nice=10 og best-effort IO med prioritet 7. Over MemoryHigh gjenvinner og struper kjernen jobben; over MemoryMax dreper den jobben, og utrullingsskriptet fjerner da den halvbygde utgaven og lar dist peke der den pekte. 450 MiB er med vilje under det bygget brukte uten tak: det meste av toppen var sidebuffer, som er det første gjenvinningen tar.

Hva det kostet: ingenting målbart

Hver utrulling med tak har fullført — tolv av tolv per 13:43 den 2026-10-13. Hver kjørings cgroup-topp ligger på 472,1–472,3 MB, altså 450 MiB-linjen, som ventet. Selve astro-prosessen toppet på 260–272 MiB per kjøring, og bygget tok 20,1–29,9 sekunder mot 22,7 og 25,8 sekunder uten tak. Hele utrullingen, fra trigger til symlenke, tar omtrent ett minutt. På en maskin med én CPU betyr Nice=10 mer enn minnelinjen for den som bruker e-postserveren under en push.

To ting som ikke virket

MemoryDenyWriteExecute=yes, den vanlige herdingslinjen, krasjer Node: JIT-en trenger sider som er skrivbare og deretter kjørbare. Enheten sier det i en kommentar, så nestemann ikke legger den inn igjen. Og systemds egen MemoryPeak= på en oneshot-tjeneste er ikke et tall per kjøring: den meldte samme 716,8 M på hver kjøring uten tak og leses som usatt etterpå. Skriptet leser memory.peak fra cgroupen selv og skriver det til utrullingsloggen, der det kan sammenlignes kjøring for kjøring.

Åpent

npm ci kjører ved hver utrulling og er den tyngste fasen; en kollegas avlesning av top under to pusher satte den til omtrent 425 MB resident. Å hoppe over den når låsfilen er uendret, ville fjernet fasen fra de fleste utrullingene. Ikke gjort ennå; det er fem linjer og en avgjørelse.

← alle notater

esc
↑↓ naviger ↵ åpne esc lukk