نقوم بتشغيل العديد من خدمات Java (Corretto JDK21) على AWS Elastic Container Service(ECS) Fargate. كل خدمة لها حاوية خاصة بها ونريد استخدام جميع الموارد الممكنة التي ندفعها مقابل كل عملية. ولكن يمكن تطبيق الخطوات على EC2 والسحابات الأخرى.
تقوم الخدمات بتشغيل مهام مجمعة وزمن الوصول ليس مهمًا، ونحن نستخدم Parallel GC (-XX: UseParallelGC). ربما يكون G1 أفضل حتى مع مهامنا، ولكنه موضوع للبحث والنشر المنفصل.
لاستخدام كل الذاكرة المتاحة، نستخدم MaxHeapSize أقل قليلاً من حجم ذاكرة الحاوية. ولكن بعد مرور بعض الوقت، لاحظنا مشكلتين، أحيانًا يتم إيقاف حاوياتنا لأنها تستخدم الكثير من الذاكرة وأحيانًا نتلقى استثناءات OutOfMemoryError. لإصلاح المشكلة الأولى، قمنا بزيادة الفجوة بين حجم ذاكرة الحاوية وMaxHeapSize وبالنسبة للمشكلة الثانية، قمنا بزيادة ذاكرة الحاويات كحل سريع وبدأنا في النظر إلى تفريغ الكومة.
أظهرت عمليات تفريغ الكومة تفاصيل مثيرة للاهتمام، وكان حجم الكومة الفعلي أقل من MaxHeapSize، وكانت كومة الذاكرة المؤقتة لجيل الشباب صغيرة جدًا مقارنة بالجيل القديم.
لم يساعد البحث على الإنترنت في العثور على دليل جيد حول كيفية ضبط معلمات JVM لحالتنا، ولم أجد سوى بعض التفاصيل عالية المستوى حول أوصاف الأكوام والمعلمات. قررت أن أكتب هذا المنشور لوصف الخطوات التي قمت بها.
الخطوات الأولى كانت:
المعدل الافتراضي للأجيال الشابة: القديمة هو 1:2، ويتم استخدام جزء فقط من الجيل الشاب في نفس الوقت لأداء GC. وبعد البدء، خصص JVM كل الذاكرة كما هو متوقع، ولكن بعد مرور بعض الوقت بدأ في تقليل حجم الكومة الخاصة بـ Young Generation إلى عدة ميغابايت تقريبًا. لذلك، بعد مرور بعض الوقت، استخدمنا فقط ثلث الذاكرة المتوفرة.
بعد بعض البحث، عثرت على معلمة لتعطيل سياسة التكيف (-XX:-UseAdaptiveSizePolicy) وساعدني ذلك، توقفت الكومة عن التناقص وزادت الفواصل الزمنية بين مجموعات البيانات المهملة بترتيب من حيث الحجم أو أكثر. الوقت الذي يستهلكه GC نما أيضًا ولكن ليس كثيرًا.
كانت الخطوة التالية هي العثور على الفجوة المثالية بين حجم ذاكرة الحاوية. افتراضيًا، حتى لو كان PrimaryRAMPercentage = 100، فإن JDK يخصص الذاكرة فقط ولا يستخدمها لذلك لا يتم تعيينها. يسمح Linux له بتخصيص ذاكرة افتراضية أكبر من الذاكرة الفعلية. وتفشل الحاوية لاحقًا عندما يتم تعيين الذاكرة بالفعل (يكتب JDK إليها). -XX: يغير AlwaysPreTouch هذا السلوك. لسوء الحظ، لم يتم تعيين بعض الذاكرة بعد، لكن إنهاء OOM يحدث بشكل أسرع بكثير. بعد عدة محاولات، انتهيت من الصيغة التالية لحجم ذاكرة الحاوية - 1024 ميجا بايت للحاويات ذات ذاكرة 8 جيجا بايت أو أكثر. على سبيل المثال، بالنسبة لحجم ذاكرة الحاوية 8192، نستخدم -XX:MaxHeapSize=7168m.
لمزيد من التحسينات، نفكر في تغيير -XX:NewRatio لتقليل حجم الجيل الشاب وتقليل وقت GC. ولكن ذلك يعتمد على عمر الكائن في التطبيق.
كما ذكرت من قبل، لم أجد أي دليل جيد يحتوي على شرح تفصيلي للمعلمات (أفضل ما وجدته هو vm-options-explorer) وخطوات الضبط. سيكون أمرا رائعا إذا كان بإمكانك مشاركة معرفتك ونتائجك.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3