ทำไมเราถึงได้รับขัดขวางอย่างฉับพลันในเวลาตอบสนอง


12

เรามี API ที่ใช้งานผ่าน ServiceStack ซึ่งโฮสต์ใน IIS ในขณะที่ทำการทดสอบการโหลดของ API เราพบว่าเวลาตอบสนองนั้นดี แต่ก็ลดลงอย่างรวดเร็วทันทีที่เรามีผู้ใช้งานพร้อมกันประมาณ 3,500 คนต่อเซิร์ฟเวอร์ เรามีเซิร์ฟเวอร์สองเครื่องและเมื่อมีผู้ใช้ถึง 7,000 คนเวลาตอบสนองโดยเฉลี่ยอยู่ต่ำกว่า 500ms สำหรับอุปกรณ์ปลายทาง กล่องเหล่านี้อยู่ด้านหลัง load balancer เราจึงได้รับ 3,500 concurrents ต่อเซิร์ฟเวอร์ อย่างไรก็ตามทันทีที่เราเพิ่มจำนวนผู้ใช้พร้อมกันทั้งหมดเราจะเห็นเวลาตอบสนองที่เพิ่มขึ้นอย่างมีนัยสำคัญ การเพิ่มผู้ใช้พร้อมกันถึง 5,000 ต่อเซิร์ฟเวอร์ทำให้เรามีเวลาตอบสนองโดยเฉลี่ยต่อปลายทางประมาณ 7 วินาที

หน่วยความจำและ CPU บนเซิร์ฟเวอร์ค่อนข้างต่ำทั้งในขณะที่เวลาตอบสนองที่ดีและเมื่อพวกเขาเสื่อมสภาพ ที่สูงสุดด้วยผู้ใช้ 10,000 คนพร้อมกันค่าเฉลี่ยของ CPU เพียงแค่ต่ำกว่า 50% และ RAM อยู่ที่ประมาณ 3-4 GB จาก 16 สิ่งนี้ทำให้เราคิดว่าเรากำลัง จำกัด ขอบเขตบางแห่ง ภาพหน้าจอด้านล่างแสดงตัวนับหลักใน perfmon ระหว่างการทดสอบโหลดซึ่งมีผู้ใช้งานพร้อมกันทั้งหมด 10,000 คน ตัวนับที่ไฮไลต์คือคำร้องขอ / วินาที ทางด้านขวาของสกรีนช็อตคุณสามารถเห็นคำขอต่อกราฟที่สองกลายเป็นเอาแน่เอานอนไม่ได้ นี่คือตัวบ่งชี้หลักสำหรับเวลาตอบสนองช้า ทันทีที่เราเห็นรูปแบบนี้เราจะสังเกตเห็นเวลาตอบสนองช้าในการทดสอบโหลด

สกรีนช็อต perfmon พร้อมการร้องขอต่อวินาทีที่ไฮไลต์

เราจะแก้ไขปัญหาประสิทธิภาพการทำงานนี้ได้อย่างไร เรากำลังพยายามระบุว่านี่เป็นปัญหาการเข้ารหัสหรือปัญหาการกำหนดค่า มีการตั้งค่าใด ๆ ใน web.config หรือ IIS ที่สามารถอธิบายพฤติกรรมนี้ได้หรือไม่? กลุ่มแอพลิเคชันกำลังเรียกใช้. NET v4.0 และรุ่น IIS คือ 7.5 การเปลี่ยนแปลงเดียวที่เราทำจากการตั้งค่าเริ่มต้นคือการอัปเดตค่าความยาวคิวแอปพลิเคชันจาก 1,000 เป็น 5,000 เราได้เพิ่มการตั้งค่าคอนฟิกต่อไปนี้ไปยังไฟล์ Aspnet.config ด้วย:

<system.web>
    <applicationPool 
        maxConcurrentRequestsPerCPU="5000"
        maxConcurrentThreadsPerCPU="0" 
        requestQueueLimit="5000" />
</system.web>

รายละเอียดเพิ่มเติม:

วัตถุประสงค์ของ API คือการรวมข้อมูลจากแหล่งข้อมูลภายนอกต่างๆและส่งคืนเป็น JSON ขณะนี้กำลังใช้การใช้แคช InMemory เพื่อแคชการโทรภายนอกแต่ละรายการที่ชั้นข้อมูล คำขอแรกไปยังทรัพยากรจะดึงข้อมูลทั้งหมดที่จำเป็นและคำขอใด ๆ ที่ตามมาสำหรับทรัพยากรเดียวกันจะได้รับผลลัพธ์จากแคช เรามี 'นักวิ่งแคช' ที่ใช้เป็นกระบวนการพื้นหลังที่อัปเดตข้อมูลในแคชตามช่วงเวลาที่กำหนด เราได้เพิ่มการล็อกรอบโค้ดที่ดึงข้อมูลจากทรัพยากรภายนอก นอกจากนี้เรายังได้ใช้บริการเพื่อดึงข้อมูลจากแหล่งภายนอกในรูปแบบอะซิงโครนัสเพื่อให้ปลายทางควรช้าเท่ากับการโทรภายนอกที่ช้าที่สุด (เว้นแต่ว่าเรามีข้อมูลในแคชแน่นอน) สิ่งนี้ทำได้โดยใช้คลาส System.Threading.Tasks.Taskเราสามารถ จำกัด จำนวนเธรดที่มีอยู่สำหรับกระบวนการได้หรือไม่?


5
ซีพียูของคุณมีกี่คอร์? บางทีคุณอาจจะเพิ่มหนึ่งแกน เมื่อเลขอาถรรพ์คือ 50%, 25% หรือ 12.5% ​​นั่นแสดงให้เห็นว่าคุณได้ขยายแกนให้ใหญ่สุดและด้วยเหตุผลบางอย่างไม่สามารถใช้คอร์อื่นที่กำลังไม่ได้ใช้งานได้ ตรวจสอบแกน maxed out
David Schwartz

1
คุณมีหนึ่งเธรดต่อคำขอหรือไม่ ดังนั้นสำหรับ 5000 คำขอคุณมี 5,000 เธรดหรือไม่ หากคุณทำเช่นนั้นอาจเป็นปัญหาของคุณ คุณควรสร้างเธรดพูลและใช้เธรดพูลเพื่อประมวลผลการร้องขอโดยจัดคิวคำขอตามที่เข้ามาในเธรดพูล เมื่อเธรดเสร็จสิ้นด้วยคำร้องขอสามารถประมวลผลคำร้องขอปิดคิว การเรียงลำดับของการสนทนานี้ดีที่สุดสำหรับ stackoverflow เธรดมากเกินไปหมายถึงการสลับบริบทมากเกินไป
Matt

1
ตรวจสอบความมีสติที่นี่คุณลองปิดกระบวนการพื้นหลังทั้งหมดของคุณแล้วดูว่าการทำงานของ JSON จะส่งคืนข้อมูลสแตติกจากแคชหรือไม่ กล่าวอีกนัยหนึ่งการทำให้ JSON ของคุณร้องขอข้อมูลคงที่และลบ "การเรียกใช้ async ภายนอก" ที่จะรีเฟรชแคชของคุณโดยสมบูรณ์ นอกจากนี้ขึ้นอยู่กับจำนวนของข้อมูล JSON ที่ให้บริการในทุกคำขอคุณเคยคิดเกี่ยวกับปริมาณงานเครือข่ายของคุณหรือไม่และหากคำขอเริ่มสำรองเนื่องจากเซิร์ฟเวอร์ไม่สามารถส่งข้อมูลเร็วพอหรือไม่
Robert

1
+1 ถึงข้อเสนอแนะ Davids ด้านบน คุณควรทำการทดสอบซ้ำและดูการใช้งานแกนหลักอย่างรอบคอบ ฉันขอแนะนำให้คุณทำโดยเร็วที่สุดเพื่อกำจัดมันถ้าไม่มีอะไรอื่น ประการที่สองฉันสงสัยแคชของคุณเล็กน้อย การแย่งชิงล็อคสามารถแสดงพฤติกรรมเช่นนี้ได้ - ที่การล็อกจุดวิกฤติบางอย่างทำให้เกิดความล่าช้าซึ่งจะทำให้การล็อคค้างไว้นานกว่าปกติทำให้เกิดจุดเปลี่ยนที่สิ่งต่าง ๆ ตกต่ำอย่างรวดเร็ว คุณสามารถแบ่งปันแคชและรหัสล็อคได้หรือไม่?
สตีฟทำอาหาร

1
การตั้งค่าดิสก์สำหรับเซิร์ฟเวอร์คืออะไร (สมมติว่าเนื่องจากโหลดมีความสมดุลการตั้งค่าดิสก์จะเหมือนกัน) คุณสามารถโพสต์รายละเอียดทั้งหมดสำหรับไดรฟ์ / เซิร์ฟเวอร์ในโพสต์เริ่มต้นของคุณได้หรือไม่? คุณได้โยน perfmon ลงในดิสก์บนไดรฟ์ฟิสิคัลที่มี IIS และไฟล์บันทึก IIS อยู่หรือไม่ อาจเป็นไปได้ว่าคุณอาจประสบปัญหาเกี่ยวกับดิสก์ที่มีการร้องขอ 3,500 รายการ = 3,500+ บันทึก IIS หากพวกเขาอยู่ในดิสก์ / พาร์ทิชันเดียวกันคุณอาจมีปัญหาใหญ่ที่นั่น
Techie Joe

คำตอบ:


2

ติดตามด้วย @DavidSchwartz และ @Matt สิ่งนี้จะดูเหมือนเธรดล็อคการจัดการปัญหา

ฉันแนะนำ:

  1. ตรึงการเรียกภายนอกและแคชที่สร้างขึ้นสำหรับพวกเขาและรันการทดสอบโหลดด้วยข้อมูลภายนอกแบบคงที่เพียงเพื่อทิ้งปัญหาใด ๆ ที่ไม่เกี่ยวข้องกับฝั่งเซิร์ฟเวอร์ - สภาพแวดล้อม

  2. ใช้กลุ่มเธรดหากไม่ได้ใช้

  3. เกี่ยวกับการโทรจากภายนอกคุณกล่าวว่า "เราได้ดำเนินการบริการเพื่อดึงข้อมูลจากแหล่งภายนอกในรูปแบบอะซิงโครนัสเพื่อให้ปลายทางควรช้าเท่ากับการโทรภายนอกที่ช้าที่สุด (เว้นแต่ว่าเรามีข้อมูลในแคช) "

คำถามคือ - คุณตรวจสอบแล้วว่าข้อมูลแคชใด ๆ ถูกล็อคระหว่างการโทรภายนอกหรือเฉพาะเมื่อเขียนผลการโทรภายนอกลงในแคชหรือไม่? (ชัดเจนเกินไป แต่ต้องพูด) - คุณล็อกแคชทั้งหมดหรือบางส่วนเล็ก ๆ ของมันหรือไม่? (ชัดเจนเกินไป แต่ต้องพูด) - แม้ว่าจะเป็นแบบอะซิงโครนัสการโทรภายนอกจะรันบ่อยแค่ไหน? แม้ว่าพวกเขาจะไม่ได้ทำงานบ่อยนักพวกเขาก็อาจถูกบล็อกโดยคำขอจำนวนมากไปยังแคชจากการโทรของผู้ใช้ขณะที่แคชถูกล็อค สถานการณ์นี้มักแสดงเปอร์เซ็นต์คงที่ของ CPU ที่ใช้เนื่องจากเธรดจำนวนมากกำลังรอในช่วงเวลาคงที่และต้อง "จัดการการล็อก" ด้วย - คุณตรวจสอบแล้วว่างานภายนอกหมายถึงเวลาตอบสนองเพิ่มขึ้นเมื่อสถานการณ์ช้ามาถึงหรือไม่

หากปัญหายังคงมีอยู่ฉันขอแนะนำให้หลีกเลี่ยงคลาส Task และทำการโทรภายนอกผ่านกลุ่มเธรดเดียวกันที่จัดการคำขอของผู้ใช้ นี่คือเพื่อหลีกเลี่ยงสถานการณ์ก่อนหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.