ในยุคที่แอปพลิเคชันมีความซับซ้อนมากขึ้นเรื่อยๆ Microservices Architecture ได้กลายมาเป็นหนึ่งในแนวทางที่นักพัฒนาหลายคนเลือกใช้ บทความนี้จะพาไปทำความเข้าใจว่าเราสามารถสร้าง Microservices ด้วย PHP แบบ Native โดยไม่ต้องพึ่งพา Framework ขนาดใหญ่ได้อย่างไร
Microservices คืออะไร?
Microservices Architecture คือรูปแบบการออกแบบซอฟต์แวร์ที่แบ่งแอปพลิเคชันออกเป็น บริการขนาดเล็กหลายๆ ตัว แต่ละตัวทำงานอิสระและสื่อสารกันผ่านเครือข่าย ตรงกันข้ามกับ Monolithic Architecture ที่ใส่ทุกอย่างไว้ในโค้ดเบสเดียวกัน
| คุณสมบัติ | Monolithic | Microservices |
|---|---|---|
| การ Deploy | Deploy ทั้งระบบพร้อมกัน | Deploy แยกอิสระแต่ละ Service |
| การ Scale | Scale ทั้งระบบ | Scale เฉพาะ Service ที่ต้องการ |
| เทคโนโลยี | Stack เดียวทั้งระบบ | แต่ละ Service เลือก Stack เองได้ |
| ความซับซ้อน | โค้ดซับซ้อนขึ้นเมื่อระบบใหญ่ | ซับซ้อนด้าน Infrastructure |
หลักการออกแบบ Microservices ด้วย PHP
เมื่อออกแบบ Microservices ด้วย PHP Native มีหลักการสำคัญ 3 ข้อที่ควรคำนึงถึง:
1. Single Responsibility — หนึ่ง Service หนึ่งหน้าที่
แต่ละ Microservice ควรรับผิดชอบเพียง Domain เดียว เช่น:
UserService— จัดการข้อมูลผู้ใช้และการลงทะเบียนAuthService— ดูแลการ Authentication และ TokenProductService— จัดการแคตตาล็อกสินค้าOrderService— ประมวลผลคำสั่งซื้อ
2. Independent Deployment — Deploy แยกกันได้
แต่ละ Service ควรมี Repository และสภาพแวดล้อมเป็นของตัวเอง สามารถอัปเดตหรือ Deploy ได้โดยไม่กระทบ Service อื่น
3. Network Communication — สื่อสารผ่านเครือข่าย
Services สื่อสารกันได้หลายรูปแบบ:
- HTTP/REST API — ง่ายที่สุด เหมาะสำหรับเริ่มต้น
- Message Queue (RabbitMQ, Redis) — เหมาะกับงาน Async
- gRPC — ประสิทธิภาพสูง รองรับ Binary Protocol
โครงสร้างโปรเจกต์
ตัวอย่างโครงสร้างโฟลเดอร์สำหรับแต่ละ Microservice:
services/
├── user-service/
│ ├── src/
│ │ ├── Controllers/
│ │ ├── Models/
│ │ └── Services/
│ ├── public/
│ │ └── index.php
│ ├── composer.json
│ └── Dockerfile
├── auth-service/
│ ├── src/
│ ├── public/
│ └── Dockerfile
└── product-service/
├── src/
├── public/
└── Dockerfileตัวอย่างโค้ด: HTTP Communication ใน PHP
วิธีง่ายที่สุดในการสื่อสารระหว่าง Services คือการใช้ file_get_contents() หรือ cURL:
แบบที่ 1: ใช้ file_get_contents
<?php
// ดึงข้อมูลผู้ใช้จาก UserService
$url = 'http://user-service.local/api/users/1';
$response = file_get_contents($url);
$user = json_decode($response, true);
echo "ชื่อผู้ใช้: " . $user['name'];
แบบที่ 2: ใช้ cURL (แนะนำ — ควบคุมได้มากกว่า)
<?php
function callService(string $url, string $method = 'GET', array $data = []): array
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $httpCode >= 400) {
throw new RuntimeException("Service call failed: HTTP $httpCode");
}
return json_decode($response, true);
}
// ตัวอย่างการใช้งาน
try {
// เรียก AuthService เพื่อ Login
$authResult = callService(
'http://auth-service.local/api/login',
'POST',
['email' => 'user@example.com', 'password' => 'secret']
);
$token = $authResult['token'];
echo "Login สำเร็จ! Token: $token";
// เรียก UserService ดึงข้อมูล
$user = callService('http://user-service.local/api/users/1');
echo "ชื่อ: " . $user['name'];
} catch (RuntimeException $e) {
echo "เกิดข้อผิดพลาด: " . $e->getMessage();
}
ตัวอย่าง: สร้าง Simple UserService
ตัวอย่าง UserService แบบ Native PHP ที่พร้อมใช้งาน:
<?php
// user-service/public/index.php
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// Routing แบบ Simple
if ($method === 'GET' && preg_match('#^/api/users/(\d+)$#', $path, $m)) {
echo json_encode(getUser((int)$m[1]));
} elseif ($method === 'GET' && $path === '/api/users') {
echo json_encode(getAllUsers());
} elseif ($method === 'POST' && $path === '/api/users') {
$body = json_decode(file_get_contents('php://input'), true);
echo json_encode(createUser($body));
} else {
http_response_code(404);
echo json_encode(['error' => 'Not Found']);
}
// ฟังก์ชันจำลองฐานข้อมูล
function getUser(int $id): array
{
$users = [
1 => ['id' => 1, 'name' => 'สมชาย ใจดี', 'email' => 'somchai@example.com'],
2 => ['id' => 2, 'name' => 'สมหญิง รักเรียน', 'email' => 'somying@example.com'],
];
return $users[$id] ?? ['error' => 'User not found'];
}
function getAllUsers(): array
{
return ['data' => [getUser(1), getUser(2)]];
}
function createUser(array $data): array
{
// บันทึกลง DB จริงๆ ในโปรเจกต์จริง
return ['success' => true, 'id' => rand(100, 999), 'data' => $data];
}
การใช้งาน Message Queue (Async)
สำหรับงานที่ไม่ต้องรอผลทันที เช่น ส่ง Email หรือประมวลผล Order แนะนำให้ใช้ Message Queue ร่วมกับ Redis หรือ RabbitMQ:
<?php
// Producer: OrderService ส่งข้อความไปยัง Queue
$redis = new Redis();
$redis->connect('redis', 6379);
$orderEvent = json_encode([
'event' => 'order.created',
'order_id' => 1234,
'user_id' => 56,
'total' => 1500.00,
'created_at' => date('c'),
]);
$redis->rPush('order_events', $orderEvent);
echo "Order event ส่งเข้า Queue เรียบร้อย";
<?php
// Consumer: EmailService รับข้อความจาก Queue (รัน background worker)
$redis = new Redis();
$redis->connect('redis', 6379);
echo "EmailService Worker เริ่มทำงาน...\n";
while (true) {
$message = $redis->blPop(['order_events'], 5); // รอ 5 วิ
if ($message) {
$event = json_decode($message[1], true);
if ($event['event'] === 'order.created') {
sendOrderConfirmationEmail($event['user_id'], $event['order_id']);
echo "ส่ง Email ยืนยัน Order #{$event['order_id']} แล้ว\n";
}
}
}
function sendOrderConfirmationEmail(int $userId, int $orderId): void
{
// Logic ส่ง Email จริงๆ
echo "Email ถึง User #$userId สำหรับ Order #$orderId\n";
}
Docker Compose สำหรับรัน Microservices
ใช้ Docker Compose จัดการ Services หลายตัวพร้อมกัน:
version: '3.8'
services:
user-service:
build: ./services/user-service
ports:
- "8001:80"
environment:
DB_HOST: user-db
DB_NAME: users_db
auth-service:
build: ./services/auth-service
ports:
- "8002:80"
environment:
JWT_SECRET: your-secret-key
product-service:
build: ./services/product-service
ports:
- "8003:80"
redis:
image: redis:alpine
ports:
- "6379:6379"
user-db:
image: mysql:8
environment:
MYSQL_DATABASE: users_db
MYSQL_ROOT_PASSWORD: secretข้อดีและข้อเสียของแนวทางนี้
✅ ข้อดี
- ไม่มี Framework Overhead — เร็วและเบา
- เข้าใจได้ง่าย เพราะเป็น PHP พื้นฐาน
- แต่ละ Service สามารถใช้ PHP Version ต่างกันได้
- Scale เฉพาะ Service ที่ Load สูงได้
- Team แยกกันพัฒนาได้โดยไม่ Conflict
❌ ข้อเสีย
- ต้องเขียน Boilerplate เยอะกว่า Framework
- ซับซ้อนด้าน Infrastructure และ DevOps
- Network Latency เพิ่มขึ้นจากการ Call ระหว่าง Services
- Debugging ยากขึ้น ต้องการ Distributed Tracing
สรุป
การสร้าง Microservices ด้วย Native PHP เป็นไปได้อย่างสมบูรณ์แบบ โดยใช้เพียง cURL, JSON, และ HTTP Standards ที่มีอยู่แล้วใน PHP โดยไม่จำเป็นต้องพึ่งพา Framework ขนาดใหญ่ อย่างไรก็ตาม ควรพิจารณาให้ดีก่อนว่าโปรเจกต์ของคุณมีความซับซ้อนพอที่จะได้ประโยชน์จาก Microservices จริงหรือไม่ เพราะสำหรับโปรเจกต์ขนาดกลาง Monolithic ที่ออกแบบดีๆ ก็ยังเป็นทางเลือกที่ดี


ความคิดเห็น
แสดงความคิดเห็น