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

เชี่ยวชาญการทดสอบประสิทธิภาพ สเตรส และโหลดใน Rails

การทดสอบเป็นส่วนสำคัญของแอปพลิเคชัน Rails ที่ทำงานได้ดี โดยที่การบำรุงรักษาไม่ใช่ฝันร้าย และฟีเจอร์ใหม่ถูกเพิ่มเข้ามาอย่างต่อเนื่อง หรือฟีเจอร์เดิมได้รับการปรับปรุง อย่างน่าเสียดาย สำหรับแอปพลิเคชันหลายตัว สภาพแวดล้อม Production คือสถานที่แรกที่พวกเขาถูกทดสอบภายใต้ภาระงานหนักหรือトラフィックมากครั้งแรก เรื่องนี้เข้าใจได้ เพราะการทดสอบประเภทนี้มีค่าใช้จ่ายสูง

ขอขอบคุณที่ Rails มีการสนับสนุนที่ดีไม่เพียงแค่ Unit, End-to-End และ Integration Tests แต่ยังรวมถึงการทดสอบที่เกี่ยวกับประสิทธิภาพและโหลดด้วย ฉันจะครอบคลุมทั้งหมดในบทความนี้และแสดงตัวอย่างปฏิบัติที่จะช่วยให้คุณเข้าใจวิธีใช้เครื่องมือทดสอบระดับประสิทธิภาพของแอปพลิเคชันอย่างมีประสิทธิภาพ

บทความแบ่งออกเป็น 2 ส่วน:

  • ทฤษฎี — ฉันจะแสดงว่าทำไมการทดสอบจึงจำเป็น ประเภทของการทดสอบที่เราสามารถทำได้ และ Metric สำคัญเมื่อทดสอบแอปพลิเคชัน

  • ปฏิบัติ — เราจะลงมือจริงและเขียนการทดสอบสำหรับแอปพลิเคชันจริงเพื่อได้ผลลัพธ์

หลังจากอ่าน 2 ส่วน คุณจะมีความเข้าใจลึกซึ้งเกี่ยวกับประเภทการทดสอบต่างๆ และวิธีการทดสอบบนแอปพลิเคชัน Rails ของคุณ ดูน่าสนใจไหม? มาเริ่มต้นด้วยทฤษฎีสั้นๆ เกี่ยวกับการทดสอบกัน

ทฤษฎีการทดสอบ

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

  • นำการเปลี่ยนแปลงมาใช้โดยไม่กังวลว่าจะทำให้สิ่ง gìเสีย — นี่คือเหตุผลหลักที่การทดสอบจำเป็น ทำให้จินตนาการทำงานบนแอปขนาดใหญ่ที่คุณต้องคลิกผ่านทั้งแอปเพื่อให้แน่ใจว่ nichts เสียทุกครั้งที่นำการเปลี่ยนแปลงมาแม้แต่วิธีเล็กๆ ด้วยการทดสอบ คุณเพียงรันคำสั่งเดียวและกระบวนการตรวจสอบจะเป็นอัตโนมัติและรวดเร็ว
  • กระบวนการ Refactoring ที่ง่าย — ฉันกล่าวไปข้างต้นว่าการทดสอบจำเป็นเมื่อเพิ่มฟีเจอร์ใหม่หรือทำการเปลี่ยนแปลง ด้วยการทดสอบที่มีอยู่ คุณจะมั่นใจมากขึ้นในการปรับปรุงโค้ดที่มีอยู่
  • การทดสอบเป็นรูปแบบหนึ่งของเอกสาร — การทดสอบที่เขียนได้ดีสามารถเป็นเอกสารสำหรับชุดฟีเจอร์ต่างๆ ในแอปพลิเคชัน พวกเขาไม่ได้แค่อธิบายว่าฟีเจอร์คืออะไร แต่ยังอธิบายว่าควรทำงานอย่างไร
  • โอกาสในการคิดใหม่เกี่ยวกับการ Implement — เมื่อคุณเขียนการทดสอบ คุณมีโอกาสคิดอีกครั้งว่าวิธีที่คุณต้องการ Implement โค้ดถูกต้องและสมเหตุสมผลหรือไม่ นอกจากนี้ คุณเพียงแค่ตรวจสอบว่าโค้ดของคุณทำงานตามที่คุณคาดหวัง

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

ประเภทการทดสอบที่แตกต่างกัน

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

  • Load Testing — ประเภทการทดสอบนี้ตอบคำถามว่า: ระบบสามารถจัดการผู้ใช้พร้อมกันได้กี่คนในช่วงเวลาที่กำหนด ทำให้จินตนาการเปิดตัวผลิตภัณฑ์ยอดนิยมบนเว็บไซต์ และพันๆ ผู้ใช้ต้องการสั่งซื้อพร้อมกัน โดยไม่มีการทดสอบโหลดที่เหมาะสม คุณเสี่ยงต่อการ Crash ในช่วงเวลาสำคัญที่สุด
  • Stress Testing — ด้วยประเภทการทดสอบนี้ คุณไม่เน้นการตรวจสอบจำนวนผู้ใช้ที่ระบบจัดการพร้อมกันได้ แต่เน้นว่าระบบจะพฤติกรรมอย่างไรเมื่อถึงขีดจำกัดของผู้ใช้
  • Performance Testing — ฉันจะบอกว่าประเภทการทดสอบนี้เป็นพ่อแม่ของ Stress และ Load Testing วัตถุประสงค์หลักคือการได้ชุด Metric เฉพาะที่เราสามารถนำไปปรับปรุงโค้ดแอปพลิเคชัน ฉันจะพูดถึง Metric เหล่านี้ในไม่ช้า

สิ่งนั้นกล่าวไปแล้ว เราพร้อมที่จะไปขั้นตอนสุดท้ายของส่วนทฤษฎี: เรียนรู้ว่า Metric อะไรสำคัญเมื่อทำ Performance Testing บนแอปพลิเคชัน Rails โดยไม่มีความรู้นั้น เราจะไม่สามารถตีความ Output ของการทดสอบได้อย่างถูกต้อง และตัดสินใจว่าเราควรเปลี่ยนโค้ดหรือไม่

Metric สำคัญ

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

  • Response Time — เวลาระหว่างการ Request ถูกส่ง และ Response ถูก Render ใน Browser Metric นี้แสดงว่าผู้ใช้ต้องรอนานแค่ไหนก่อนจะได้รับข้อมูลที่เขาร้องขอ บางครั้งเรียกว่า Process Time
  • Memory Usage — ปริมาณหน่วยความจำที่ใช้สำหรับ Request ที่กำหนด นี่เป็นข้อมูลสำคัญเพราะมันชี้ไปที่จุดที่คุณสามารถปรับปรุงโค้ดได้ เพื่อให้ระบบตอบสนองเร็วขึ้นและใช้น้อยทรัพยากรน้อยลง
  • Objects Allocation — การจัดสรรหน่วยความจำสูงทำให้ Memory Usage สูงและ Response Time ยาว Metric นี้สามารถนำคุณไปยังจุดที่แน่นอนในโค้ดที่มีการจัดสรร Object มาก ที่คุณสามารถตรวจสอบได้ทันที

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

ปฏิบัติ

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

แอปพลิเคชัน Rails ตัวอย่าง

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

rails new simpleapp -d=postgresql

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

ก่อนที่เราจะสร้าง Model มาสร้าง Database ก่อน:

cd simpleapp/ bin/rails db:create

ตอนนี้เราสามารถสร้าง Model ได้:

rails g model User name:string rails g model Animal name:string user:references bin/rails db:migrate

เพียงแค่ Update เล็กน้อยใน Model User เพื่อสะท้อนความสัมพันธ์กับ Model Animal:

class User < ApplicationRecord has_many :animals end

เราสามารถเพิ่ม Seeds ในไฟล์ db/seeds.rb ได้แล้ว:

people = { 'Tim' => ['Pinky', 'Rick'], 'Martha' => ['Rudolph'], 'Mark' => ['Niki', 'Miki', 'Bella'], 'Tina' => ['Tom', 'Luna'] } people.each_pair do |name, pets| user = User.create(name: name) pets.each do |pet_name| user.animals.create(name: pet_name) end end

และโหลดข้อมูลลง Database:

bin/rails db:seed

ฉันจะสร้าง Controller หนึ่งตัวพร้อมการกำหนด User และใน View จะแสดงรายชื่อ User ทั้งหมดพร้อมชื่อสัตว์เลี้ยง ฉันใช้โค้ดที่ทำให้เกิดปัญหาประสิทธิภาพอย่างเจตนา เพื่อให้คุณวัดการปรับปรุงภายหลัง

touch app/controllers/home_controller.rb mkdir app/views/home touch app/views/home/index.html.erb

Controller เรียบง่าย:

class HomeController < ApplicationController def index @users = User.all end end

และ View ก็เรียบง่ายเช่นกัน:

<h1>List</h1> <ul> <% @users.each do |user| %> <li><%= user.name %> (<%= user.animals.count %>) <ul> <% user.animals.each do |animal| %> <li><%= animal.name %></li> <% end %> </ul> </li> <% end %> </ul>

ขั้นตอนสุดท้ายคือ Update ไฟล์ config/routes.rb ให้ Rails รู้ว่าคุณต้องการเห็นอะไรเมื่อเข้าชม URL หลัก:

Rails.application.routes.draw do root to: 'home#index' end

Load Tests ด้วย JMeter

JMeter เป็นซอฟต์แวร์ Open Source ที่สร้างโดย Apache Software Foundation ออกแบบมาเพื่อ Load Test พฤติกรรมการทำงาน เนื่องจากเป็นโปรแกรมที่สร้างด้วย Java คุณสามารถติดตั้งบน OS ใดๆ ได้ คุณสามารถดาวน์โหลดไฟล์ได้ที่: https://jmeter.apache.org/download_jmeter.cgi

หากคุณทำงานบน macOS คุณสามารถติดตั้ง JMeter ได้ง่ายด้วย Homebrew:

brew install jmeter

หลังติดตั้ง คุณสามารถรันโปรแกรมได้ด้วยคำสั่ง:

jmeter

การกำหนดค่าการทดสอบ

กระบวนการกำหนดค่าประกอบด้วยขั้นตอนต่อไปนี้:

  • เพิ่ม Thread Group — ระบุจำนวนผู้ใช้และระยะเวลาที่แต่ละคนจะเข้าชมเว็บไซต์
  • กำหนดค่า HTTP Request — ระบุ Endpoint ที่ JMeter ควร Hit
  • ตั้งค่า Metric ที่เราสนใจ

มาดูทีละขั้นตอนสำหรับการกำหนดค่าการทดสอบง่ายๆ เพื่อจำลอง Request เดียวของผู้ใช้ไปหน้าหลักของแอปง่ายๆ ที่เราสร้างไว้ก่อนหน้านี้

เพิ่ม Thread Group

เลือก Add -> Threads (Users) -> Thread Group จากเมนูที่ขยายเมื่อคุณคลิกขวาที่ "Test Plan":

ระบุจำนวนผู้ใช้และ Attribute เพิ่มเติม:

กำหนดค่า HTTP Request

คลิกขวาที่ Thread ที่เราสร้างในขั้นตอนก่อนหน้า และเลือก Add -> Sampler -> HTTP Request:

กำหนด Protocol, Server Name, Port และ Path ของ Request:

ระบุมุมมองผลลัพธ์

คลิกขวาที่ HTTP Request และเลือก Add -> Listener -> View Results Tree:

การรันการทดสอบ

การทดสอบได้รับการกำหนดค่าแล้ว และเราสามารถ Trigger ได้ เพื่อทำเช่นนั้น ให้คลิกที่ปุ่ม Play สีเขียว:

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

ขั้นตอนต่อไป

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

Performance Tests ด้วย Ruby-prof

ฟีเจอร์ Performance Test ถูก Built-in ใน Rails จนถึงเวอร์ชัน 3 แล้วจึงถูกแยกออกไปเป็น Gem แยกต่างหาก https://github.com/rails/rails-perftest เนื่องจากฉันมีปัญหาบ้างในการใช้กับ Rails เวอร์ชันล่าสุด ฉันจึงตัดสินใจไม่รวมในบทความนี้ แทนที่จะใช้ library ruby-prof ที่ทำงานได้ดีมาก

ตามปกติ ขั้นตอนแรกคือเพิ่ม Gem ลงในแอปพลิเคชันของเรา:

bundle add ruby-prof

ขั้นตอนที่สองและขั้นตอนสุดท้ายของการกำหนดค่าคือ Update config/application.rb และใช้ Middleware สำหรับ Gem เพื่อให้ Library สามารถตรวจสอบ Request ของเราโดยอัตโนมัติและสร้างรายงานจากพวกมัน:

module Simpleapp class Application < Rails::Application config.middleware.use Rack::RubyProf, :path => './tmp/profile' end end

ตอนนี้คุณสามารถเข้าถึงแอปได้ และทุกครั้งที่คุณทำ Request Gem จะสร้างรายงานใหม่ มันจะมีลักษณะแบบนี้:

คุณสามารถหาได้ที่ Path ที่กำหนดค่าไว้ ซึ่งในกรณีนี้คือ tmp/profile รายงานที่สองก็ถูกสร้างขึ้นเช่นกัน และแสดง Call Stack ซึ่งก็เป็น Metric ที่ช่วยได้มากเมื่อ Debug ปัญหาประสิทธิภาพในแอปพลิเคชัน Rails

สำคัญที่ต้องจำว่า การตั้งค่า cache_classes และ cache_template_loading เป็น true จะทำให้แอปพลิเคชันช้าลงและท่วมท้น Metric ของแอปพลิเคชัน เนื่องจาก Rails จะพยายามโหลดไฟล์ที่จำเป็น

สรุป

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

ในบทความนี้ เราครอบคลุมด้านสำคัญต่อไปนี้ของการทดสอบ:

  • เหตุผลที่คุณควรทดสอบโค้ดของคุณ
  • ประเภทการทดสอบประสิทธิภาพที่แตกต่างกัน
  • วิธีที่คุณสามารถทดสอบประสิทธิภาพของแอป Rails ของคุณ

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

หากคุณสนใจในการตรวจสอบประสิทธิภาพของแอปไม่ได้แค่ใน Local แต่ยังรวมถึงสภาพแวดล้อม Production หรือ Staging คุณควรดู AppSignal ด้วย

P.S. หากคุณต้องการอ่านโพสต์ Ruby Magic ทันทีที่เผยแพร่ สมัครรับข่าวสาร Ruby Magic newsletter และจะไม่พลาดโพสต์เด็ดๆ ไปเลย!