Membedah lapisan jaringan dalam load test: mengendalikan perilaku TLS dengan insecureSkipTLSVerify, noConnectionReuse, dan maxRedirects, mengatur userAgent, menguji WebSocket dengan modul k6/ws, serta menyinggung dukungan HTTP/2 dan browser module.

Sejak episode 1, kita menulis request HTTP dan membacanya seolah request itu melayang sendiri dari kode ke server. Di episode 9 kemarin kalian sudah membangun skenario multi-endpoint yang menyerupai perjalanan pengguna sungguhan. Tapi setiap request itu sebenarnya melewati lapisan jaringan yang punya perilaku tersendiri: TCP handshake, TLS handshake, keep-alive, redirect, hingga kemungkinan upgrade koneksi menjadi WebSocket. Di bawah beban tinggi, lapisan ini sering menjadi titik pertama yang menyerah — bukan kode aplikasi kalian.
Bayangkan mengukur waktu tempuh perjalanan dari rumah ke kantor, tapi kalian hanya mencatat waktu sampai gerbang kompleks, mengabaikan antrean lift, lampu lalu lintas, dan gate security. Itu gambaran load test yang mengabaikan lapisan jaringan. Episode ini mengisi celah itu: kita akan mengendalikan bagaimana k6 memperlakukan koneksi, kapan menguji WebSocket, dan protokol apa saja yang didukung k6 saat ini.
Sebuah aplikasi bisa secepat kilat di kode aplikasinya, tapi jika TLS handshake memakan 200 ms, itu yang akan tercatat sebagai http_req_duration. Redirect yang tidak di-follow membuat k6 mencatat status 3xx yang tidak pernah kalian lihat di browser. Koneksi yang di-buka-ulang tanpa henti membuat jumlah koneksi TCP meledak di sisi server — hal yang tidak akan dilakukan browser sungguhan.
k6 memberi kalian beberapa opsi untuk meniru perilaku klien nyata dengan tepat. Opsi-opsi ini biasanya diletakkan di options agar terdokumentasi bersama script:
export const options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
maxRedirects: 10,
userAgent: "BelajarK6/1.0 (+https://example.com)",
vus: 20,
duration: "2m",
};Kita bedah satu per satu:
insecureSkipTLSVerify — menonaktifkan verifikasi sertifikat TLS. Nilai true hanya dibenarkan saat target memakai sertifikat self-signed (misal staging yang belum dilengkapi CA internal). Ini seperti membuka pintu tanpa memeriksa KTP pengunjung — praktis, tapi berbahaya di lingkungan produksi.noConnectionReuse — ketika false (default), k6 memakai HTTP keep-alive dan menggunakan ulang koneksi TCP antar request, persis seperti browser. Saat true, setiap request membuka koneksi baru. Uji dengan nilai true berguna untuk mengukur beban di sisi server yang lemah dalam menangani koneksi baru, tetapi ingat ini menambah biaya handshake ke angka latensi kalian.maxRedirects — berapa banyak redirect yang di-follow sebelum menyerah. K6 mengikuti redirect (3xx) secara otomatis, sehingga http_req_duration mencakup seluruh rantai redirect. Batas 10 hampir selalu cukup; redirect yang berputar tanpa henti (redirect loop) adalah bug yang ingin kalian lihat sebagai error, bukan mengikutinya selamanya.userAgent — nilai header User-Agent yang dikirim k6. Defaultnya menandakan k6 (misal k6/0.58.0). Memakai user agent kustom membantu kalian mengidentifikasi trafik tes di log server, dan memastikan WAF atau analitik memperlakukan request secara konsisten.Warning
Jangan sekali-kali mengaktifkan insecureSkipTLSVerify di produksi secara
permanen. Tes yang mem-bypass verifikasi TLS tidak lagi memvalidasi
kesehatan infrastruktur sertifikat — salah satu lapisan keamanan yang justru
paling sering bermasalah. Gunakan hanya untuk lingkungan yang memang memakai
sertifikat internal.
Default k6 sudah benar untuk kebanyakan kasus: koneksi dipakai ulang (keep-alive), seperti yang dilakukan browser. Uji coba dengan noConnectionReuse: true adalah latihan khusus untuk menjawab pertanyaan spesifik: "bagaimana server menangani ledakan pembukaan koneksi baru?" Ini relevan saat kalian mensimulasikan ribuan pengguna yang baru datang setelah aplikasi lama tidak aktif — setiap pengguna itu membuka koneksi segar.
Perhatikan perbedaan yang kalian lihat di ringkasan akhir: dengan koneksi baru per request, http_req_blocked dan http_req_connecting akan membengkak karena koneksi harus melewati DNS dan TCP handshake dulu. Angka itu sendiri bukan bug — itu cerminan kondisi jaringan yang kalian ciptakan.
Redirect bukan hal sepele. Setelah login, aplikasi sering mengarahkan pengguna ke halaman lain. Jika k6 berhenti di response 302 pertama, kalian tidak pernah mengukur halaman yang sebenarnya dipakai pengguna. Dengan maxRedirects: 10, k6 menelusuri rantai redirect dan melaporkan satu response final dengan redirect_count sebagai tag sistemnya.
Ada satu jebakan: setiap hop redirect menambah latensi. Jika dashboard kalian menampilkan http_req_duration yang tinggi, tanyakan dulu apakah bagian terbesarnya berasal dari rangkaian redirect, bukan dari aplikasi. Memisahkan ukuran redirect dari waktu eksekusi endpoint asli adalah alasan utama kenapa kalian menandai request dengan tag (kita bedah tuntas di episode 14).
Sebagian aplikasi tidak berkomunikasi dengan pola tanya-jawab HTTP. Chat, notifikasi real-time, kolaborasi dokumen, dan streaming harga memakai WebSocket: koneksi tunggal yang tetap terbuka, tempat klien dan server saling mengirim pesan kapan pun.
Analogi paling pas: HTTP seperti memesan makanan lewat antrean — setiap permintaan berdiri di antrean sendiri dan menerima jawaban sendiri. WebSocket seperti saluran telepon yang tetap tersambung — begitu diangkat, dua belah pihak bisa bicara bergantian tanpa menutup sambungan.
Modul k6 menangani ini lewat import ws from "k6/ws". Pola dasarnya: ws.connect(url, params, function (socket) { ... }) — di dalam callback inilah kalian mendaftarkan handler peristiwa:
import ws from "k6/ws";
import { check } from "k6";
export const options = {
vus: 10,
duration: "30s",
};
export default function () {
const res = ws.connect("wss://echo.websocket.org", { tags: { endpoint: "ws-echo" } }, function (socket) {
socket.on("open", function () {
socket.send("ping dari VU");
});
socket.on("message", function (message) {
check(message, {
"server membalas dengan teks asli": (msg) => msg.includes("ping dari VU"),
});
socket.close();
});
socket.on("close", function () {
console.log("koneksi WebSocket ditutup");
});
});
check(res, {
"handshake WebSocket sukses": (r) => r.status === 101,
});
}Alurnya: socket.on("open") menandakan handshake selesai dan koneksi siap dipakai — di sinilah kalian mengirim pesan pertama lewat socket.send("..."). Setiap balasan dari server memicu socket.on("message"), tempat kalian menjalankan check. socket.close() menutup koneksi secara elegan; tanpa ini koneksi akan dibiarkan menggantung sampai VU berakhir.
Perhatikan r.status === 101 — ws.connect mengembalikan objek response dengan status dari handshake. Status 101 berarti koneksi berhasil di-upgrade dari HTTP ke WebSocket. Ini check paling mendasar: jika handshake gagal (misalnya karena server tidak mendukung WebSocket di jalur tersebut), seluruh pengujian sia-sia.
WebSocket memberi wawasan yang tidak didapat dari HTTP biasa: berapa lama handshake berlangsung, seberapa cepat pesan membalas, dan bagaimana server menangani ribuan koneksi yang terbuka bersamaan. Chat berskala besar mati bukan karena CPU, melainkan karena kehabisan file descriptor atau koneksi database per-socket. Uji WebSocket adalah satu-satunya cara melihat itu sebelum pengguna melihatnya.
Dua hal yang sering ditanyakan pemula:
HTTP/2 — k6 mendukung HTTP/2 untuk permintaan HTTP lewat modul k6/http sejak lama. K6 otomatis memakai HTTP/2 saat server menyatakan dukungannya selama handshake TLS (ALPN), tanpa perlu konfigurasi tambahan. Artinya multiplexing dan kompresi header yang disediakan HTTP/2 ikut terukur secara realistis.
Browser module — untuk menguji perilaku browser sungguhan (JavaScript berjalan, layout, interaksi penuh halaman), k6 menyediakan import browser from "k6/browser". Ini kelas tersendiri: ia menjalankan Chromium asli dan melengkapi, bukan menggantikan, pengujian protokol HTTP. Pengujian browser jauh lebih berat, sehingga praktik terbaiknya adalah memakai browser module untuk beberapa perjalanan kritis, bukan untuk ribuan VU.
Titik pijak yang benar: mulai dari protokol HTTP + WebSocket yang murah dan cepat. Tambahkan browser module hanya untuk skenario yang benar-benar membutuhkan eksekusi JavaScript klien.
userAgent — trafik k6 tidak bisa dikenali di log server, menyulitkan kolaborasi dengan tim infra saat ada anomali.insecureSkipTLSVerify: true tertinggal di script produksi — jadikan aturan: opsi ini hanya boleh muncul via __ENV untuk lingkungan tertentu, bukan hardcoded.http_req_duration.maxRedirects yang cukup, tetapi latensinya tercampur. Beri tag untuk memisahkan.Pada episode 10 ini kalian telah memahami lapisan jaringan yang selama ini "tersembunyi" di balik request HTTP: mengendalikan verifikasi TLS lewat insecureSkipTLSVerify, menyimulasikan pembukaan koneksi baru dengan noConnectionReuse, membatasi dan membaca rantai redirect via maxRedirects, menandai trafik dengan userAgent, menguji WebSocket end-to-end dengan modul k6/ws (handshake, kirim, terima, tutup), serta mengenal dukungan HTTP/2 dan browser module.
Inti yang harus kalian bawa:
insecureSkipTLSVerify adalah pengecualian untuk lingkungan tertentu, bukan gaya hidup.ws.connect, bukan dengan modul HTTP; handshake 101 adalah tanda sukses.Sekarang kalian bisa menembus lapisan jaringan. Tapi sebagian besar API yang ingin kalian uji tidak membuka pintunya begitu saja — mereka memakai otentikasi. Di episode 11 selanjutnya kita akan membahas Otentikasi, Otorisasi & Access Control: login lalu memakai token, sesi berbasis cookie, API key, sampai strategi refresh token di tengah skenario panjang. Siapkan akun uji kalian, sampai jumpa di episode 11!