تتكون مجموعة Kubernetes الحالية التي تعمل في Google Container Engine (GKE) من n1-standard-1أنواع الأجهزة (1 وحدة معالجة مركزية افتراضية و 3.75 غيغابايت من الذاكرة) التي تعمل بنظام Debian GNU / Linux 7.9 (Wheezy) الذي تتم صيانته بواسطة Google. نظرًا لزيادة التحميل واستخدام الذاكرة لخدماتنا ، نحتاج إلى ترقية عقدنا إلى نوع جهاز أكبر. أثناء تجربة ذلك في مجموعة الاختبار الخاصة بنا ، اختبرنا شيئًا (بالنسبة لنا) يبدو غريبًا جدًا.

يبدو أن الذاكرة التي يستهلكها تطبيق JVM عند نشرها في عقدة Google تتناسب مع عدد النوى المتوفرة في العقدة. حتى إذا قمنا بتعيين ذاكرة JVM max (Xmx) على 128 ميجا بايت ، فإنها تستهلك حوالي 250 ميجا بايت على جهاز واحد أساسي (هذا أمر مفهوم لأن JVM يستهلك ذاكرة أكبر من الحد الأقصى بسبب GC ، و JVM نفسه ، إلخ) ، ولكنه يستهلك حوالي 700 ميجا بايت على جهاز ثنائي النواة ( n1-standard-2) وحوالي 1.4 جيجا بايت على جهاز رباعي النواة ( n1-standard-4). الشيء الوحيد المختلف هو نوع الجهاز ، ويتم استخدام نفس صورة Docker والتكوينات.

على سبيل المثال ، إذا قمت بإدخال SSH إلى جهاز باستخدام n1-standard-4نوع الجهاز وتشغيله ، فسأحصل sudo docker stats <container_name>على هذا:

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 

عندما أقوم بتشغيل نفس صورة Docker بنفس التكوين (التطبيق) بالضبط محليًا (mac osx و docker-machine) أرى:

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         

وهو أكثر انسجامًا مع ما أتوقعه بسبب Xmxالإعداد (بالنسبة للسجل ، لدي 8 نوى وذاكرة 16 جيجابايت). تم تأكيد نفس الشيء عند تشغيل top -p <pid>مثيل GKE الذي يمنحني تخصيص ذاكرة RES / RSS من 1.1 إلى 1.4 جيجا بايت.

يتم تعريف صورة Docker على النحو التالي:

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

لقد حاولت أيضًا إضافة:

ENV MALLOC_ARENA_MAX 4

التي رأيتها موصى بها في العديد من المواضيع مثل هذا ولكن لا يبدو أنها تحدث أي فرق على الإطلاق. لقد حاولت أيضًا التغيير إلى صورة قاعدة Java أخرى بالإضافة إلى استخدام alpine linux ولكن لا يبدو أن هذا يغير الأشياء أيضًا.

إصدار Docker المحلي الخاص بي هو 1.11.1 وإصدار Docker في Kubernetes / GKE هو 1.9.1. إصدار Kubernetes (إذا كان مهمًا) هو v1.2.4.

الأمر المثير للاهتمام أيضًا هو أنه إذا قمنا بنشر مثيلات متعددة من الحاوية / الحاوية على نفس الجهاز / العقدة ، فإن بعض الحالات ستخصص ذاكرة أقل بكثير. على سبيل المثال ، قد تخصص الثلاثة الأولى 1.1-1.4 جيجا بايت من الذاكرة ولكن بعد ذلك العشر حاويات التالية تخصص فقط حوالي 250 ميجا بايت لكل منها وهو ما أتوقعه تقريبًا كلمثيل لتخصيص. تكمن المشكلة في أنه إذا وصلنا إلى الحد من ذاكرة الجهاز ، فإن الحالات الثلاث الأولى (تلك التي تخصص ذاكرة 1.1 جيجا بايت) لا يبدو أنها تحرر الذاكرة المخصصة لها. إذا كان عليهم تحرير الذاكرة عندما يكون الجهاز تحت ضغط متزايد ، فلن أقلق بشأن هذا ، ولكن نظرًا لأنهم يحتفظون بتخصيص الذاكرة حتى عند تحميل الجهاز ، تصبح مشكلة (نظرًا لأنه يحظر جدولة الحاويات الأخرى على هذا الجهاز و وبالتالي تهدر الموارد).

أسئلة:

  1. ما الذي يمكن أن يسبب هذا السلوك؟ هل هي مشكلة JVM؟ قضية عامل ميناء؟ مشكلة VM؟ مشكلة لينكس؟ مشكلة التكوين؟ أو ربما مزيج؟
  2. ما الذي يمكنني محاولة القيام به للحد من تخصيص ذاكرة JVM في هذه الحالة؟
answer

عندما تحدد

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

ثم -Xmx128m -serverيتم تمرير القيم التي تنوي أن تكون وسائط JVM ( ) كوسائط سطر أوامر إلى الفئة الرئيسية في الملف .jar. إنها متوفرة في شكل args في طريقتك public static void main(String... args).

لاحظ أن هذا صحيح أيضًا إذا كنت تقوم بتشغيل فئة رئيسية بالاسم ، بدلاً من تحديد jarملف قابل للتنفيذ .

لتمريرها كوسيطات JVM ، بدلاً من وسيطات لبرنامجك ، تحتاج إلى تحديدها قبل الوسيطة -jar.

راجع https://stackoverflow.com/questions/5536476/passing-arguments-to-jar-which-is-required-by-java-interpreter

كانت المشكلة مع إعدادات JVM المحددة في Dockerfile. بدأنا JVM لدينا مثل هذا:

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

ولكن عندما انتقلنا إلى:

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

تم أخذ الإعدادات في الاعتبار. ما زلت لا أفهم سبب عدم رؤيتي لهذا الأمر محليًا ، لكنني سعيد لأننا تمكنا من حلها.