“Den dagen de skulle drepe ham, stod Santiago Nasar opp klokken 5.30 om morgenen for å vente på båten som biskopen kom med. Han hadde drømt at han vandret gjennom en kjempefikenskog hvor det falt bløtt duskregn, og et øyeblikk var han lykkelig …”

Tittelen og formen på denne posten er inspirert av Gabriel Garcia Marquezs roman “Beretninger om et varslet mord”. Et av de sentrale temaene i denne romanen er mordet på Santiago Nasar, som var forutsett og tilsynelatende hadde hele samfunnets velsignelse, mens det i virkeligheten skjer uten at noen egentlig ville det. Dette er et forsøk på en alternativ last- og ytelsesrapport, for helt ærlig hvor gøy er det egentlig å skrive eller lese slike rapporter?

Vi hadde kjørt ml-appen vår i produksjon en liten stund, og alt hadde sett bra ut. Vi var egentlig ganske fornøyde, men de siste dagene hadde vi sett at noe var på gang, minnebruken gjorde noen hopp med jevne mellomrom. Det ble aldri frigitt noe.

Minne er en begrenset ressurs og denne utviklingen er ikke bærekraftig. Vi kommer til å gå tom for minne. I oppsettet vårt er det slik at når grensen for tildelt minne nås vil applikasjonen drepes. Heldigvis skal vi ha introdusert et “Jesus”-gen, så de skal gjenoppstå av seg selv. Dette har vi ikke fått testet i produksjon, så da denne situasjonen oppstod hadde vi et perfekt utgangspunkt for å få verifisert at alle deler fungerte som forutsatt.

Plutselig må det ha skjedd noe dramatisk, to av instansene får en ustoppelig apetitt på minne. Kan ikke være lenge til nå. Vi finner frem kalkulatoren og regner oss frem til at den første instansen vil eksplodere ca kl 8 fredag kveld. Vi kjøper inn popcorn og sitter klare.

Men, vi har tabbet oss ut. I overvåkningsgrafene våre plotter vi minnebruken i GB, mens tildelt minne er GiB. Katastrofen er utsatt! Her er første læringspunkt, sørg for å rapportere i samme skala som man opererer. Spiste popcornet likevel.

Katastrofen er uungåelig, og klokken 23 lørdag kveld skjer det. Og ingen får det egentlig med seg. Før på mandag. Og da er jo alt bare fryd og gammen. Appen har gjenoppstått som den skulle og den spiser minne som tidligere.

Løsningen er verifisert, trafikken ble rutet til en av de andre instansene og kundene merket ingenting.

Det er et kjent ordtak som sier at Python tar det minne den kan få tak i, og frigir bare til seg selv. Vi forventer altså en svakt økende minnebruk. Dette er greit å ha med seg og betyr at du ikke nødvendigvis har gjort noe feil i applikasjonen din.

Vi hadde benyttet biblioteket functools til å håndtere trådene i applikasjonen. Våre undersøkelser tydet på at problemet lå i hvordan vi brukte dette biblioteket. Vi byttet til standard Python trådhåndtering og da ble det rimelig klart hvor problemet var:

Minnebruk ved ulike trådhåndteringsbiblioteker

For å se hvordan forskjellige modellstørrelser påvirker minne- og CPU-bruk trente vi først opp modeller på forskjellige mengder treningsdata. Modellene ble brukt med et oppsett som skulle simulere produksjon.

Maksimalt påtrykk som er målt i produksjon er 600 request/minutt med et snitt på 80 elementer/request. På dette grunnlaget ble det generert en statisk request med 80 elementer som ble kjørt i to tråder. Request-delay ble satt til 200 ms, som gir 2x5 request/sekund = 600 req/min totalt.

Tallene i tabellen under ble plukket ut fra top etter at tallene hadde stabilisert seg etter et par kjøringer.

Her ser vi flere ting:

  • Ved bruk av veldig runde tall — modellstørrelsen dobles for hver 4x økning av treningssettet
  • Minneforbruk korrelerer bra med størrelsen på modellene. Den er ikke helt lineær, stigningen er avtagende (innslag av logaritme).
  • CPU-bruk øker ikke veldig mye selv om modellstørrelsen øker betraktelig.
  • Responstid ligger på snitt 3ms siden CPU holder seg godt under 100%

Alt dette hadde vi gjort før instansen gikk i luften, vi hadde også en ny versjon klar som fikset problemet. Kjøremiljøet vårt er Kubernetes/OpenShift og i løpet av prosessen endte vi også opp med å gjøre endringer i hvordan minne og CPU tildeles.

Aller helst skulle vi sett at problemet ikke hadde oppstått. Når det først skjedde har det, at vi lot katastrofen inntreffe, gjort at vi totalt sett har en bedre løsning nå enn om vi hadde rettet feilen med en gang vi oppdaget den.

--

--