in Technology

แนะนำ k6 สำหรับทำ Load Testing และ Automation Testing

ในบรรดาเครื่องมือ Load Test ที่เรารู้จักกันคงหนีไม่พ้น ab (ApacheBench) และ Apache jMeter โพสต์นี้จะมาแนะนำอีกตัวหนึ่ง ที่ Developer น่าจะชอบเลย ชื่อว่า k6 ครับ

Performance Testing, Load Testing กับ Stress Testing ต่างกันอย่างไร

ก่อนจะไปถึงเครื่องมือ มาทำความเข้าใจกันก่อนว่า Test ทั้ง 3 ตัวนี้ ต่างกันอย่างไร

ต้องบอกว่า Load Testing และ Stress Testing เป็นส่วนหนึ่งใน Performance Testing ซึ่งคือ การที่เราทดสอบในแง่มุมต่างๆ เพื่อบ่งบอกประสิทธิภาพของระบบ เช่น

  • ระบบมีการทำงานได้เร็วไหม? ความเร็วเท่าไร? ที่จำนวน Request แต่ละชุด (Load Testing)
  • ถ้าระบบทำงานหนักๆ ติดต่อกันนาน จะเกิดปัญหาไหม? (Endurance Testing)
  • ถ้าระบบทำงานหนักมากๆ จนล่ม สามารถกลับมาทำงานได้ไหม? ใช้เวลากลับมา นานแค่ไหน? (Recovery Testing)
  • ถ้าระบบทำงานสูงขึ้นเรื่อยๆ แบบเกินปกติ จะรองรับได้ที่เท่าไร? (Stress Testing)
  • ถ้าระบบมีการใช้งานพุ่งสูงแบบกระทันหัน จะเกิดปัญหาไหม? (Spike Testing)

จริงๆ มีมากกว่านี้ แต่จากรายการข้างต้น เรียกว่าเป็นกลุ่มของ Non-Functional Testing ที่ไม่ได้เห็น Bug ชัดเจนจากการเขียนโปรแกรมที่ผิดพลาด จึงอาจต้องอาศัยคนหรือเครื่องมือเพื่อจำลองสถานการณ์ขึ้นมา ว่าได้ตามเกณฑ์ที่กำหนดหรือเปล่า

รู้จักกับ k6 – Open source load testing tool

k6 เป็นเครื่องมือ Open source ที่เขียนด้วยภาษา Go สำหรับทำ Load Testing โดยทำคำสั่งผ่าน CLI คล้ายกับ ab (ApacheBench) แต่ด้วยความที่มันเป็น Scriptable tools เลยทำให้สามารถเขียนโค้ดทดสอบเพิ่มเติมได้ โดยใช้ภาษา Javascript และแน่นอน มันจึงทำ Automated Testing ได้สะดวกขึ้น และน่าจะถูกใจชาว Developer ด้วย

อธิบายเพิ่มเติม: ab (ApacheBench) เป็นเครื่องมือประเภท Non-Scriptable ข้อดีคือใช้งานง่าย เพียงพิมพ์คำสั่งและตามด้วย parameter ที่กำหนด ก็ใช้งานได้เลย เหมาะกับคนทั่วไปที่ไม่ต้องเขียนโค้ดเป็น แต่ข้อเสียคือ ไม่สามารถทำอะไรได้นอกเหนือจาก parameter ที่มีให้ ตัวอย่างเช่น

ab -n 100 -c 10 http://www.website.com/ -H "clientId:1234" -H  "token:a2ds5mvo93mcnsk3ncsju3nxdl"

ส่วนเครื่องมือที่นิยมอีกตัวหนึ่ง คือ Apache jMeter ที่สามารถเขียนคำสั่งได้ด้วย XML แต่ก็ต้องทำภายใต้ข้อจำกัดของ XML Syntax ที่เขาเตรียมไว้ให้

วิธีติดตั้ง k6

k6 รองรับการใช้งาน 3 ระบบ เลือกติดตั้งตามความเหมาะสมได้เลยครับ

สำหรับชาว Linux (deb and rpm packages)

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 379CE192D401AB61
echo "deb https://dl.bintray.com/loadimpact/deb stable main" | sudo tee -a /etc/apt/sources.list
sudo apt-get update
sudo apt-get install k6

สำหรับชาว Mac (brew)

brew install k6

สำหรับชาว Windows (MSI installer)

ไปโหลดได้ที่: https://dl.bintray.com/loadimpact/windows/k6-v0.26.1-amd64.msi
หรือเข้าไปดู release ล่าสุดได้ที่ https://github.com/loadimpact/k6/releases

ติดตั้งใช้งานผ่าน Docker

docker pull loadimpact/k6

เริ่มต้นทดสอบ Load Testing ด้วย k6 อย่างง่าย

ลองมาทดสอบด้วยการส่ง Request ไปหาเว็บไซต์ http://test.k6.io กัน โดยการสร้างไฟล์ k6-script.js ขึ้นมา และใส่โค้ดไปดังนี้

import http from 'k6/http';
import { sleep } from 'k6';

export default function() {
  http.get('http://test.k6.io');
  sleep(1);
}

จากนั้นทำการ run ชุดโค้ดทดสอบด้วยคำสั่ง ดังนี้

k6 run k6-script.js

จะได้ผลลัพธ์ออกมาแบบนี้ครับ

โดยที่ค่าสำคัญๆ ที่เราจะใช้ดู คือ

  • duration : เวลาที่จะใช้ทดสอบ (ในที่นี้ไม่ได้ระบุ จึงไม่ได้ใช้)
  • iterations : จำนวนครั้ง request ที่ใช้ทดสอบ (ในที่นี้ไม่ได้ระบุ จึงเป็นค่า 1)
  • vus : ย่อมาจาก virtual user หรือการจำลองคนใช้งาน 1 คน (ในที่นี้ไม่ได้ระบุ จึงเป็นค่า 1)
  • max : คือจำนวน vus มากที่สุดที่จะใช้ทดสอบ โดยจะใช้ระบุคู่กับ duration เท่านั้น (ในที่นี้ไม่ได้ระบุ จึงเป็นค่า 1) และในการทำ stage จะใช้ชื่อว่า target
  • data_received : จำนวน Byte ที่มีการรับกลับมาจากการทดสอบ
  • data_sent : จำนวน Byte ที่มีการส่งออกไปเพื่อทดสอบ
  • http_req_duration : จำนวนเวลารวมที่มีการ request ทดสอบ (ผลรวมของ http_req_sending + http_req_waiting + http_req_receiving)
  • http_reqs : จำนวนครั้งที่มี request ในช่วงเวลา duration ที่กำหนด

ส่วนค่าอื่นๆ อ่านคำอธิบายได้จากที่นี่ครับ https://k6.io/docs/getting-started/results-output

ลองใส่ k6 Parameters ง่ายๆ เพื่อกำหนดรูปแบบการทดสอบ

กำหนดให้ vus เป็น 10 และ duration time เป็น 30 วินาที

k6 run --vus 10 --duration 30s k6-script.js

กำหนดให้ vus เป็น 10 และขยับขึ้นไปที่ 20 ภายในเวลา 30 วินาที

k6 run --vus 10 --duration 30s --max 20 k6-script.js

กำหนดให้ vus เป็น 10 และ iteration เป็น 100 ครั้ง (หมายถึง 1 vus ทำการ request 10 ครั้ง)

k6 run --vus 10 --iterations 100 k6-script.js

ข้อมูล Parameters ต่างๆ สามารถดูเพิ่มเติมได้ที่นี่ครับ https://k6.io/docs/using-k6/options

เปลี่ยนจากการระบุ Parameters รูปแบบการทดสอบ มาเป็นเขียนโค้ด

parameter ต่างๆ เราสามาถเขียนในรูปแบบโค้ด ใน Javascript เราได้ด้วยนะครับ เช่น

import http from 'k6/http';
import { sleep } from 'k6';

export let options = {
  vus: 10,
  iterations: 100,
};

export default function() {
  http.get('http://test.k6.io');
  sleep(1);
}

จากนั้นก็สั่ง run โค้ด แบบไม่ต้องระบุ parameter ก็จะได้ผลลัพธ์เหมือนกัน

k6 run k6-script.js

รูปแบบการใช้งานต่างๆ อ่านได้จากที่นี่ครับ https://k6.io/docs/getting-started/running-k6 และสามารถดู Options ต่างๆ ได้ที่นี่ครับ https://k6.io/docs/using-k6/options

ทดสอบ Load Testing แบบ Stages ด้วยการกำหนดจำนวน vus ให้ขึ้นลงตามระยะเวลาที่กำหนด

บางทีเราต้องการจำลองการทดสอบจำนวนคนเข้า (vus) ในแต่ละช่วงเวลาไม่เท่ากัน จะขยับขึ้น (ramping up) จะลง (ramping down) หรือจะขึ้นไปเรื่อยๆ ก็สามารถระบุเป็น Stages ได้ เช่น

ต้องการทดสอบโดยให้ vus มีประมาณจาก 1 ไป 20 vus ภายในเวลา 30 วินาที จากนั้นให้ลดลงมาที่ 10 vus ภายในเวลา 1:30นาที และลดลงเป็น 0 ภายในเวลา 20 วินาที จะเขียนโค้ด ดังนี้

import http from 'k6/http';
import { sleep } from 'k6';

export let options = {
  stages: [
    { duration: '30s', target: 20 },
    { duration: '1m30s', target: 10 },
    { duration: '20s', target: 0 },
  ],
};

export default function() {
  http.get('http://test.k6.io');
  sleep(1);
}

ผลลัพธ์ที่ได้คือ ทดสอบจำนวน 2:20 นาที มี requests ได้ถึง 1,394 ครั้ง

ทดสอบส่งค่าผ่าน HTTP Request และทำการเช็คผลลัพธ์ที่ได้

ได้ลอง Get data ไปแล้ว คราวนี้มาลองส่ง Input data ผ่าน Post บ้าง และระบุ Header ด้วย จากนั้นจะต้องได้ผลลัพธ์ตามที่เรากำหนด ซึ่งจะมีรูปแบบการเขียนดังนี้

import { check } from "k6";
import http from 'k6/http';

export default function() {
  var url = 'http://test.loadimpact.com/login.php';
  var formdata = {
    login: 'admin',
    password: '123',
  };

  var params = {
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    redirects: 1
  };

  let res = http.post(url, formdata, params);
  let jar = http.cookieJar();
  let cookies = jar.cookiesForURL(url);

  check(res, {
    "is status 200": r => r.status === 200,
    "has cookie 'sid'": (r) => cookies.sid.length > 0,
    "has cookie 'uid'": (r) => cookies.uid.length > 0,
    "cookie 'sid' has correct value": (r) => cookies.sid == "39b77ac6-39c4-4c43-98b3-6b2816682036",
    "cookie 'uid' has correct value": (r) => cookies.uid == "3221"
 });

}

ผลลัพธ์ที่ได้คือ

ในตัวอย่าง ผมได้ทดสอบการ login เข้าสู่ระบบ โดยส่ง login, password ผ่าน form data ไปให้ url จากนั้น ทำการตรวจสอบความถูกต้อง 5 เรื่อง คือ

  • ได้ HTTP Status Codes คือกลับมาเป็น 200 หรือไม่
  • มี Cookie ชื่อ sid หรือไม่
  • มี Cookie ชื่อ uid หรือไม่
  • Cookie ชื่อ sid มีค่าที่ต้องการหรือไม่
  • Cookie ชื่อ uid มีค่าที่ต้องการหรือไม่

ซึ่ง จากผลลัพธ์ สามารถเรียกใช้งานได้ และมีความถูกต้อง 5 เรื่อง ข้างต้นด้วย

ซึ่งถ้าผมอยากทำ Load Testing ระบบ login นี้ด้วยการจำลองสัก 10 vus จำนวน 100 ครั้ง ก็ใช้คำสั่งที่เราเคยลองทำมาคือ

k6 run --vus 10 --iterations 100 k6-script-http.js 

สรุป

จากที่ได้ลองเล่น k6 ดู ผมชอบตรงที่สามารถเขียนโค้ดการทดสอบได้ (Scriptable) และเขียนด้วยภาษา Javascript ที่นักพัฒนาเว็บไซต์ในโลกส่วนใหญ่มักจะเขียนเป็นกันอยู่แล้ว รวมไปถึง ตัว k6 เอง ใช้ภาษา Go ที่มีความสามารถในการทำงานที่เร็วและไม่กิน Memory มากนัก คิดว่าต่อไปคงได้เปลี่ยนจาก ApacheBench มาใช้ k6 แทน อย่างไม่ต้องสงสัยเลยครับ

ใครสนใจ สามารถไปดูข้อมูลเพิ่มเติมต่อได้ที่ https://k6.io/

ใครอยากได้ Demo ที่ผมทดสอบ หาได้จากที่นี่ครับ https://github.com/ifew/k6-load-testing

ส่วนใครอยากดูผลการ Benchmark ทดสอบเครื่องมือ Load Tesing สามารถดูได้ที่ https://k6.io/blog/comparing-best-open-source-load-testing-tools (ดูข้อมูลและกราฟทดสอบก็พอ อย่าไปเชื่อผลสรุปมันมาก เพราะค่อนข้างลำเอียง อารมณ์ล้วนๆ จากคนเขียน k6 เอง ฮ่าๆ)

Reference