เนื้อหาในเว็บไซต์นี้ได้รับการแปลโดยใช้ปัญญาประดิษฐ์ (AI) หรือเทคโนโลยีการแปลด้วยเครื่อง และอาจมีข้อผิดพลาด

Skip to content

การปรับปรุงการใช้ทรัพยากรเซิร์ฟเวอร์โดยการติดตามการรั่วไหลของหน่วยความจำ

ประมาณหนึ่งปีที่แล้ว เราสังเกตเห็นสัญญาณเบื้องต้นของรูปแบบที่กำลังเกิดขึ้น ซึ่งแสดงให้เห็นถึงขีดความสามารถที่ลดลงในเซิร์ฟเวอร์เกมของเรา ในช่วงเริ่มต้นนั้นแทบไม่มีผลกระทบต่อผู้เล่นเลย เนื่องจากเรายังมีพื้นที่รองรับเหลืออยู่มาก แต่บัฟเฟอร์ของเรากำลังลดลงอย่างรวดเร็ว เซิร์ฟเวอร์เกมจะยินดีรับผู้เล่นใหม่หรือเริ่มเกมใหม่ตราบใดที่มีทรัพยากร CPU และหน่วยความจำเพียงพอ ในกรณีนี้ ขีดจำกัดของหน่วยความจำเป็นสิ่งที่จำกัดจำนวนเกมที่สามารถโฮสต์บนเซิร์ฟเวอร์ได้ หากไม่สามารถแก้ไขปัญหานี้ได้ จะต้องขยายศูนย์ข้อมูลของเราเพื่อรองรับฐานผู้เล่น ซึ่งจะต้องใช้แรงงานและค่าใช้จ่ายทางการเงินที่สูงมาก

สมมติฐานแรกที่เราสำรวจคือรูปแบบการใช้หน่วยความจำของเกมกำลังเปลี่ยนแปลง เราสนับสนุนให้นักพัฒนาผลักดันขีดจำกัดของแพลตฟอร์ม ใช้ทรัพยากรที่มีอยู่เพื่อสร้างเกมที่น่าทึ่งและล้ำสมัย สิ่งนี้ตรวจสอบได้ง่าย เราสามารถรวบรวมข้อมูลการใช้หน่วยความจำของเกมทั้งหมดและดูว่ามีการเพิ่มขึ้นหรือไม่ แต่ไม่เป็นเช่นนั้น ค่าเฉลี่ยและเปอร์เซ็นไทล์ของการใช้หน่วยความจำต่อเกมยังคงค่อนข้างคงที่ ในขณะที่ขีดความสามารถของเรากำลังลดลงอย่างต่อเนื่อง

เราจัดเก็บข้อมูลประสิทธิภาพและการใช้ทรัพยากรจำนวนหลายเทราไบต์ต่อเดือน ซึ่งสามารถรวบรวมและกรองเพื่อช่วยค้นหาสาเหตุที่แท้จริงของปัญหาเช่นนี้ได้ เราได้พยายามแยกปัญหาให้เฉพาะเจาะจงกับภูมิภาค, ประเภทฮาร์ดแวร์, หรือเวอร์ชันซอฟต์แวร์ แต่โชคร้ายที่ปัญหาปรากฏขึ้นทุกที่. เราจึงตัดสินใจตรวจสอบเซิร์ฟเวอร์เกมบางตัวเพื่อค้นหาปัญหาอย่างละเอียด. ในตอนแรกฉันถูกทำให้เข้าใจผิดโดยแนวคิดของ "หน่วยความจำว่าง" บนระบบ Linux. ซึ่งเป็นปัญหาที่พบได้บ่อยมากจนทำให้ใครบางคนต้องลงทะเบียนโดเมนและสร้างเว็บไซต์เพื่ออธิบายหมวดหมู่ของหน่วยความจำ: https://www.linuxatemyram.com.

สรุปสั้น ๆ คือ การที่หน่วยความจำส่วนใหญ่ถูกใช้งานอยู่ถือเป็นเรื่องดี หน่วยความจำที่ว่างเปล่าคือหน่วยความจำที่สูญเปล่า เราควรกังวลก็ต่อเมื่อหน่วยความจำที่เหลืออยู่ใกล้ศูนย์เท่านั้น

เมื่อเราตรวจสอบแล้วว่าเรากำลังติดตามความจำอย่างถูกต้อง เราได้เริ่มทำการทดลองชุดหนึ่งเพื่อพิจารณาว่าความจำถูกนำไปใช้ที่ไหน วิธีการของเราคือการติดตามหมวดหมู่ย่อยของความจำที่เฉพาะเจาะจงเพื่อให้เราสามารถหาทางแก้ไขที่ตรงจุดได้

(หมายเหตุ: การใช้หน่วยความจำ (%) คำนวณจาก (หน่วยความจำทั้งหมด - หน่วยความจำที่ใช้งานได้) / หน่วยความจำทั้งหมด)

หน่วยความจำที่พร้อมใช้งานคำนวณโดยประมาณจากการรวมกันของ MemFree + Active(ไฟล์) + Inactive(ไฟล์) + SReclaimable

MemFree ติดตามหน่วยความจำที่ไม่ได้ใช้งาน

Active(ไฟล์) และ Inactive(ไฟล์) ติดตามหน่วยความจำแคชของหน้าเว็บ แคชของหน้าเว็บจะเก็บข้อมูลที่ถูกเข้าถึงในหน่วยความจำเพื่อลดปริมาณการอ่าน/เขียนข้อมูลจากดิสก์

SReclaimable tracks ติดตามหน่วยความจำ slab ที่สามารถเรียกคืนได้ หน่วยความจำ slab ถูกใช้สำหรับเก็บแคชของวัตถุที่ถูกเริ่มต้นแล้วซึ่งมักถูกใช้โดยเคอร์เนล

การทดลองแรกคือการปรับแต่งแคช โดยเฉพาะ: vm.vfs_cache_pressure และ vm.dirty_background_ratio

การเพิ่มค่า vfs_cache_pressure จะทำให้เรามีแนวโน้มที่จะนำวัตถุกลับมาจากแคชที่สามารถนำกลับมาใช้ใหม่ได้มากขึ้น ซึ่งจะมีผลกระทบต่อประสิทธิภาพ (ทั้งในแง่ของการพลาดแคชและเวลาค้นหาวัตถุที่สามารถนำกลับมาใช้ใหม่ได้)

dirty_background_ratio คือเปอร์เซ็นต์ (ของหน่วยความจำแคชหน้าที่เป็นข้อมูลที่เปลี่ยนแปลง) เมื่อเราเริ่มเขียนข้อมูลลงดิสก์ในลักษณะที่ไม่บล็อกการทำงาน

เราได้ทำการเปลี่ยนแปลงดังต่อไปนี้และสังเกตผลในหน่วยความจำ, slabinfo และ cgroups

vm.vfs_cache_pressure= 100 ==&gt; 10000<br>vm.dirty_background_ratio= 10 ==&gt; 5

วิธีที่ไม่รุกล้ำในการติดตามผลลัพธ์คือการเรียกใช้ cron job เป็นระยะๆ เพื่อจับภาพสถานะของหน่วยความจำ สิ่งที่คล้ายกับ:

#!/bin/bash<br>now=`date +%Y-%m-%d.%H:%M`
  # create test dir<br>mkdir -p ~/memtest&nbsp;
# log meminfo<br>sudo cat /proc/meminfo 
  ~/memtest/meminfo_$now
# log slabinfo<br>sudo cat /proc/slabinfo
  ~/memtest/slabinfo_$now&nbsp;
# log cgroups<br>sudo cat /proc/cgroups
  ~/memtest/cgroups_$now&nbsp;

หลังจากทำการเปลี่ยนแปลงการกดดันแคชและสังเกตการณ์เป็นเวลาหลายชั่วโมง เราได้เริ่มทำการวิเคราะห์ เราสรุปได้ว่าเราได้เพิ่มหน่วยความจำว่างประมาณ 8GB แต่หน่วยความจำนั้นได้มาจากแคชเพจและดิสก์โดยตรง ซึ่งอยู่ในหมวดหมู่ Active(ไฟล์) และ Inactive(ไฟล์) นี่เป็นผลลัพธ์ที่น่าผิดหวัง เพราะไม่มีการเพิ่มขึ้นของหน่วยความจำที่สามารถใช้งานได้อย่างมีนัยสำคัญ และเราไม่สามารถใช้หน่วยความจำนี้ให้เกิดประโยชน์ได้อีกต่อไป เราจำเป็นต้องกู้คืนหน่วยความจำจากแหล่งอื่น

หลังจากที่ไม่สามารถเพิ่มหน่วยความจำที่ใช้งานได้โดยตรง เราได้ลองลดหมวดหมู่ที่แข่งขันกัน เราสังเกตเห็นว่าหมวดหมู่ SUnreclaim มีขนาดใหญ่ ในบางกรณีขยายตัวถึง 60GB ในช่วงเวลาไม่กี่เดือน หมวดหมู่ SUnreclaim ติดตามหน่วยความจำที่ใช้สำหรับกลุ่มวัตถุโดยระบบปฏิบัติการที่ไม่สามารถเรียกคืนได้ภายใต้ความกดดันของหน่วยความจำ สัญญาณแรกของปัญหาคือจำนวน cgroups ที่เพิ่มขึ้นอย่างต่อเนื่อง เราคาดว่าจะมี cgroups ไม่เกินสองร้อยกลุ่มจากการรันกระบวนการที่ dockerized ของเรา แต่เรากลับพบ cgroups เป็นจำนวนหลายแสนกลุ่ม โชคดีสำหรับเราที่วิศวกรอีกท่านหนึ่งชื่อ Roman Gushchin จาก Facebook ได้ค้นพบและแก้ไขปัญหานี้ในระดับเคอร์เนลเมื่อไม่นานมานี้ https://patchwork.kernel.org/cover/10943797/ เขากล่าวว่า:

ปัญหาพื้นฐานนั้นค่อนข้างง่าย: หน้าใดก็ตามที่ถูกเรียกเก็บเงินไปยัง cgroup จะถือการอ้างอิงถึงหน้านั้น ดังนั้น cgroup จึงไม่สามารถเรียกคืนได้จนกว่าหน้าทั้งหมดที่ถูกเรียกเก็บเงินจะหายไป หากวัตถุ slab ถูกใช้งานโดย cgroup อื่นอยู่ มันจะไม่ถูกเรียกคืน และจะป้องกันไม่ให้ cgroup ต้นทางถูกเรียกคืนเช่นกัน

นี่ดูเหมือนจะเป็นปัญหาของเราอย่างแท้จริง ดังนั้นเราจึงรอคอยอย่างใจจดใจจ่อให้เคอร์เนลเวอร์ชัน 5.3 มาตรวจสอบการแก้ไขนี้

เราใช้สคริปต์ติดตามหน่วยความจำจากการทดลองเกี่ยวกับความกดดันของแคชซ้ำ แต่สำหรับการทดลองของเคอร์เนล เราต้องการจัดตั้งกลุ่มควบคุมและกลุ่มทดลอง เราได้ทำการย้ายปริมาณการใช้งานจากเซิร์ฟเวอร์ 2 ตู้แร็คออก จากนั้นได้ทำการอัปเกรดเคอร์เนลเป็นเวอร์ชัน 5.3 บนตู้แร็คหนึ่งตู้ และคงเคอร์เนลเวอร์ชัน 5.0 ไว้บนตู้แร็คอีกตู้หนึ่ง จากนั้นเราได้ทำการรีบูตทั้งสองตู้แร็ค และเปิดให้ปริมาณการใช้งานจากระบบกลับมาใช้งานได้อีกครั้ง หลังจากผ่านไปประมาณหนึ่งสัปดาห์ เราได้ติดตามการเปลี่ยนแปลงของ cgroups และหน่วยความจำ slab ที่ไม่สามารถคืนได้ตลอดเวลา นี่คือผลลัพธ์ที่ได้:

เคอร์เนล 5.0.0 มีการเติบโตของ cgroups อย่างต่อเนื่อง และในช่วงเวลาเพียงหนึ่งสัปดาห์มีการเพิ่มหน่วยความจำ slab ที่ไม่สามารถเรียกคืนได้ถึง 4GB รวมเป็น 6GB ในทางกลับกัน เคอร์เนล 5.3.7 มีการลดลงของ cgroups อย่างมีนัยสำคัญในแต่ละวัน และการเติบโตของหน่วยความจำ slab ที่ไม่สามารถเรียกคืนได้นั้นช้ามาก หลังจากหนึ่งสัปดาห์ หน่วยความจำ slab ที่ไม่สามารถเรียกคืนได้อยู่ที่ประมาณ 2 GB เมื่อใช้เคอร์เนลใหม่ หน่วยความจำ slab ที่ไม่สามารถเรียกคืนได้จะคงที่อยู่ที่ประมาณ 4 GB แม้หลังจากใช้งานต่อเนื่องหลายเดือน

ปัญหาหลักที่เราต้องการแก้ไขคือเซิร์ฟเวอร์เกมของเรากำลังสูญเสียความสามารถในการรองรับผู้เล่นเมื่อเวลาผ่านไป สาเหตุมาจากหน่วยความจำที่พร้อมใช้งานลดลง ซึ่งเกิดจากการเพิ่มขึ้นอย่างต่อเนื่องของ slab memory ที่ไม่สามารถเรียกคืนได้ ดังนั้นเมื่อเราสามารถควบคุมปัญหานี้ได้ในระดับหนึ่งด้วยการแก้ไขเคอร์เนลแล้ว ผลกระทบต่อความสามารถในการรองรับของเซิร์ฟเวอร์จะเป็นอย่างไร?

ทางด้านซ้าย คุณจะเห็นปัญหาของเรา คือจำนวนเกมที่ลดลงอย่างต่อเนื่องต่อเซิร์ฟเวอร์ ซึ่งสร้างภาระอย่างมากต่อโครงสร้างพื้นฐานของเรา เราได้ติดตั้งเคอร์เนลเวอร์ชัน 5.3 ทั่วทั้งระบบทั่วโลกของเราประมาณเดือนมีนาคม 2020 และสามารถรักษาความจุของเซิร์ฟเวอร์ให้อยู่ในระดับสูงมาจนถึงขณะนี้ ขอขอบคุณ Roman Gushchin สำหรับการแก้ไขเคอร์เนล และ Andre Tran สำหรับการช่วยตรวจสอบปัญหาและติดตั้งการแก้ไข

ทั้งบริษัท Roblox Corporation และบล็อกนี้ไม่ได้รับรองหรือสนับสนุนบริษัทหรือบริการใด ๆ ทั้งสิ้น นอกจากนี้ ไม่มีการรับประกันหรือคำมั่นสัญญาใด ๆ เกี่ยวกับความถูกต้อง ความน่าเชื่อถือ หรือความสมบูรณ์ของข้อมูลที่ปรากฏในบล็อกนี้

บทความบล็อกนี้ได้รับการเผยแพร่ครั้งแรกบนบล็อกเทคโนโลยีของ Roblox