Chạy load test/performance test với Artillery

Chạy load test/performance test với Artillery

Giới thiệu

Performance testing là gì? Và tại sao bạn nên thực hiện load test?

Performance testing là kiểm thử phần mềm đánh giá mức độ hoạt động của ứng dụng dưới các khối lượng công việc khác nhau.

Điều này liên quan đến việc đo lường các số liệu khác nhau như thời gian response, băng thông và khả năng mở rộng nhằm đảm bảo rằng ứng dụng có thể xử lý đúng số lượng request từ người dùng dự kiến mà không làm giảm hiệu suất hoặc gặp sự cố. Performance testing cũng có thể xác định các vấn đề về hiệu năng và tắc nghẽn, nó giúp bạn thực hiện các thay đổi cần thiết để tối ưu hóa hiệu năng. Mục tiêu của việc này là đảm bảo rằng ứng dụng mang lại trải nghiệm người dùng mượt mà, nhanh chóng và đáng tin cậy ngay cả trong điều kiện tải nặng.

Giới thiệu về Artillery.io

Artillery.io là một công cụ performance test mã nguồn mở cho phép bạn kiểm tra hiệu năng và khả năng mở rộng của các ứng dụng web, API và microservices. Bạn có thể mô phỏng hành vi người dùng thực tế, tạo tải từ nhiều nguồn và kiểm tra luồng ứng dụng của mình theo kịch bản.

Giao thức được hỗ trợ

Artillery.io được viết bằng Node.js và hỗ trợ các giao thức HTTP, Websocket và socket.io.

Ngoài ra, bạn có thể sử dụng plugin của Artillery để kiểm tra các stack khác như HLS (HTTP Live Streaming), Amazon Kinesis, Apache Kafka, v.v.

Định dạng của Script

Không giống như các công cụ kiểm tra phổ biến khác, Artillery.io cung cấp cú pháp dựa trên YAML linh hoạt để định nghĩa các kịch bản load test của bạn. Nó cũng hỗ trợ định dạng JSON.

Cài đặt & Tính năng cơ bản

Cài đặt

Bạn có thể cài đặt global dependency Artillery.io thông qua npm hoặc yarn bằng cách thực hiện theo lệnh sau:

#npm
npm install -g artillery
#yarn
yarn global add artillery

hoặc bạn cũng có thể cài đặt dưới dev dependency cho dự án Node.js với:

npm install -D artillery

Test nhanh

Sử dụng subcommand quick để bạn có thể chạy test mà không cần phải viết test script. Ví dụ, để chạy 10 virtual users (VUs), mỗi user thực hiện 20 request đến địa chỉ address http://localhost:3000/:

artillery quick -c 10 -n 20 http://localhost:3000/api/user

Parameter -c chỉ định tổng số VU, và -n chỉ định số lượng yêu cầu trên mỗi VU.

Chạy test script

Subcommand  run dùng để chạy test script từ máy cục bộ. Cách chạy cơ bản để chạy test là:

artillery run script.yaml -o report.json

Parameter -o là tùy chọn để ghi báo cáo JSON vào một file.

Xuất report

artillery report report.json -o report.html

Subcommand report cho phép chuyển đổi report JSON do subcommand run tạo ra thành một report HTML mới.

Viết một load test đơn giản

Phần hướng dẫn bên dưới chúng ta sẽ sử dụng cú pháp YAML, đầu tiên chúng ta cần tạo một tên tệp như “script.yml”, sau đó chúng ta bắt đầu định nghĩa phần “config” ở đầu tệp.

Phần Config

Chúng ta cần đặt base URL cho test script của mình với tùy chọn target:

config:
  target: "http://localhost:3000/api"

Tiếp theo, Chúng ta sẽ bắt đầu định nghĩa load phase, load phase giúp xác định cách Artillery tạo ra VU mới trong một khoảng thời gian xác định:

config:
  ...
  phases:
    - duration: 60
      arrivalRate: 100

Phần Scenarios

Chúng ta có thể định nghĩa một hoặc nhiều kịch bản. Mỗi định nghĩa kịch bản là một object yêu cầu có flow attribute.

scenarios:
  - name: "Get All Users"
    flow:
      - get:
          url: "/user"
          qs:
            limit: 10
            offset: 20

Trong property ‘flow’, chúng ta tiếp tục định nghĩa Method của HTTP dưới dạng object attribute, sau đó chúng ta cần xác định đường dẫn của API, chúng ta cũng có thể đặt query string hoặc form body như URL-encoded forms, Multipart forms hay JSON.

Lưu lại script và sau đó chạy test script của bạn.

Luồng người dùng thực tế

Ví dụ: luồng người dùng có thể như sau:

config:
  target: "http://localhost:3000/api"
  phases:
    - duration: 120
      arrivalRate: 10
      name: "Preparing"
    - duration: 240
      arrivalRate: 30
      rampTo: 100
      name: "Increasing"
    - duration: 600
      arrivalRate: 100
      name: "Sustained Load"
  payload:
    path: "login.csv"
    cast: false
    fields:
      - "user"
      - "pass"
  processor: "./processor.js"

before:
  flow:
    - log: "Get auth token"
    - post:
        url: "/auth/login"
        json:
          username: "{{user}}"
          password: "{{pass}}"
        capture:
          - json: $.tokens.accessToken
            as: token
scenarios:
  - name: "Search Users"
    flow:
      - get:
          url: "/user"
          headers:
            authorization: "Bearer {{ token }}"
  - name: "Create New User"
    flow:
      - post:
          url: "/user"
          beforeRequest: "setJsonBody"
          headers:
            authorization: "Bearer {{ token }}"

Trong script ở trên, chúng ta có ba phase trong phần config:

  • Giai đoạn đầu tạo 10 VU mỗi giây và gửi chúng đến ứng dụng trong 2 phút.
  • Trong giai đoạn thứ hai, load test sẽ bắt đầu với 30 người dùng mỗi giây và tăng dần lên 100 người dùng mỗi giây trong 4 phút.
  • Giai đoạn cuối cùng mô phỏng sẽ tải liên tục 100 người dùng mỗi giây trong 10 phút.

Bằng cách sử dụng nhiều phase cho phép bạn mô phỏng chính xác các tình huống lưu lượng truy cập thực tế và đánh giá khả năng xử lý hàng loạt yêu cầu đột ngột của ứng dụng.

Trong flow đầu tiên của kịch bản, mỗi VU yêu cầu đến GET | “Search user”, sau đó trong luồng thứ hai, họ sẽ yêu cầu đến POST | “Create user”.

Để dễ dạng tạo dữ liệu. Theo cách này, trước khi thực hiện yêu cầu. Chúng ta sử dụng hàm setJsonBody trên custom hook tên beforeRequest. Hàm setJsonBody được định nghĩa trong file processor.js và được tham chiếu ở phần config.processor.

# processor.js
const { faker } = require("@faker-js/faker");

function setJsonBody(requestParams, context, ee, next) {
  var body = {
    username: faker.internet.userName(),
    password: faker.internet.password(3),
    email: faker.internet.exampleEmail(),
    name: faker.name.fullName(),
    role: faker.datatype.number({ min: 0, max: 1 }),
  };

  requestParams.json = body;
  return next();
}

module.exports = {
  setJsonBody,
};

So sánh với K6 load testing

Artillery và k6 đều là các công cụ performance testing mã nguồn mở và có các tính năng tương tự như khả năng mở rộng, tích hợp với các công cụ CI/CD và khả năng thiết lập các mẫu kiểm thử. Tuy nhiên, có một số khác biệt giữa chúng. Artillery được viết bằng Node.js trong khi k6 được viết bằng Go. Vì vậy, Artillery chậm hơn k6, vì nó không đa luồng và sử dụng nhiều bộ nhớ hơn. Dưới đây là các biểu đồ so sánh mức sử dụng bộ nhớ giữa k6 với Artillery và các công cụ khác:

Sử dụng bộ nhớ

Mức sử dụng bộ nhớ trên mỗi cấp độ VU

Tóm lại, Artillery và k6 đều là những công cụ mạnh mẽ. Tuy nhiên k6 có nhiều ưu điểm hơn Artillery. Nếu bạn muốn viết một load test đơn giản, thì Artillery là một giải pháp tốt khi sử dụng cú pháp YAML.

Tham khảo

https://www.artillery.io/
https://k6.io/blog/comparing-best-open-source-load-testing-tools/