# Week 13: Lab Exercise - Performance Testing

## วัตถุประสงค์ของการปฏิบัติการ

หลังจากสิ้นสุดการปฏิบัติการนี้ ผู้เรียนจะสามารถ:

1. ติดตั้งและใช้งาน k6 สำหรับการทดสอบโหลด
2. สร้างและดำเนินการสคริปต์การทดสอบประสิทธิภาพ
3. วิเคราะห์ผลลัพธ์การทดสอบและประเมินประสิทธิภาพของระบบ
4. ระบุและบันทึกจุดคอขวดด้านประสิทธิภาพ
5. ติดตั้งและใช้งานการทดสอบการเปลี่ยนแปลงภาพด้วย Playwright (ทางเลือก)
6. จัดการฐานข้อมูลภาพสำหรับการเปรียบเทียบ
7. ทดสอบการออกแบบของสื่อประสาท (Responsive Design)

---

## ความเชื่อมโยงระหว่างสัปดาห์ 12 และ 13

**สัปดาห์ที่ 12 (สัปดาห์ที่ผ่านมา):** การทดสอบความปลอดภัย

- ค้นหา บันทึก และบันทึกรายละเอียดช่องโหว่ด้านความปลอดภัย

**สัปดาห์ที่ 13 (สัปดาห์นี้):** การทดสอบประสิทธิภาพ

- ใช้ API เดียวกัน และทดสอบภายใต้ภาระการทำงานสูง
- คำถามหลัก: "เมื่อระบบมีความปลอดภัย ระบบสามารถรับภาระการทำงานได้เท่าใด?"

---

## ตารางเวลาการปฏิบัติการ

- **ส่วนที่ 1: การทดสอบประสิทธิภาพด้วย k6**
  - ติดตั้งเครื่องมือ: 10 นาที
  - ปฏิบัติการที่ 1: การทดสอบโหลดพื้นฐาน
  - ปฏิบัติการที่ 2: สถานการณ์การทดสอบขั้นสูง

- **ส่วนที่ 2: การทดสอบการเปลี่ยนแปลงภาพ** (20 นาที) [ทางเลือก]
  - ปฏิบัติการที่ 3: ติดตั้งการทดสอบการเปลี่ยนแปลงภาพ (10 นาที)
  - ปฏิบัติการที่ 4: การทดสอบการออกแบบแบบรับสภาวะ (10 นาที)

---

## ความพร้อมของระบบสำหรับการปฏิบัติการ

- ระบบจัดการห้องสมุด v2 ที่พร้อมทำงาน
- Node.js เวอร์ชัน 18 ขึ้นไป ติดตั้งแล้ว
- Playwright ติดตั้งแล้ว (จากการปฏิบัติการในสัปดาห์ที่ 12)
- ความรู้เกี่ยวกับ HTTP และ APIs จากสัปดาห์ที่ 11
- (ทางเลือก) เครื่องมือเช่น Burp Suite หรือ OWASP ZAP สำหรับการทดสอบความปลอดภัยเพิ่มเติม

---

---

# ส่วนที่ 1: การทดสอบประสิทธิภาพด่วย k6 (40 นาที)

---

## ปฏิบัติการที่ 1: ติดตั้ง k6 และการทดสอบโหลดพื้นฐาน (25 นาที)

---

### ขั้นตอนที่ 1: ติดตั้ง k6

เลือกระบบปฏิบัติการของคุณ:

#### **Windows (ใช้ Chocolatey):**

```bash
# ตรวจสอบว่าติดตั้ง Chocolatey แล้ว
# หากยังไม่ได้ ไปที่: https://chocolatey.org/install

choco install k6
```

#### **macOS:**

```bash
brew install k6
```

#### **Linux (Debian/Ubuntu):**

```bash
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6-list
sudo apt-get update
sudo apt-get install k6
```

#### **ตรวจสอบการติดตั้ง:**

```bash
k6 version
# ควรแสดงผล: k6 v0.47.0 (หรือเวอร์ชันที่ใหม่กว่า)
```

---

### ขั้นตอนที่ 2: ตรวจสอบว่าระบบจัดการห้องสมุดกำลังทำงาน

```bash
# เปิดเทอร์มินัลแยกต่างหาก จากนั้นเริ่มระบบจัดการห้องสมุด
cd Library-Management-v2
docker-compose up

# หรือหากใช้ npm:
npm start

# จากนั้นเปิดเบราว์เซอร์และเข้าไปที่ http://localhost:8080
# ผลลัพธ์: ควรแสดงหน้า login
```

---

### ขั้นตอนที่ 3: สร้างสคริปต์การทดสอบโหลดเบื้องต้นของคุณ

**สร้างไดเรกทอรี่:**

```bash
mkdir -p tests/performance
```

**สร้างไฟล์:** `tests/performance/01-basic-load-test.js`

**เนื้อหา:**

```javascript
import http from "k6/http";
import { check, sleep } from "k6";

// การกำหนดค่าสำหรับการทดสอบ
export const options = {
  vus: 10, // จำนวนผู้ใช้ที่จำลองขึ้น: 10 คน
  duration: "30s", // ระยะเวลาการทดสอบ: 30 วินาที

  thresholds: {
    // เกณฑ์: 95% ของคำขอต้องตอบสนองในเวลาน้อยกว่า 500ms
    http_req_duration: ["p(95)<500"],
    // เกณฑ์: อัตราข้อผิดพลาดต้องน้อยกว่า 1%
    http_req_failed: ["rate<0.01"],
  },
};

// ฟังก์ชันหลักของสถานการณ์การทดสอบ
export default function () {
  // กิจกรรมที่ 1: ขอเข้าสู่หน้าหลักของระบบ
  const homeResponse = http.get("http://localhost:8080/index.php");

  check(homeResponse, {
    "หน้าหลัก - รหัสสถานะ 200": (r) => r.status === 200,
    "หน้าหลัก - เวลาตอบสนอง < 500ms": (r) => r.timings.duration < 500,
    "หน้าหลัก - มีเนื้อหา": (r) => r.body.length > 0,
  });

  sleep(1); // จำลองเวลาที่ผู้ใช้อ่านหน้า

  // กิจกรรมที่ 2: ดูรายชื่อหนังสือ
  const booksResponse = http.get("http://localhost:8080/books.php");

  check(booksResponse, {
    "หน้ารายชื่อหนังสือ - รหัสสถานะ 200": (r) => r.status === 200,
    "หน้ารายชื่อหนังสือ - เวลาตอบสนอง < 500ms": (r) => r.timings.duration < 500,
  });

  sleep(1);

  // กิจกรรมที่ 3: ค้นหาหนังสือ
  const searchResponse = http.get(
    "http://localhost:8080/books.php?search=test",
  );

  check(searchResponse, {
    "การค้นหา - รหัสสถานะ 200": (r) => r.status === 200,
    "การค้นหา - เวลาตอบสนอง < 1000ms": (r) => r.timings.duration < 1000,
  });

  sleep(2); // จำลองเวลาหยุดที่นานกว่าหลังการค้นหา
}
```

**ดำเนินการทดสอบ:**

```bash
k6 run tests/performance/01-basic-load-test.js
```

**สิ่งที่ควรสังเกตในผลลัพธ์:**

```
ผลลัพธ์: เซิร์ฟเวอร์ตอบสนองและยอมรับคำขอ
เมตริกส์หลัก:
  - http_req_duration (เวลาตอบสนอง): ต้องน้อยกว่า 500ms สำหรับ P95
  - http_req_failed (อัตราข้อผิดพลาด): ควรเป็น 0%
  - Throughput (http_reqs): ระบบประมวลผลคำขอต่อวินาทีได้กี่รายการ
```

**การวิเคราะห์ผลลัพธ์:**

```
http_req_duration..: p(95)=380ms  (ผ่าน: < 500ms)
http_req_failed.....: 0.00%       (ผ่าน: < 1%)
http_reqs...........: 420  14/s    (ระบบประมวลผล 14 คำขอต่อวินาที)
```

---

## ปฏิบัติการที่ 2: สถานการณ์การทดสอบขั้นสูง (15 นาที)

### สร้างไฟล์: `tests/performance/02-advanced-scenarios.js`

**งานที่ทำ:** สร้างสคริปต์การทดสอบแบบเพิ่มโหลดเรื่อยๆ

```javascript
import http from "k6/http";
import { check, sleep } from "k6";

// สถานการณ์ที่ 1: การเพิ่มภาระการทำงานแบบค่อยเป็นค่อยไป (จำลองช่วงเวลาเบสี่นก)
export const options = {
  stages: [
    { duration: "2m", target: 20 }, // เพิ่มตั้งแต่ 0 ถึง 20 ผู้ใช้ในเวลา 2 นาที
    { duration: "3m", target: 20 }, // คงอยู่ที่ 20 ผู้ใช้เป็นเวลา 3 นาที (สูงสุด)
    { duration: "2m", target: 0 }, // ลดลงจาก 20 เป็น 0 ผู้ใช้
  ],

  thresholds: {
    http_req_duration: ["p(95)<500", "p(99)<1000"], // ตั้งเกณฑ์สำหรับ P95 และ P99
    http_req_failed: ["rate<0.01"],
    iterations: ["rate>0"], // ต้องมีการทำซ้ำ
  },
};

export default function () {
  // จำลองการเข้าสู่ระบบของผู้ใช้
  const loginRes = http.post("http://localhost:8080/login.php", {
    username: "teacher1",
    password: "password123",
  });

  check(loginRes, {
    การเข้าสู่ระบบสำเร็จ: (r) => r.status === 200,
  });

  sleep(1);

  // ดูรายชื่อหนังสือ
  const booksRes = http.get("http://localhost:8080/books.php");
  check(booksRes, {
    รายชื่อหนังสือโหลดสำเร็จ: (r) => r.status === 200,
  });

  sleep(2);

  // ค้นหาหนังสือ
  const searchRes = http.get("http://localhost:8080/books.php?search=java");
  check(searchRes, {
    การค้นหาทำงานถูกต้อง: (r) => r.status === 200,
  });

  sleep(1);
}
```

**Run it:**

```bash
k6 run tests/performance/02-advanced-scenarios.js
```

**Observe:**

- How does response time change as load increases?
- When does error rate appear?
- At what point does system degrade?

---

### ปฏิบัติการเพิ่มเติม 2b: การทดสอบภาวะเค้น (ค้นหาจุดที่ระบบพังแล้ว)

**สร้างไฟล์:** `03-stress-test.js`

```javascript
export const options = {
  stages: [
    { duration: "1m", target: 50 }, // เพิ่มเป็น 50 ผู้ใช้
    { duration: "1m", target: 100 }, // เพิ่มเป็น 100 ผู้ใช้
    { duration: "1m", target: 200 }, // เพิ่มเป็น 200 ผู้ใช้
    { duration: "1m", target: 500 }, // เพิ่มเป็น 500 ผู้ใช้
    { duration: "30s", target: 0 }, // ลดลงเป็น 0
  ],

  thresholds: {
    http_req_duration: ["p(95)<2000"], // มีความเคร่งครัดน้อยลงภายใต้ความกดดัน
    http_req_failed: ["rate<0.1"], // ยอมให้มีข้อผิดพลาดสูงสุด 10%
  },
};

// (ใช้ฟังก์ชันทดสอบเดียวกันจากปฏิบัติการ 2)
// รัน: k6 run 03-stress-test.js
// สังเกต: ว่าจะเกิดปัญหาเมื่อมีผู้ใช้จำลองกี่คน
```

# การสร้างรายงานการทดสอบประสิทธิภาพ

## โครงสร้างของรายงาน

สร้างไฟล์: `PERFORMANCE_TEST_REPORT.md`

```markdown
# รายงานการทดสอบประสิทธิภาพ

สัปดาห์ที่ 13 - ระบบจัดการห้องสมุด

---

## บทสรุปสำหรับผู้บริหาร

ทำการทดสอบประสิทธิภาพของระบบจัดการห้องสมุด
ผลลัพธ์โดยรวม: PASS / MARGINAL / FAIL

ข้อค้นพบสำคัญ:

- จำนวนผู้ใช้พร้อมกันสูงสุดที่ระบบรองรับ: [X]
- เวลาตอบสนอง P95: [XXX]ms
- อัตราข้อผิดพลาดภายใต้ภาระการทำงานสูงสุด: [X]%

---

## สภาพแวดล้อมการทดสอบ

- เซิร์ฟเวอร์: localhost:8080
- ฐานข้อมูล: MySQL (ในเครื่อง)
- เครือข่าย: เครือข่าย LAN ท้องถิ่น
- ระยะเวลาการทดสอบ: [รายละเอียด]

---

## สถานการณ์การทดสอบที่ดำเนินการ

### 1. การทดสอบโหลดพื้นฐาน (ปฏิบัติการ 1)

- ระยะเวลา: 30 วินาที
- จำนวนผู้ใช้จำลอง: 10 คนพร้อมกัน
- จุดปลายทางที่ทดสอบ: /index.php, /books.php, /books.php?search=
- ผลลัพธ์:
  - เวลาตอบสนองเฉลี่ย: XXXms
  - เวลาตอบสนอง P95: XXXms
  - ความสามารถในการประมวลผล: XX คำขอต่อวินาที
  - อัตราข้อผิดพลาด: X.X%
  - สถานะ: PASS / FAIL

### 2. การทดสอบภาระการทำงานที่เพิ่มขึ้น (ปฏิบัติการ 2)

- ระยะเวลา: 7 นาที
- ขั้นตอน: 0→20→20→0 ผู้ใช้
- ผลลัพธ์:
  - เวลาตอบสนองสูงสุด: XXXms
  - ความสามารถในการประมวลผลสูงสุด: XX คำขอต่อวินาที
  - อัตราข้อผิดพลาดที่ภาระการทำงานสูง: X%
  - สถานะ: PASS / FAIL

### 3. การทดสอบภาวะเค้น (อาจารย์เลือก - ปฏิบัติการ 2b)

- ระยะเวลา: 4 นาที
- ภาระการทำงานสูงสุด: XXX ผู้ใช้พร้อมกัน
- จุดพัง: ระบบรองรับได้มากถึง XXX ผู้ใช้ก่อนที่จะเกิด [ปัญหา]
- สถานะ: Stable / Degradation / Crashed

---

## Performance Metrics Analysis

### เวลาตอบสนอง
```

P50 (ค่ามัธยฐาน): 200ms
P95 (สำคัญ): 450ms (เป้าหมาย: < 500ms)
P99 (กรณีสุดขั้ว): 1200ms (1% ของผู้ใช้มีการตอบสนองช้า)
สูงสุด (กรณีร้ายแรว่): 3500ms

```

### ความสามารถในการประมวลผล
- เฉลี่ย: 14 คำขอต่อวินาที
- สูงสุด: 18 คำขอต่อวินาที
- ต่ำสุด: 5 คำขอต่อวินาที

### อัตราข้อผิดพลาด
- โดยรวม: 0.00%
- ที่ภาระการทำงานสูง: 0.05%
- ในระหว่างการทดสอบภาวะเค้น: 2.5%

### การใช้งานทรัพยากร
- อัตราการใช้งาน CPU: 45% (สุขภาพดี)
- หน่วยความจำ: 620MB (สุขภาพดี)
- การเชื่อมต่อฐานข้อมูล: 8/50 (มีพื้นที่เพียงพอ)

---

## จุดคอขวดที่ระบุได้

### จุดคอขวดที่ 1: ประสิทธิภาพของการค้นหา
- การสังเกต: การค้นหาใช้เวลา 800-1200ms
- สาเหตุ: ไม่มีดัชนีฐานข้อมูล (index) สำหรับเขตข้อมูล books.title
- ข้อเสนอแนะ: สร้างดัชนีแบบประกอบ (composite index) บน (title, author)
- ความสำคัญ: สูง

### จุดคอขวดที่ 2: การเชื่อมต่อฐานข้อมูล
- การสังเกต: เมื่อมีผู้ใช้ 500 คนพร้อมกัน การเชื่อมต่อถึงขีดจำกัด
- สาเหตุ: ขนาดของกลุ่มการเชื่อมต่อปัจจุบัน: 10 การเชื่อมต่อ
- ข้อเสนอแนะ: เพิ่มขึ้นเป็น 50 การเชื่อมต่อ
- ความสำคัญ: ปานกลาง

---

## การเปรียบเทียบกับข้อตกลงระดับบริการ (SLA)

| ความต้องการ | เป้าหมาย | ผลลัพธ์จริง | สถานะ |
|-------------|--------|--------|--------|
| การค้นหา P95 | <500ms | 450ms | PASS |
| การยืมหนังสือ P95 | <1000ms | 950ms | PASS |
| อัตราข้อผิดพลาด | <0.1% | 0.00% | PASS |
| ความพร้อมใช้งาน | 99.5% | 100% | PASS |
| ผู้ใช้พร้อมกัน | 100+ | 50 with issues | MARGINAL |

---

## บทสรุป

### สิ่งที่ทำงานได้ดี
- เวลาตอบสนองตรงตามข้อตกลงระดับบริการสำหรับภาระการทำงานที่คาดหวัง
- การจัดการบ้นผิดพลาดเป็นแบบยั่งยืน
- ฐานข้อมูลมีเสถียรภาพ

### สิ่งที่ต้องปรับปรุง
- การค้นหามีความเร็วน้อยกว่าการคาด (ขาดดัชนี)
- ไม่สามารถรองรับผู้ใช้ 500+ คนพร้อมกัน
- อาจมีการรั่วไหลของหน่วยความจำ (ต้องติดตั้งการตรวจสอบหน่วยความจำ)

### ข้อเสนอแนะ (เรียงตามความสำคัญ)
1. **ความสำคัญสูง:** เพิ่มดัชนีฐานข้อมูลบน books.title
   - ความพยายาม: 30 นาที
   - การปรับปรุงที่คาดหวัง: การค้นหาเร็วขึ้น 3-5 เท่า

2. **ความสำคัญสูง:** เพิ่มขนาดของกลุ่มการเชื่อมต่อฐานข้อมูล
   - ความพยายาม: 15 นาที
   - การปรับปรุงที่คาดหวัง: รองรับผู้ใช้พร้อมกัน 200+ คน

3. **ความสำคัญปานกลาง:** ปรับใช้การจัดเก็บแคชสำหรับรายชื่อหนังสือ
   - ความพยายาม: 2-4 ชั่วโมง
   - การปรับปรุงที่คาดหวัง: การค้นหาที่เป็นที่นิยมเร็วขึ้น 10 เท่า

4. **ความสำคัญต่ำ:** ติดตามการรั่วไหลของหน่วยความจำภายใต้ภาระการทำงานต่อเนื่อง
   - ระยะเวลาการทดสอบ: การทดสอบ 24 ชั่วโมง
   - สถานะปัจจุบัน: ยังไม่ได้ทดสอบ

---

## ขั้นตอนต่อไป

1. แชร์รายงานกับทีมพัฒนา
2. ผู้พัฒนานำเสนอการปรับปรุงที่แนะนำ
3. ทดสอบซ้ำหลังจากการปรับปรุง
4. กำหนดหลักเกณฑ์เมตริกการทำงานใหม่
5. สร้างการทดสอบประสิทธิภาพในไปป์ไลน์ CI/CD

---

## Appendices

### ก. สคริปต์การทดสอบ k6
[แนบไฟล์การทดสอบ: 01-basic-load-test.js, 02-advanced-scenarios.js]

### ข. เมตริกรายละเอียด (ผลลัพธ์จริง)
[วางผลลัพธ์คอนโซล k6 ทั้งหมด]

### ค. ภาพหน้าจออและกราฟ (ทางเลือก)
[รวมกราฟของเวลาตอบสนองในช่วงเวลา ฯลฯ]

---

**วันที่รายงาน:** [วันนี้]
**ทดสอบโดย:** [ทีมของคุณ]
**ระยะเวลา:** [X ชั่วโมงของการทดสอบ]
```

---

---

# เกณฑ์การประเมิน

| เกณฑ์การประเมิน                       |     | ยอดเยี่ยม                                                   | ดี                               | พอใจ                        | ต้องปรับปรุง     |
| ------------------------------------- | --- | ----------------------------------------------------------- | -------------------------------- | --------------------------- | ---------------- |
| **การติดตั้ง k6**                     |     | ติดตั้ง ตรวจสอบ และทำงานได้                                 | ติดตั้ง มีปัญหาบ้าง              | ติดตั้งบางส่วน              | ไม่ได้ติดตั้ง    |
| **ปฏิบัติการ 1: การทดสอบโหลดพื้นฐาน** |     | สคริปต์สร้าง ดำเนินการ และวิเคราะห์ผลลัพธ์อย่างถูกต้อง      | สคริปต์ทำงาน การวิเคราะห์พื้นฐาน | สคริปต์มีข้อผิดพลาด         | ไม่พยายาม        |
| **ปฏิบัติการ 2: สถานการณ์ขั้นสูง**    |     | สคริปต์พิเศษ กำหนดเกณฑ์ และตีความผลลัพธ์                    | สคริปต์สร้างและทำงาน             | สคริปต์สร้างแต่ไม่สมบูรณ์   | ไม่พยายาม        |
| **การทดสอบภาวะเค้น (ทางเลือก)**       |     | สิ้นสุด ระบุจุดพัง ให้ข้อเสนอแนะ                            | สิ้นสุด พบจุดพัง                 | พยายามแต่ไม่สมบูรณ์         | ไม่พยายาม        |
| **คุณภาพรายงาน**                      |     | ระดับมืออาชีพ เมตริกชัดเจน ระบุจุดคอขวด ข้อเสนอแนะที่ใช้ได้ | รายงานดี เมตริกส่วนใหญ่          | รายงานพื้นฐาน ขาดรายละเอียด | รายงานไม่สมบูรณ์ |

---

## ตัวชี้วัดประสิทธิภาพหลักที่ต้องติดตาม

ในฐานะผู้เรียน ให้รายงานเมตริกหลักเหล่านี้:

| เมตริก                        | ความหมาย                               | ช่วงที่ยอมรับได้                                |
| ----------------------------- | -------------------------------------- | ----------------------------------------------- |
| เวลาตอบสนอง P95               | 95% ของผู้ใช้ประสบการณ์นี้หรือเร็วกว่า | <500ms สำหรับการค้นหา <1000ms สำหรับการปรับปรุง |
| ความสามารถในการประมวลผล (RPS) | คำขอต่อวินาทีที่ระบบจัดการ             | ขึ้นอยู่กับการออกแบบระบบของคุณ                  |
| อัตราข้อผิดพลาด               | % ของคำขอที่ล้มเหลว                    | <1% ภายใต้ภาระการทำงานปกติ <5% ภายใต้ความกดดัน  |
| ผู้ใช้สูงสุด (VUs)            | จำนวนผู้ใช้พร้อมกันสูงสุดก่อนเกิดปัญหา | ควรรองรับ 100+                                  |
| การใช้งาน CPU                 | อัตราการใช้ประมวลผลเซิร์ฟเวอร์         | <70% ระบบสุขภาพดี >85% น่าเป็นห่วง              |
| หน่วยความจำ                   | การใช้งาน RAM เซิร์ฟเวอร์              | <80% ระบบสุขภาพดี >90% มีความเสี่ยง             |

---
