ผ่านบทความนี้เราจะอธิบายปัญหาที่พบในการประมวลผลแบบอะซิงโครนัสเป็นหลักในการพัฒนา Java และการแก้ปัญหา ต่อไปนี้เป็นเนื้อหาเฉพาะ:
Servlet 3.0 ได้เริ่มให้ AsyncContext เพื่อสนับสนุนการประมวลผลแบบอะซิงโครนัส ดังนั้นการประมวลผลการร้องขอแบบอะซิงโครนัสจะได้รับประโยชน์อะไรบ้าง?
โดยทั่วไปวิธีที่เว็บคอนเทนเนอร์จัดการคำขอคือการกำหนดเธรดให้กับแต่ละคำขอ เราทุกคนรู้ว่าการสร้างเธรดไม่ได้ไม่มีค่าใช้จ่ายและพูลเธรดของเว็บคอนเทนเนอร์มีขีด จำกัด สูงสุด
ปัญหาที่คาดการณ์ได้มากคือภายใต้สภาวะโหลดสูงพูลเธรดจะถูกครอบครองดังนั้นคำขอที่ตามมาสามารถรอได้เท่านั้น หากคุณไม่โชคดีลูกค้าจะรายงานข้อผิดพลาดการหมดเวลารอคอย
ก่อนที่ AsyncContext จะปรากฏขึ้นวิธีเดียวที่จะแก้ปัญหานี้คือการขยายพูลเธรดของเว็บคอนเทนเนอร์
แต่ยังมีปัญหากับสิ่งนี้พิจารณาสถานการณ์ต่อไปนี้:
มีเว็บคอนเทนเนอร์ที่มีขนาดพูลเธรด 200 มีเว็บแอปที่มีสอง servlets เวลาที่ใช้เวลา servlet-A เพื่อจัดการคำขอเดียวคือ 10s และเวลาที่ใช้ servlet-b เพื่อจัดการคำขอเดียวคือ 1s
ตอนนี้เราพบว่ามีการโหลดสูงโดยมีคำขอมากกว่า 200 รายการไปยัง Servlet-A หากมีการร้องขอ servlet-b ในเวลานี้เราจะรอเพราะเธรด HTTP ทั้งหมดถูกครอบครองโดย Servlet-A
ในเวลานี้วิศวกรค้นพบปัญหาและขยายขนาดพูลเธรดเป็น 400 แต่โหลดยังคงเพิ่มขึ้นอย่างต่อเนื่อง ขณะนี้มี 400 คำขอไปยัง Servlet-A และ Servlet-B ยังไม่สามารถตอบกลับได้
คุณเคยเห็นปัญหาหรือไม่? เนื่องจากเธรด HTTP และเธรดคนงานถูกรวมเข้าด้วยกันจึงจะเติมเต็มเธรด HTTP เมื่อมีการร้องขอจำนวนมากในการดำเนินการใช้เวลานานทำให้เกิดการตอบสนองของเว็บคอนเทนเนอร์ทั้งหมดที่ไม่สามารถตอบกลับได้
อย่างไรก็ตามหากเราใช้ ASYNCCONTEXT เราสามารถส่งมอบการดำเนินการที่ใช้เวลานานไปยังเธรดอื่นเพื่อให้เธรด HTTP จะถูกปล่อยออกมาและเราสามารถจัดการคำขออื่น ๆ ได้
โปรดทราบว่าการใช้ AsyncContext เท่านั้นที่สามารถบรรลุเอฟเฟกต์ที่กล่าวถึงข้างต้น หากคุณใช้เธรดใหม่ () หรือวิธีการที่คล้ายกันโดยตรงเธรด HTTP จะไม่ถูกส่งกลับไปยังคอนเทนเนอร์
นี่คือตัวอย่างอย่างเป็นทางการ:
@webservlet (urlpatterns = {"/asyncservlet"}, asyncsupported = true) คลาสสาธารณะ asyncservlet ขยาย httpservlet {/ * ... ตัวแปรเดียวกันและวิธีการเริ่มต้นใน syncservlet ... Response.setContentType ("ข้อความ/html; charset = utf-8"); ขั้นสุดท้าย asyncContext acontext = request.startasync (); acontext.start (ใหม่ runnable () {public void run () {string param = acontext.getRequest (). getParameter ("param"); สตริงผลลัพธ์ = ทรัพยากร. process (param); httpservletResponse = acontext.getResponse (); / * ... - กับดัก
ในตัวอย่างอย่างเป็นทางการนี้แต่ละเธรด HTTP จะเปิดเธรดคนงานอื่นเพื่อประมวลผลคำขอจากนั้นส่งคืนเธรด HTTP ไปยังเว็บคอนเทนเนอร์ แต่ดูที่ javadoc ของวิธี asyncContext.start ():
ทำให้คอนเทนเนอร์ส่งเธรดซึ่งอาจมาจากพูลเธรดที่มีการจัดการเพื่อเรียกใช้ Runnable ที่ระบุ
ในความเป็นจริงไม่มีกฎระเบียบที่นี่ที่เธรดคนงานมาจาก อาจเป็นพูลเธรดอื่นนอกเหนือจากพูลเธรด HTTP? หรือเป็นเพียงพูลเธรด HTTP?
บทความที่มีประโยชน์ จำกัด ของ ASYNCCONTEXT.START () การอ่าน: เว็บคอนเทนเนอร์ที่แตกต่างกันมีการใช้งานที่แตกต่างกันสำหรับสิ่งนี้ แต่ TOMCAT ใช้พูลเธรด HTTP จริง ๆ เพื่อจัดการ asyncContext.start ()
ซึ่งหมายความว่าตอนแรกเราต้องการที่จะปล่อยเธรด HTTP แต่ในความเป็นจริงมันไม่ได้เนื่องจากเธรด HTTP ยังคงใช้เป็นเธรดคนงาน แต่เธรดนี้ไม่เหมือนกับเธรด HTTP ที่ได้รับคำขอ
นอกจากนี้เรายังสามารถเห็นข้อสรุปนี้ผ่านเกณฑ์มาตรฐาน Jmeter ของ AsyncServlet1 และ SyncServlet และผลลัพธ์ของปริมาณงานทั้งสองนั้นคล้ายคลึงกัน วิธีการเริ่มต้น: เริ่มต้นหลักแล้วใช้ JMeter เพื่อเริ่ม Benchmark.jmx (HTTP เธรดพูล = 200 ภายใต้การกำหนดค่าเริ่มต้น Tomcat)
ใช้ ExecutorService
ฉันเห็นก่อนหน้านี้ว่า Tomcat ไม่ได้รักษาพูลด้ายคนงานแยกต่างหากดังนั้นเราต้องหาวิธีที่จะทำเองดู AsyncServlet2 ซึ่งใช้ ExecutorService พร้อมพูลเธรดเพื่อจัดการ ASYNCCONTEXT
วิธีอื่น
ดังนั้นจึงไม่มีวิธีที่แน่นอนในการใช้ ASYNCCONTEXT คุณสามารถใช้วิธีการต่าง ๆ เพื่อจัดการกับมันตามความต้องการที่แท้จริง ด้วยเหตุนี้คุณจึงต้องมีความรู้เกี่ยวกับการเขียนโปรแกรม Java พร้อมกัน
ความเข้าใจผิดเกี่ยวกับการแสดง
จุดประสงค์ของ ASYNCCONTEXT คือการไม่ปรับปรุงประสิทธิภาพและไม่ให้การปรับปรุงประสิทธิภาพโดยตรง มันมีกลไกในการแยกเธรด HTTP และเธรดคนงานซึ่งจะเป็นการปรับปรุงการตอบสนองของเว็บคอนเทนเนอร์
อย่างไรก็ตาม ASYNCCONTEXT สามารถปรับปรุงประสิทธิภาพในบางจุด แต่ขึ้นอยู่กับว่ารหัสของคุณเขียนอย่างไร
ตัวอย่างเช่น: จำนวนพูลเธรด HTTP ในเว็บคอนเทนเนอร์คือ 200 และ Servlet ใช้พูลเธรดคนงาน 300 คนเพื่อจัดการ ASYNCCONTEXT
เมื่อเทียบกับวิธีการซิงค์เวชภัณฑ์พูลคนงาน = พูลเธรด http = 200 ในกรณีนี้เรามีกลุ่มด้ายคนงาน 300 ดังนั้นมันจะนำการปรับปรุงประสิทธิภาพบางอย่าง (หลังจากทั้งหมดมีคนทำงานมากขึ้น)
ในทางตรงกันข้ามหากจำนวนเธรดของคนงานคือ <= จำนวนเธรด HTTP จะไม่มีการปรับปรุงประสิทธิภาพเนื่องจากคอขวดสำหรับการร้องขอการประมวลผลอยู่ที่เธรดคนงาน
คุณสามารถปรับเปลี่ยนขนาดพูลเธรดของ AsyncServlet2 และเปรียบเทียบกับผลลัพธ์มาตรฐาน SyncServlet เพื่อตรวจสอบข้อสรุปนี้
อย่าคิดว่าพูลด้ายคนงานจะต้องใหญ่กว่าพูลเธรด HTTP เหตุผลมีดังนี้:
ความรับผิดชอบทั้งสองนั้นแตกต่างกัน หนึ่งคือว่าเว็บคอนเทนเนอร์ถูกใช้เพื่อรับคำขอภายนอก และอื่น ๆ คือการประมวลผลตรรกะทางธุรกิจ
การสร้างเธรดมีค่าใช้จ่าย หากพูลเธรด HTTP มีขนาดใหญ่อยู่แล้วการสร้างพูลเธรดคนงานที่ใหญ่ขึ้นจะทำให้เกิดสวิตช์บริบทและค่าใช้จ่ายหน่วยความจำมากเกินไป
จุดประสงค์ของ ASYNCCONTEXT คือการปล่อยเธรด HTTP เพื่อหลีกเลี่ยงการใช้งานระยะยาวและทำให้เว็บคอนเทนเนอร์ไม่สามารถตอบสนองได้
ดังนั้นในกรณีส่วนใหญ่สระว่ายน้ำด้ายของคนงานจะไม่ใหญ่มากและกลุ่มคนงานที่แตกต่างกันจะถูกสร้างขึ้นตามธุรกิจที่แตกต่างกัน
ตัวอย่างเช่น: ขนาดพูลเธรดเว็บคอนเทนเนอร์คือ 200 และขนาดพูลของคนงานคือ 10 สำหรับ servlet ช้า ด้วยวิธีนี้ไม่ว่าจะมีการร้องขอจำนวนเท่าใดในการดำเนินการช้าลงมันจะไม่เติมเต็มเธรด HTTP และทำให้คำขออื่นไม่สามารถดำเนินการได้