การใช้งาน Redis Cache กับ PHP: ตัวอย่างการ Cache ข้อมูลจากฐานข้อมูล
ในบทความที่แล้ว เราได้เรียนรู้วิธีการติดตั้งและตั้งค่า Redis Server บน Ubuntu ในบทความนี้ เราจะมาดูวิธีการนำ Redis Cache มาใช้งานร่วมกับ PHP เพื่อเพิ่มประสิทธิภาพในการเข้าถึงข้อมูลจากฐานข้อมูล MySQL โดยเราจะทำการ Cache ผลลัพธ์ของ query เพื่อลดภาระของ database server และเพิ่มความเร็วในการตอบสนองของแอปพลิเคชัน
ขั้นตอนที่ 1: การติดตั้ง predis/predis library
ในการใช้งาน Redis กับ PHP เราจำเป็นต้องมี library ที่ช่วยในการเชื่อมต่อและสื่อสารกับ Redis Server Library ที่นิยมใช้กันคือ predis/predis ซึ่งสามารถติดตั้งได้ง่ายๆ ผ่าน Composer:
composer require predis/predis
หลังจากรันคำสั่งนี้ Composer จะทำการดาวน์โหลดและติดตั้ง predis/predis library ลงใน project ของเรา
ขั้นตอนที่ 2: การเชื่อมต่อกับ Redis Server
เมื่อติดตั้ง library เรียบร้อยแล้ว เราสามารถเริ่มเขียนโค้ด PHP เพื่อเชื่อมต่อกับ Redis Server ได้ ตัวอย่างเช่น:
<?php
require 'vendor/autoload.php'; // โหลด Composer autoloader
try {
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1', // หรือ IP address ของ Redis server
'port' => 6379, // default port
'password' => 'your_redis_password' // หากมีการตั้ง password ใน redis.conf
]);
$redis->ping(); // ตรวจสอบการเชื่อมต่อ
echo "Connected to Redis successfully!\n";
} catch (Exception $e) {
echo "Couldn't connect to Redis: " . $e->getMessage() . "\n";
}
?>
คำอธิบาย:
require 'vendor/autoload.php';: โหลด autoloader ของ Composer เพื่อให้สามารถใช้งาน predis/predis library ได้new Predis\Client([...]);: สร้าง instance ของ Predis client โดยระบุ scheme (tcp), host, port และ password (ถ้ามี)$redis->ping();: ส่งคำสั่ง PING ไปยัง Redis Server เพื่อตรวจสอบว่าการเชื่อมต่อสำเร็จหรือไม่try...catch: ใช้เพื่อดักจับ exception ที่อาจเกิดขึ้นระหว่างการเชื่อมต่อ เช่น Redis Server ไม่พร้อมใช้งาน หรือ password ไม่ถูกต้อง
ข้อผิดพลาดที่พบบ่อย:
- "Could not connect to Redis": ตรวจสอบให้แน่ใจว่า Redis Server กำลังทำงานอยู่ และ host, port, password ถูกต้อง
- "php_network_getaddresses: getaddrinfo failed": ตรวจสอบว่า host name ที่ระบุสามารถ resolve ได้หรือไม่ (เช่น ในกรณีที่ใช้ domain name)
ขั้นตอนที่ 3: การ get/set ค่าใน Redis
เมื่อเชื่อมต่อกับ Redis Server ได้แล้ว เราสามารถใช้คำสั่ง get และ set เพื่ออ่านและเขียนข้อมูลใน Redis ได้ ตัวอย่างเช่น:
<?php
require 'vendor/autoload.php';
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'your_redis_password'
]);
// Set ค่า
$redis->set('mykey', 'Hello Redis!');
// Get ค่า
$value = $redis->get('mykey');
echo "Value from Redis: " . $value . "\n"; // Output: Value from Redis: Hello Redis!
// Check if key exists
if ($redis->exists('mykey')) {
echo "Key 'mykey' exists in Redis.\n";
} else {
echo "Key 'mykey' does not exist in Redis.\n";
}
?>
คำอธิบาย:
$redis->set('mykey', 'Hello Redis!');: กำหนดค่า 'Hello Redis!' ให้กับ key ที่ชื่อ 'mykey'$redis->get('mykey');: อ่านค่าของ key 'mykey'$redis->exists('mykey');: ตรวจสอบว่า key 'mykey' มีอยู่ใน Redis หรือไม่
ขั้นตอนที่ 4: การกำหนด TTL (Time-To-Live)
TTL คือระยะเวลาที่ข้อมูลใน Redis จะถูกเก็บไว้ หลังจาก TTL หมดอายุ ข้อมูลนั้นจะถูกลบออกจาก Redis โดยอัตโนมัติ การกำหนด TTL มีประโยชน์ในการจัดการ cache data ที่มีการเปลี่ยนแปลงบ่อย ตัวอย่างเช่น:
<?php
require 'vendor/autoload.php';
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
'password' => 'your_redis_password'
]);
// Set ค่าพร้อมกำหนด TTL เป็น 60 วินาที
$redis->setex('mykey', 60, 'This data will expire in 60 seconds.');
// Get ค่า
$value = $redis->get('mykey');
echo "Value from Redis: " . $value . "\n";
sleep(61); // Wait for 61 seconds
$value = $redis->get('mykey');
echo "Value from Redis after 61 seconds: " . $value . "\n"; // Output: Value from Redis after 61 seconds: (null)
?>
คำอธิบาย:
$redis->setex('mykey', 60, 'This data will expire in 60 seconds.');: กำหนดค่าพร้อม TTL โดยsetexรับพารามิเตอร์ 3 ตัว: key, TTL (วินาที), และ value- หลังจาก 60 วินาที ข้อมูลที่เก็บไว้ใน key 'mykey' จะถูกลบออกจาก Redis ทำให้การเรียก
$redis->get('mykey')คืนค่าnull
ขั้นตอนที่ 5: การ cache query results
ตอนนี้เรามาดูตัวอย่างการ cache ผลลัพธ์ของ query จากฐานข้อมูล MySQL โดยสมมติว่าเรามีตาราง users ที่มี column id และ name เราต้องการ cache ข้อมูลผู้ใช้ที่มี id เท่ากับ 1
<?php
require 'vendor/autoload.php';
// Database connection parameters
$dbHost = 'localhost';
$dbName = 'mydatabase';
$dbUser = 'myuser';
$dbPass = 'mypassword';
// Redis connection parameters
$redisHost = '127.0.0.1';
$redisPort = 6379;
$redisPassword = 'your_redis_password';
try {
// Connect to Redis
$redis = new Predis\Client([
'scheme' => 'tcp',
'host' => $redisHost,
'port' => $redisPort,
'password' => $redisPassword
]);
// Connect to MySQL
$pdo = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUser, $dbPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$userId = 1;
$cacheKey = 'user:' . $userId;
// Try to get data from cache
$cachedData = $redis->get($cacheKey);
if ($cachedData) {
// Data found in cache
$user = json_decode($cachedData, true);
echo "Data retrieved from cache:\n";
print_r($user);
} else {
// Data not found in cache, fetch from database
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $userId);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
// Store data in cache with a TTL of 300 seconds (5 minutes)
$redis->setex($cacheKey, 300, json_encode($user));
echo "Data retrieved from database and stored in cache:\n";
print_r($user);
} else {
echo "User not found in database.\n";
}
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
คำอธิบาย:
- เชื่อมต่อกับทั้ง Redis Server และ MySQL database
- กำหนด
$cacheKeyโดยใช้ prefix 'user:' ตามด้วย user ID เพื่อให้ง่ายต่อการจัดการ cache data - พยายามอ่านข้อมูลจาก cache โดยใช้
$redis->get($cacheKey) - ถ้าข้อมูลอยู่ใน cache (
$cachedDataไม่เป็นnull) ให้ decode ข้อมูลจาก JSON และแสดงผล - ถ้าข้อมูลไม่อยู่ใน cache ให้ query จาก database, encode ข้อมูลเป็น JSON, และเก็บไว้ใน cache ด้วย TTL 300 วินาที
กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย:
- Cache Miss: ในครั้งแรกที่เรียกใช้ script ข้อมูลจะยังไม่อยู่ใน cache ทำให้ต้อง query จาก database
- Data Inconsistency: ถ้าข้อมูลใน database มีการเปลี่ยนแปลง แต่ cache ยังคงเก็บข้อมูลเก่าอยู่ จะทำให้เกิด data inconsistency แก้ไขได้โดยใช้ cache invalidation strategies ซึ่งจะกล่าวถึงในบทความถัดไป
- Serialization: การ serialize ข้อมูลเป็น JSON ก่อนเก็บใน Redis เป็นวิธีที่ง่ายและสะดวก แต่มี overhead ในการ encode/decode หากต้องการประสิทธิภาพที่สูงขึ้น อาจพิจารณาใช้ serialization format อื่นๆ เช่น MessagePack หรือ Protocol Buffers
ในบทความนี้ เราได้เรียนรู้วิธีการใช้งาน Redis Cache ร่วมกับ PHP เพื่อเพิ่มประสิทธิภาพในการเข้าถึงข้อมูลจากฐานข้อมูล MySQL เราได้เห็นตัวอย่างการเชื่อมต่อกับ Redis Server, การ get/set ค่า, การกำหนด TTL, และการ cache query results ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับ Cache Invalidation Strategies ซึ่งเป็นแนวทางการจัดการ cache ที่มีประสิทธิภาพ เพื่อให้มั่นใจว่าข้อมูลใน cache เป็นข้อมูลที่ถูกต้องและทันสมัยอยู่เสมอ