Ons huidige Kubernetes-kluster wat in Google Container Engine (GKE) loop, bestaan ​​uit n1-standard-1masjientipes (1 virtuele SVE en 3,75 GB geheue) wat Debian GNU/Linux 7.9 (wheezy) gebruik wat deur Google onderhou word. Weens verhoogde vrag en geheuegebruik van ons dienste moet ons ons nodusse na 'n groter masjientipe opgradeer. Terwyl ons dit in ons toetsgroep probeer het, het ons iets ervaar wat (vir ons) nogal vreemd lyk.

Die geheue wat deur die JVM-toepassing verbruik word wanneer dit na 'n Google-nodus ontplooi word, blyk eweredig te wees aan die aantal kerne wat op die nodus beskikbaar is. Selfs as ons die JVM max geheue (Xmx) op 128Mb stel, verbruik dit ongeveer 250Mb op 'n 1-kern masjien (dit is verstaanbaar aangesien die JVM meer geheue verbruik as die maksimum limiet as gevolg van GC, die JVM self ens), maar dit verbruik ongeveer 700Mb op 'n 2-kern masjien ( n1-standard-2) en ongeveer 1,4 Gb op 'n 4-kern masjien ( n1-standard-4). Die enigste ding wat verskil is die masjientipe, dieselfde Docker-beeld en konfigurasies word gebruik.

As ek byvoorbeeld SSH in 'n masjien gebruik met 'n n1-standard-4masjientipe en hardloop sudo docker stats <container_name>, kry ek dit:

CONTAINER CPU %               MEM USAGE / LIMIT    MEM %               NET I/O             BLOCK I/O
k8s.name  3.84%               1.11 GB / 1.611 GB   68.91%              0 B / 0 B 

As ek dieselfde Docker-beeld met presies dieselfde (toepassing) konfigurasie plaaslik (mac osx en docker-masjien) gebruik, sien ek:

CONTAINER CPU %               MEM USAGE / LIMIT    MEM %               NET I/O               BLOCK I/O
name      1.49%               236.6 MB / 1.044 GB  22.66%              25.86 kB / 14.84 kB   0 B / 0 B         

Wat baie meer in pas is met wat ek sou verwag as gevolg van die Xmxinstelling (vir die rekord het ek 8 kerns en 16 Gb geheue). Dieselfde ding word bevestig wanneer ek top -p <pid>op die GKE-instansie hardloop wat my 'n RES/RSS-geheuetoewysing van 1.1 tot 1.4 Gb gee.

Die Docker-beeld word soos volg gedefinieer:

FROM java:8u91-jre
EXPOSE 8080
EXPOSE 8081

ENV JAVA_TOOL_OPTIONS -Dfile.encoding=UTF-8

# Add jar
ADD uberjar.jar /data/uberjar.jar

CMD java -jar /data/uberjar.jar -Xmx128m -server

Ek het ook probeer byvoeg:

ENV MALLOC_ARENA_MAX 4

wat ek in verskeie drade soos hierdie aanbeveel het gesien, maar dit lyk nie of dit enige verskil maak nie. Ek het ook probeer om na 'n ander Java-basisbeeld te verander sowel as om alpine linux te gebruik, maar dit lyk ook nie of dit dinge verander nie.

My plaaslike Docker-weergawe is 1.11.1 en die Docker-weergawe in Kubernetes/GKE is 1.9.1. Die Kubernetes-weergawe (as dit saak maak) is v1.2.4.

Wat ook interessant is, is dat as ons veelvuldige gevalle van die peul/houer na dieselfde masjien/nodus ontplooi, sommige gevalle baie minder geheue sal toeken. Die eerste drie kan byvoorbeeld 1.1-1.4Gb geheue toewys, maar dan ken die 10 opeenvolgende houers slegs ongeveer 250 Mb elk toe, wat ongeveer is wat ek elke keer sou verwaginstansie toe te ken. Die probleem is dat as ons die geheue beperking van die masjien bereik, die eerste drie gevalle (diegene wat 1.1Gb geheue toeken) blykbaar nooit hul toegewese geheue vrystel nie. As hulle geheue sou vrystel wanneer die masjien onder verhoogde druk is, sou ek nie hieroor bekommerd wees nie, maar aangesien hulle die geheuetoewysing behou, selfs wanneer die masjien gelaai is, word dit 'n probleem (aangesien dit verbied dat ander houers op hierdie masjien geskeduleer word en dus word hulpbronne vermors).

Vrae:

  1. Wat kan hierdie gedrag veroorsaak? Is dit 'n JVM-kwessie? Docker-kwessie? VM probleem? Linux kwessie? Konfigurasieprobleem? Of dalk 'n kombinasie?
  2. Wat kan ek probeer doen om die geheuetoewysing van die JVM in hierdie geval te beperk?
answer

Wanneer jy spesifiseer

CMD java -jar /data/uberjar.jar -Xmx128m -server

dan word die waardes wat jy van plan is om JVM-argumente ( -Xmx128m -server) te wees as opdragreëlargumente na die Hoofklas in die .jar-lêer deurgegee. Hulle is beskikbaar as die args in jou public static void main(String... args)metode.

Let daarop dat dit ook waar is as jy 'n hoofklas op naam bestuur, eerder as om 'n uitvoerbare jarlêer te spesifiseer .

Om dit as JVM-argumente, eerder as argumente aan jou program deur te gee, moet jy hulle voor die -jararg.

Sien https://stackoverflow.com/questions/5536476/passing-arguments-to-jar-which-is-required-by-java-interpreter

Die probleem was met die JVM-instellings wat in die Dockerfile. Ons het ons JVM so begin:

CMD java -jar /data/uberjar.jar -Xmx128m -server

maar toe ons oorgeskakel het na:

CMD java -Xmx128m -server -jar /data/uberjar.jar

die instellings is in ag geneem. Ek verstaan ​​egter steeds nie hoekom ek dit nie plaaslik gesien het nie, maar ek is net bly dat ons dit reggekry het.