Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การทดสอบแบบขนานใน Ruby on Rails:ความเสี่ยงและกลยุทธ์การบรรเทาผลกระทบ

คุณเคยได้ยินใครบ่นว่าการทดสอบของพวกเขาเร็วเกินไปหรือไม่? ฉันก็เช่นกัน

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

จากทั้งหมดที่กล่าวมา การสร้างชุดทดสอบที่รวดเร็วปานสายฟ้าไม่ได้ง่ายอย่างที่คุณคาดหวังเสมอไป โชคดีที่ Rails 6 เปิดตัวฟีเจอร์ที่น่าตื่นเต้นที่เรียกว่า การทดสอบแบบขนาน . การเริ่มต้นใช้งานนั้นง่ายดายและสามารถเพิ่มความเร็วในการทดสอบของคุณได้มาก อย่างไรก็ตาม มีข้อผิดพลาดบางประการที่ต้องระวัง

การทดสอบแบบขนานคืออะไร

การทดสอบแบบขนานหมายความว่าอย่างไร

เมื่อคุณเรียกใช้ชุดการทดสอบ โดยปกติแล้วตัวทดสอบของคุณจะสร้างกระบวนการเดียวเพื่อดำเนินการทดสอบของคุณทีละขั้นตอน — หรือ ต่อเนื่อง . กระบวนการทดสอบเดี่ยวใช้แกน CPU ตัวเดียว ดังที่คุณคงจินตนาการได้ วิธีการนี้ไม่ได้ใช้ประโยชน์จากฮาร์ดแวร์สมัยใหม่อย่างเต็มที่ ซึ่งมักจะมีแกน CPU หลายสิบแกน

คุณอาจมี MacBook สุดหรูที่มีคอร์ CPU 10 คอร์ แต่น่าเสียดายที่มันไม่ทำให้การทดสอบของคุณดำเนินไปเร็วไปกว่านี้แล้ว!

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

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

ลองนึกภาพการทำแบบเดียวกันนี้กับเครื่องจักรขนาด 16 คอร์ที่สวยงาม ซึ่งเราสามารถวางไข่คนงานได้ 16 คน ดีมากจริงๆ!

การกำหนดค่าการทดสอบแบบขนานใน Rails

แล้วเราจะไปที่นั่นได้อย่างไร? จนกระทั่งเมื่อไม่นานมานี้ คุณสามารถใช้ Gems ของบริษัทอื่นเพื่อทำให้ชุดการทดสอบของคุณขนานกัน แต่เริ่มจากRails 6 การทดสอบแบบขนานจะเป็นมาตรฐาน ง่ายเหมือนกับการเพิ่ม 06 ในการทดสอบของคุณ:

 

เมื่อใช้การกำหนดค่านี้ Rails จะสร้างกระบวนการของผู้ปฏิบัติงานโดยอัตโนมัติตามจำนวนโปรเซสเซอร์ในเครื่องของคุณ Rails จะสร้างฐานข้อมูลเนมสเปซด้วย (เช่น 18 , 21 ฯลฯ) เพื่อทำการทดสอบ

เพียงเท่านี้ก็เริ่มต้นได้แล้ว! แน่นอนว่ามีตัวเลือกการกำหนดค่าเพิ่มเติมบางอย่างหากคุณต้องการ

บางครั้ง คุณอาจต้องดำเนินการตั้งค่าหรือการล้างข้อมูลเฉพาะสำหรับการทดสอบแบบขนาน Rails มีตะขอสองอันให้คุณใช้ — 37 และ 41 . สิ่งเหล่านี้ถูกเรียกก่อนและหลังกระบวนการของผู้ปฏิบัติงานใหม่:

 

คุณยังสามารถกำหนดจำนวนพนักงานได้ด้วยตนเอง:

 

หรือใช้ 58 ตัวแปรสภาพแวดล้อมเพื่อแทนที่การกำหนดค่าที่มีอยู่:

 

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

 

69 เป็นตัวเลือกเริ่มต้นเมื่อใช้ JRuby หรือ TruffleRuby ตามทฤษฎีแล้ว การใช้เธรดจะให้ประสิทธิภาพที่ดีขึ้นเล็กน้อย เธรดต้องการค่าใช้จ่ายน้อยกว่ากระบวนการ อย่างไรก็ตาม ในทางปฏิบัติ ฉันไม่เคยพบว่าการใช้เธรดทั้งหมดมีประโยชน์เกินไป และคุณควรยึดติดกับการทำงานแบบขนานตามกระบวนการเป็นส่วนใหญ่

ระวังหลุมพราง

ดังนั้นสิ่งที่คุณต้องทำคือเพิ่ม 74 กับการทดสอบที่มีอยู่ของคุณเพื่อสัมผัสประสบการณ์การเร่งความเร็วที่น่าทึ่งใช่ไหม มันง่ายมาก!

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

เรามาทำความเข้าใจสิ่งหนึ่งกันดีกว่า หากคุณใช้ RSpec แทนที่จะเป็น Minitest แสดงว่าคุณไม่มีโชค RSpec ไม่รองรับการทดสอบแบบขนานในตัวของ Rails 6 มีการพูดคุยกันอย่างต่อเนื่องเกี่ยวกับการเปลี่ยนแปลงดังกล่าว แต่ไม่มีความคืบหน้าที่สำคัญมาระยะหนึ่งแล้ว หากคุณต้องการการทดสอบแบบขนานกับ RSpec ทางออกที่ดีที่สุดของคุณยังคงใช้ Gem ของบุคคลที่สาม เช่น Grosser/parallel_tests

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

คุณอาจดีกว่าที่จะปิดการใช้งานการทดสอบแบบขนานสำหรับการทดสอบจำนวนเล็กน้อย คุณสามารถทำได้โดยใช้81 ตัวแปรสภาพแวดล้อม:

 

Rails 7 แก้ไขปัญหานี้ด้วยการเปิดใช้งานการดำเนินการแบบขนานเฉพาะเมื่อคุณดำเนินการทดสอบจำนวนมากเท่านั้น ดังนั้นหากคุณอัปเกรดแล้ว คุณจะไม่พบปัญหานี้ ตามค่าเริ่มต้น เกณฑ์การทำขนานจะตั้งไว้ที่ 50 แต่คุณสามารถแทนที่ได้:

 

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

 

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

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

 

เนื่องจากผู้ปฏิบัติงาน 2 ลบไฟล์ก่อนที่จะดำเนินการยืนยันของผู้ปฏิบัติงาน 1 การทดสอบครั้งแรกจึงล้มเหลว - ในบางครั้ง เพื่อเพิ่มการบาดเจ็บ บางครั้งคำสั่งดำเนินการที่แตกต่างกันอาจทำให้การทดสอบครั้งที่สองล้มเหลวและการทดสอบแรกผ่านไป

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

ไม่มีหัวข้อใดที่จะกล่าวถึงการทดสอบแบบขนานที่ไม่สม่ำเสมอได้ โดยทั่วไป คุณจะต้องตรวจสอบให้แน่ใจว่ากระบวนการทดสอบหลายรายการไม่แชร์ทรัพยากร สำหรับไฟล์ ให้ใช้ Tempfiles ใช้ 91 เพื่อสร้างทรัพยากรเนมสเปซ (เช่น ฐานข้อมูล Redis) และอื่นๆ

การเพิ่มการทดสอบแบบขนานให้กับการทดสอบ Rails ที่มีอยู่

สมมติว่าคุณประสบปัญหากับความล้มเหลวในการทดสอบแบบสุ่มเนื่องจากการขนาน และไม่มีเวลาแก้ไข อย่างไรก็ตาม คุณยังคงต้องการเก็บเกี่ยวผลประโยชน์จากการทดสอบแบบขนาน คุณอาจต้องการเปิดใช้งานเฉพาะการทดสอบบางส่วนเท่านั้น

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

 

คลาสการทดสอบใดๆ ที่รวมโมดูลนี้ไว้จะทำงานแบบขนาน:

 

หรือคุณสามารถสร้างคลาสการทดสอบใหม่เช่น 113 :

 

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

การทดสอบแบบขนานโดยใช้ Bandaid

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

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

สรุป

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

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

ไม่ว่าคุณจะเลือกวิธีใด การทดสอบแบบขนานเป็นเครื่องมือที่ยอดเยี่ยมในการเร่งการทดสอบของคุณ!

ขอให้สนุกกับการเขียนโค้ด!

ปล. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่เผยแพร่ สมัครรับจดหมายข่าว Ruby Magic ของเราและไม่พลาดแม้แต่โพสต์เดียว! การทดสอบแบบขนานใน Ruby on Rails:ความเสี่ยงและกลยุทธ์การบรรเทาผลกระทบ

ฮันส์-ยอร์ก ชเนดลิทซ์

Hans ผู้เขียนรับเชิญของเราเป็นวิศวกรของ Rails จากเวียนนา ประเทศออสเตรีย เขาใช้เวลาส่วนใหญ่ในการเขียนโค้ดหรืออ่านหนังสือเกี่ยวกับการเขียนโค้ด และบางครั้งก็เขียนเกี่ยวกับเรื่องนี้ในบล็อกของเขาด้วยซ้ำ! เมื่อเขาไม่ได้นั่งอยู่หน้าจอ คุณอาจพบเขากำลังปีนเขาอยู่ข้างนอก

บทความทั้งหมดโดย Hans-Jörg Schnedlitz