Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

k6 introduction — modern alternative

Mở đầu — vì sao bài này quan trọng

Nếu bạn đã đi qua các bài trước về JMeter, hẳn bạn đã quen với giao diện đồ họa đầy các Thread Group, Sampler, Listener xếp thành cây. JMeter mạnh mẽ và đã thống trị thế giới performance testing suốt gần hai thập kỷ. Nhưng nếu hôm nay bạn bước vào một startup công nghệ ở TP.HCM, một team fintech ở Singapore, hay một đội DevOps ở bất kỳ công ty product hiện đại nào, khả năng cao bạn sẽ nghe một cái tên khác: k6.

Vì sao lại có sự dịch chuyển này? Câu trả lời nằm ở một thay đổi lớn trong cách các đội kỹ thuật làm việc. Ngày nay, ranh giới giữa "người viết code" và "người test hiệu năng" đã mờ đi rất nhiều. Developer được kỳ vọng phải tự kiểm thử hiệu năng dịch vụ mình viết ra, và họ muốn làm điều đó bằng thứ ngôn ngữ họ dùng hằng ngày, quản lý bằng Git, chạy tự động trong pipeline CI/CD. Đây chính là mảnh đất mà k6 sinh ra để lấp đầy.

Bài học này giới thiệu k6 như một "modern alternative" — một lựa chọn hiện đại. Chúng ta sẽ không đi sâu vào cấu hình chi tiết như Options, Stages hay Scenarios (những nội dung đó thuộc các bài sau). Thay vào đó, bài này giúp bạn hiểu k6 là gì, triết lý đằng sau nó, tại sao nó khác biệt so với JMeter, và viết được kịch bản test đầu tiên. Hiểu được nền tảng tư duy này, bạn sẽ học các bài chuyên sâu về sau nhẹ nhàng hơn rất nhiều.

Khái niệm cốt lõi

k6 là gì?

k6 là một công cụ kiểm thử hiệu năng (load testing) mã nguồn mở, do Grafana Labs phát triển. Ban đầu nó là sản phẩm của công ty LoadImpact, và được Grafana Labs mua lại năm 2021 — đây là lý do vì sao k6 tích hợp cực kỳ mượt với hệ sinh thái Grafana (dashboard, Prometheus, Loki...).

Điểm đặc biệt nằm ở kiến trúc: phần lõi (core engine) của k6 được viết bằng ngôn ngữ Go, nhưng bạn viết kịch bản test bằng JavaScript. Đây là một sự kết hợp rất thông minh mà tôi muốn bạn ghi nhớ ngay từ đầu:

  • Go cho hiệu năng: Go xử lý concurrency (đa luồng, đa tiến trình) cực tốt, tiêu tốn ít bộ nhớ. Một máy tính bình thường có thể tạo ra hàng chục nghìn "người dùng ảo" mà không sập.
  • JavaScript cho trải nghiệm viết test: JS là ngôn ngữ phổ biến nhất thế giới, developer nào cũng biết chút ít, cú pháp gọn gàng, dễ đọc.
Lưu ý quan trọng để tránh hiểu lầm: k6 không chạy trên Node.js. Nó dùng một JavaScript runtime riêng (goja) nhúng trong Go. Vì vậy bạn không thể npm install một thư viện Node bất kỳ rồi require vào script k6 như bình thường. Đây là điểm hay khiến nhiều bạn mới bối rối.

Triết lý "developer-friendly"

Khẩu hiệu ngầm của k6 là: test hiệu năng phải giống như viết code, và được đối xử như code. Cụ thể:

Test là code (test-as-code). Kịch bản k6 là một file .js thuần văn bản. Bạn commit nó vào Git cùng với source code dự án, review qua pull request, xem lịch sử thay đổi. So sánh với JMeter, nơi test plan là file .jmx định dạng XML dài dằng dặc — mở ra để review diff trong pull request gần như là ác mộng.

Command-line first. k6 được thiết kế để chạy từ dòng lệnh: k6 run script.js. Không cần mở giao diện đồ họa, không cần môi trường desktop. Điều này khiến nó cực kỳ tự nhiên khi đưa vào server CI/CD (nơi không có màn hình).

Không có GUI để tạo test. Đây vừa là điểm mạnh vừa là điểm cần làm quen. JMeter có giao diện kéo-thả giúp người mới dễ bắt đầu. k6 thì bắt bạn viết code ngay từ đầu. Đổi lại, khi đã quen, tốc độ tạo và bảo trì test nhanh hơn nhiều.

Cấu trúc một script k6 tối giản

Mọi script k6 đều xoay quanh một hàm mặc định — chính là "kịch bản" mà mỗi người dùng ảo sẽ lặp đi lặp lại:

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

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

Chỉ vậy thôi. Hàm export default function() chính là "hành vi của một người dùng". Khi bạn chạy với 50 người dùng ảo (Virtual Users — VU), k6 sẽ cho 50 "người" cùng lặp lại hàm này liên tục. sleep(1) mô phỏng khoảng nghỉ 1 giây giữa các thao tác — giống như người dùng thật cần thời gian đọc trang trước khi bấm tiếp.

Khái niệm VU (Virtual User) là trái tim của k6. Mỗi VU là một luồng thực thi độc lập, chạy vòng lặp hàm default. Bạn tăng số VU để tăng tải.

So sánh nhanh với JMeter (ở góc độ triết lý)

Tôi không so sánh chi tiết tính năng ở đây (bài 40 có hẳn một "decision matrix"), nhưng để bạn định hình:

Khía cạnhJMeterk6
Cách tạo testGUI kéo-thả + XMLViết JavaScript
Ngôn ngữ lõiJavaGo
Tài nguyên/VUNặng (mỗi thread ~1 Java thread)Nhẹ (Go goroutine)
Hợp với CI/CDĐược nhưng cồng kềnhSinh ra để làm việc này
Đường cong họcDễ bắt đầu, khó bảo trì lớnCần biết JS, dễ bảo trì
Thông điệp cốt lõi: k6 không "thay thế" JMeter một cách tuyệt đối. Nó là một triết lý khác, phù hợp với đội ngũ developer-centric và văn hóa DevOps.

Tình huống thực tế

Ví dụ 1: Startup giao đồ ăn ở TP.HCM chuyển từ JMeter sang k6

Một startup giao đồ ăn (gọi là FoodFast, khoảng 30 kỹ sư) ban đầu dùng JMeter để test API đặt hàng. Vấn đề nảy sinh khi họ áp dụng CI/CD: mỗi lần merge code, họ muốn chạy một load test nhẹ để bắt regression hiệu năng. Nhưng file .jmx của họ dài hơn 4.000 dòng XML. Khi hai developer cùng sửa test plan, việc merge trên Git liên tục xung đột, và không ai đọc nổi cái diff toàn thẻ <HTTPSamplerProxy>.

Họ chuyển sang k6. Kịch bản test chính giờ chỉ còn khoảng 120 dòng JavaScript, chia thành các file module rõ ràng (login.js, browse.js, checkout.js). Diff trong pull request đọc như code bình thường. Quan trọng hơn, họ nhét thẳng lệnh k6 run vào GitHub Actions, chạy sau mỗi lần build.

Bài học rút ra: với đội ngũ đề cao Git và code review, "test là văn bản dễ đọc" không phải chi tiết nhỏ — nó quyết định việc test có thực sự được bảo trì hay bị bỏ rơi. JMeter không sai, nhưng nó không hợp với văn hóa làm việc của họ.

Ví dụ 2: Team fintech ở Singapore và bài toán tài nguyên máy chạy test

Một công ty ví điện tử ở Singapore cần mô phỏng 20.000 người dùng đồng thời gọi API kiểm tra số dư. Với JMeter, khi họ thử tạo tải này từ một máy, JVM ngốn hết RAM và JMeter treo ở khoảng 3.000–4.000 thread. Họ buộc phải dựng cụm distributed testing gồm 5–6 máy chỉ để tạo đủ tải — tốn kém và phức tạp về vận hành.

Khi thử lại bằng k6, nhờ mô hình goroutine nhẹ của Go, một máy chủ tầm trung (4 vCPU, 8GB RAM) đã tạo được khoảng 15.000–18.000 VU trước khi cần chia tải. Chi phí hạ tầng để chạy test giảm đáng kể.

Bài học rút ra: kiến trúc lõi bằng Go không phải chuyện "khoe kỹ thuật" — nó ảnh hưởng trực tiếp đến chi phí và độ phức tạp khi bạn cần tải lớn. Một VU trong k6 "rẻ" hơn nhiều so với một thread trong JMeter.

Ví dụ 3: Bạn developer backend tự test API mà không cần chuyên gia QA

Minh, một backend developer tại một công ty SaaS ở Hà Nội, viết một endpoint mới cho tính năng xuất báo cáo. Trước đây, muốn biết endpoint chịu được bao nhiêu request/giây, anh phải gửi yêu cầu cho team QA, chờ họ dựng test plan JMeter — mất vài ngày qua lại.

Với k6, Minh tự viết một file test 25 dòng ngay trong lúc code, chạy k6 run report_api.js trên máy mình, thấy ngay p95 latency là 850ms và error rate 0% ở mức 50 VU. Anh phát hiện query chậm, sửa index database, chạy lại, latency xuống 210ms. Tất cả trong một buổi chiều, không cần chờ ai.

Bài học rút ra: k6 hạ thấp rào cản để developer tự kiểm thử hiệu năng ngay trong vòng lặp phát triển. Đây chính là tinh thần "shift-left testing" — đẩy việc kiểm thử về sớm, gần với người viết code nhất.

Hướng dẫn từng bước

Hãy cùng chạy thử k6 lần đầu. Phần này cố ý giữ ở mức nhập môn — các tùy chọn nâng cao sẽ học ở bài sau.

Bước 1 — Cài đặt k6.

k6 là một file thực thi duy nhất (single binary), cài rất nhanh:

  • macOS: brew install k6
  • Windows: choco install k6 hoặc winget install k6
  • Linux (Debian/Ubuntu): thêm repo của Grafana rồi sudo apt-get install k6
  • Hoặc dùng Docker: docker pull grafana/k6
Kiểm tra cài đặt thành công:

k6 version

Bước 2 — Tạo script đầu tiên.

Tạo file first-test.js:

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

export default function () { const res = http.get('https://test.k6.io');

check(res, { 'status là 200': (r) => r.status === 200, });

sleep(1); }

Ở đây check() là một khẳng định mềm — nó kiểm tra điều kiện nhưng không dừng test nếu sai (khác với assertion cứng của JMeter). test.k6.io là trang demo công khai do Grafana cung cấp để luyện tập — bạn cứ dùng thoải mái.

Bước 3 — Chạy test cơ bản.

k6 run first-test.js

k6 mặc định chạy 1 VU trong 1 lần lặp. Bạn sẽ thấy một bảng tóm tắt kết quả ở cuối.

Bước 4 — Tăng tải bằng cờ dòng lệnh.

Chạy 10 người dùng ảo trong 30 giây:

k6 run --vus 10 --duration 30s first-test.js

--vus là số Virtual User, --duration là thời lượng test. (Cách khai báo tải bài bản qua optionsstages sẽ được dạy ở bài 14.)

Bước 5 — Đọc các chỉ số quan trọng.

Sau khi chạy, chú ý mấy dòng sau trong output:

  • http_req_duration — thời gian phản hồi. Xem giá trị p(95) (95% request nhanh hơn con số này).
  • http_reqs — tổng số request và số request/giây.
  • http_req_failed — tỉ lệ request thất bại.
  • iterations — tổng số lần vòng lặp default chạy.
  • vus — số VU đang hoạt động.
Chỉ với năm bước này, bạn đã có một load test thực thụ chạy được.

Lỗi thường gặp & mẹo

Lỗi 1: Tưởng k6 chạy trên Node.js. Nhiều bạn cố require('axios') hay import thư viện npm quen thuộc rồi báo lỗi. Nhớ: k6 dùng runtime JS riêng (goja), chỉ hỗ trợ một tập module tích hợp (k6/http, k6/crypto, k6/encoding...) và một số thư viện tương thích. Muốn dùng thư viện ngoài, thường phải bundle qua webpack/rollup hoặc dùng xk6 (nội dung nâng cao ở bài 42).

Lỗi 2: Nhầm VU với số request. 10 VU không có nghĩa là 10 request. Mỗi VU lặp liên tục, nên 10 VU trong 30 giây có thể tạo ra hàng trăm, hàng nghìn request tùy độ nhanh của server và sleep.

Lỗi 3: Quên sleep, tạo tải phi thực tế. Nếu bỏ sleep, mỗi VU sẽ "bắn" request nhanh nhất có thể — điều người dùng thật không bao giờ làm. Kết quả là bạn test ra một kịch bản không giống đời thực. Luôn thêm khoảng nghỉ hợp lý (thường gọi là think time).

Lỗi 4: Chạy k6 để tạo tải khổng lồ ngay trên máy cá nhân yếu. Máy tạo tải cũng có giới hạn CPU/mạng. Nếu chính máy chạy k6 bị nghẽn, số liệu latency sẽ sai — bạn đo cái nghẽn của máy mình chứ không phải của server.

Mẹo hay:

  • Dùng cờ --http-debug để xem chi tiết request/response khi debug script.
  • Đặt tên check rõ ràng bằng tiếng Việt hoặc tiếng Anh mô tả đúng ý — output sẽ dễ đọc hơn nhiều.
  • Bắt đầu với 1 VU để chắc chắn script chạy đúng logic, rồi mới tăng tải. Đừng viết xong nhảy thẳng lên 1.000 VU.
  • Chia script thành các file module (login, browse, checkout) ngay từ đầu để dễ bảo trì — đây là lợi thế lớn của việc "test là code".

Bài tập thực hành

  • Cài đặt và chạy hello world. Cài k6 trên máy bạn, viết script gọi https://test.k6.io, thêm một check kiểm tra status 200, chạy với 1 VU và đọc toàn bộ output. Ghi lại giá trị http_req_duration p(95).
  • Tăng tải và quan sát. Chạy lại script với --vus 20 --duration 1m. So sánh p(95) với lần chạy 1 VU. Nó tăng lên không? Vì sao? Ghi lại tổng số http_reqs và số request/giây.
  • Viết đoạn so sánh triết lý. Trong 150–200 từ, viết cho một đồng nghiệp đang dùng JMeter, giải thích ba lý do bạn muốn thử k6 cho dự án tiếp theo, dựa trên khái niệm test-as-code, kiến trúc Go, và tính hợp CI/CD. Đây là bài luyện tư duy, không chỉ tay chân.
  • Bắt lỗi cố ý. Đổi URL thành một endpoint không tồn tại (ví dụ https://test.k6.io/khong-ton-tai), chạy lại và quan sát http_req_failed cùng kết quả check. Hiểu cách k6 báo lỗi trước khi bạn cần nó trong thực tế.

Tóm tắt

k6 là công cụ load testing hiện đại của Grafana Labs, với triết lý cốt lõi là "test là code": bạn viết kịch bản bằng JavaScript, quản lý bằng Git, chạy từ dòng lệnh và tích hợp tự nhiên vào CI/CD. Kiến trúc lai — lõi Go cho hiệu năng, JavaScript cho trải nghiệm viết test — giúp k6 tạo được lượng lớn VU với ít tài nguyên, đồng thời giữ script gọn gàng dễ bảo trì.

Những điều cần khắc cốt ghi tâm sau bài này: VU (Virtual User) là đơn vị tải, mỗi VU lặp hàm export default function(); k6 không chạy trên Node.js mà dùng runtime riêng; và k6 không phải "kẻ thay thế" JMeter một cách tuyệt đối, mà là một lựa chọn phù hợp hơn với văn hóa developer-centric và DevOps. Qua ba tình huống thực tế — startup giao đồ ăn, fintech Singapore, và developer tự test — bạn thấy k6 tỏa sáng khi đội ngũ coi trọng Git, cần tải lớn với chi phí thấp, và muốn đẩy kiểm thử về sớm trong vòng đời phát triển.

Bạn vừa chạy được load test k6 đầu tiên. Ở các bài tiếp theo, chúng ta sẽ đi sâu vào cách khai báo tải bài bản qua Options và Stages, thiết kế Scenarios với các executor khác nhau, và dựng các cổng chất lượng (SLA gates) bằng Checks và Thresholds. Nền tảng tư duy bạn có hôm nay sẽ khiến tất cả những điều đó trở nên tự nhiên.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi