Redis: Cache ตัวเก่ง เสริมพลังเว็บให้เร็วปรู๊ดปร๊าด!

Redis: Cache ตัวเก่ง เสริมพลังเว็บให้เร็วปรู๊ดปร๊าด!

September 25, 2025

Database

ทุกคนครับ! เคยเจอปัญหานี้ไหมครับ?

  • เว็บไซต์หรือแอปของเราช่วงแรก ๆ ก็เร็วดี แต่พอผู้ใช้เยอะขึ้น ข้อมูลเยอะขึ้น อยู่ดี ๆ ก็เริ่ม โหลดช้าลง ซะอย่างนั้น
  • บางทีแค่ต้องการแสดงผลข้อมูลเดิม ๆ ซ้ำ ๆ บนหน้าเว็บ แต่ฐานข้อมูลก็ต้อง ทำงานหนัก ดึงข้อมูลชุดเดิมมาให้ทุกครั้ง
  • ผู้ใช้ก็บ่นว่า "เว็บอืดจังเลย" ...เป็นสัญญาณว่าถึงเวลาต้องหาตัวช่วยแล้ว😵!

วันนี้เราจะมาทำความรู้จักกับฮีโร่ที่จะมาช่วยแก้ปัญหานี้ นั่นก็คือ Redis ครับ! และจะเน้นไปที่บทบาทที่สำคัญที่สุดอย่างหนึ่ง นั่นก็คือการทำ Caching

Redis คืออะไร? (แบบเข้าใจง่าย)

Redis ย่อมาจาก Remote Dictionary Server มันคือ In-memory Data Structure Store ครับ (ฟังดูเท่ แต่ไม่ยากอย่างที่คิด!)

  • In-memory: จุดเด่นคือมันเก็บข้อมูลไว้ใน RAM (หน่วยความจำหลัก) ของเครื่อง Server ทำให้มันอ่านและเขียนข้อมูลได้ เร็วโคตร ๆ เมื่อเทียบกับการเก็บใน Hard Disk (แบบฐานข้อมูลทั่วไป)
  • Data Structure Store: ไม่ได้เป็นแค่ Key-Value Store ธรรมดา แต่เก็บข้อมูลได้หลากหลายรูปแบบ เช่น Strings, Hashes, Lists, Sets และ Sorted Sets ซึ่งแต่ละแบบก็มีประโยชน์ต่างกันไป

ด้วยความเร็วระดับฟ้าผ่า⚡ นี้แหละครับ ที่ทำให้ Redis เป็นตัวเลือกอันดับต้น ๆ สำหรับการทำ Caching

ทำไมต้อง Cache ด้วย Redis? (ปัญหาที่ Redis แก้ได้)

ลองนึกภาพว่าฐานข้อมูลของเราเป็นเหมือน "ห้องสมุดขนาดใหญ่" ที่มีหนังสือ (ข้อมูล) เยอะแยะมากมาย เวลาใครจะหาหนังสือ ก็ต้องเดินเข้าไปหา หยิบออกมา แล้วจดข้อมูลที่ต้องการ

ถ้ามีคน 100 คน อยากได้หนังสือเล่มเดียวกัน ฐานข้อมูลก็ต้องทำกระบวนการนี้ซ้ำ ๆ 100 ครั้ง ซึ่งกินเวลาและทรัพยากรมาก

Redis ในบทบาท Caching ก็เหมือนกับ "สมุดจดโน้ตส่วนตัวของบรรณารักษ์"

  • บรรณารักษ์ (แอปของเรา) ไปเอาหนังสือจากห้องสมุดมาครั้งแรก
  • จดข้อมูลสำคัญ ๆ ลงในสมุดโน้ต (Redis Cache)
  • ครั้งต่อไป ถ้ามีใครถามหาหนังสือเล่มเดิม บรรณารักษ์ก็แค่เปิดสมุดโน้ตดู แป๊บเดียวก็ได้คำตอบแล้ว! ไม่ต้องเดินเข้าห้องสมุดให้เสียเวลา

นี่คือหลักการง่าย ๆ ของ Caching เก็บข้อมูลที่ถูกเรียกใช้บ่อย ๆ หรือใช้เวลานานในการประมวลผลไว้ในที่ ที่เข้าถึงได้เร็วกว่า

Use Case: Caching API Responses (ตัวอย่างจริง)

สมมติว่าเรามี API สำหรับดึงรายการสินค้ายอดนิยม ที่ต้องไป Query ข้อมูลซับซ้อนจากฐานข้อมูลทุกครั้ง ซึ่งใช้เวลาประมาณ 500ms (ครึ่งวินาที)

ก่อนใช้ Redis: ผู้ใช้ 100 คนกดหน้านี้พร้อมกัน ฐานข้อมูลต้องทำงานหนัก 100 รอบ

Old API Route (No Cache)

// ตัวอย่าง: Node.js + Express
const express = require('express');
const app = express();
const db = require('./db'); // สมมติว่านี่คือการเชื่อมต่อฐานข้อมูล
 
app.get('/api/popular-products', async (req, res) => {
  console.log('Fetching from Database...');
  const products = await db.getComplexPopularProductsQuery(); // ใช้เวลา 500ms
  res.json(products);
});
 
app.listen(3000, () => console.log('Server running on port 3000'));

หลังจากใช้ Redis Caching: ผู้ใช้ 100 คนกดหน้านี้พร้อมกัน ฐานข้อมูลทำงานแค่ ครั้งแรก เท่านั้น! อีก 99 ครั้งที่เหลือดึงจาก Redis แค่ไม่กี่มิลลิวินาที

New API Route (With Redis Cache)

// ตัวอย่าง: Node.js + Express + Redis
const express = require('express');
const app = express();
const redis = require('redis');
const db = require('./db');
 
const client = redis.createClient(); // สร้าง Redis Client
client.connect(); // เชื่อมต่อ Redis
 
// API ดึงรายการสินค้ายอดนิยม
app.get('/api/popular-products', async (req, res) => {
  const cacheKey = 'popular_products'; // Key สำหรับเก็บข้อมูลใน Redis
 
  try {
    // 1. ลองดึงข้อมูลจาก Redis ก่อน
    const cachedProducts = await client.get(cacheKey);
 
    if (cachedProducts) {
      console.log('Serving from Redis Cache!');
      return res.json(JSON.parse(cachedProducts)); // ส่งข้อมูลจาก Cache
    }
 
    // 2. ถ้าไม่มีใน Redis (Cache Miss) ค่อยไปดึงจากฐานข้อมูล
    console.log('Fetching from Database...');
    const products = await db.getComplexPopularProductsQuery(); // ใช้เวลา 500ms
 
    // 3. เก็บข้อมูลที่ได้จากฐานข้อมูลลง Redis พร้อมกำหนดเวลาหมดอายุ (TTL)
    // EX: กำหนดให้ Cache หมดอายุใน 60 วินาที
    await client.set(cacheKey, JSON.stringify(products), {
      EX: 60, // Expire after 60 seconds
    });
 
    res.json(products);
 
  } catch (error) {
    console.error('Error:', error);
    res.status(500).send('Internal Server Error');
  }
});
 
app.listen(3000, () => console.log('Server running on port 3000'));

สิ่งสำคัญ: Cache Invalidation (การทำให้ Cache เป็นข้อมูลล่าสุด)

การมี Cache นั้นดี แต่ถ้าข้อมูลในฐานข้อมูลเปลี่ยนไป แต่ Cache ยังคงแสดงข้อมูลเก่าอยู่ (เรียกว่า Stale Data) ก็จะเป็นปัญหาใหญ่ได้! เราจึงต้องมีกลยุทธ์ในการ "บอก" Redis ว่าข้อมูลนี้มันไม่สดใหม่แล้วนะ ลบออกไปซะ!

1. Time-to-Live (TTL)

นี่คือวิธีที่ง่ายที่สุดที่เราเห็นในตัวอย่างด้านบน (EX: 60) คือการกำหนดเวลาหมดอายุให้ข้อมูลใน Cache เมื่อครบกำหนด Redis จะลบข้อมูลนั้นทิ้งไปเอง ทำให้ครั้งต่อไประบบจะไปดึงข้อมูลใหม่จากฐานข้อมูลมาเก็บไว้แทน

เหมาะสำหรับ: ข้อมูลที่ไม่จำเป็นต้องเป็น Real-time 100% และมีการเปลี่ยนแปลงไม่บ่อยนัก

2. Manual Invalidation (Delete-on-Update)

วิธีนี้คือการที่เราจะ ลบ Cache ออกทันที เมื่อข้อมูลที่เกี่ยวข้องมีการเปลี่ยนแปลงในฐานข้อมูล

Use Case: สมมติว่ามี API สำหรับอัปเดตข้อมูลสินค้า เมื่อมีผู้ดูแลระบบแก้ไขราคาสินค้า เราต้องการให้ข้อมูลใหม่ปรากฏทันที

API Route (Update Product & Invalidate Cache)

// ... (code for Redis client and DB connection) ...
 
app.put('/api/products/:id', async (req, res) => {
  const productId = req.params.id;
  const { newPrice } = req.body;
  const cacheKey = 'popular_products'; // Cache ที่เราเคยสร้างไว้
 
  try {
    // 1. อัปเดตข้อมูลในฐานข้อมูลก่อน
    await db.updateProductPrice(productId, newPrice);
    console.log(`Product ${productId} updated in DB.`);
 
    // 2. ลบ Cache ที่เกี่ยวข้องออก
    await client.del(cacheKey); // ลบ Cache ของ popular products
    console.log('Cache for popular products invalidated!');
 
    res.status(200).send('Product updated and cache invalidated successfully.');
 
  } catch (error) {
    console.error('Error:', error);
    res.status(500).send('Internal Server Error');
  }
});

เมื่อใดที่มีการอัปเดตข้อมูลสินค้า สินค้าใน Cache popular_products ก็จะถูกลบออกไป ทำให้ Request ถัดไป ระบบจะไปดึงข้อมูลใหม่จากฐานข้อมูล และสร้าง Cache ใหม่ขึ้นมาทันที

Redis ยังทำอะไรได้อีก? (ตัวอย่าง Queue เบื้องต้น)

นอกจาก Caching แล้ว Redis ยังเก่งเรื่องอื่น ๆ อีกเยอะเลยครับ หนึ่งในนั้นคือการทำ Message Queue หรือระบบคิวงานเบื้องหลัง

ปัญหา: บางงานใช้เวลานาน เช่น ประมวลผลรูปภาพ, ส่งอีเมลหาผู้ใช้หลายพันคน, หรือสร้างรายงาน ถ้าเราให้ผู้ใช้รอจนกว่างานเหล่านี้จะเสร็จ ก็คงไม่ดีแน่!

Redis Queue เข้ามาช่วย: เราสามารถใช้ Redis ในรูปแบบของ List (โครงสร้างข้อมูลของ Redis) เพื่อเป็นคิวงานได้:

  • Producer: เมื่อมีงานที่ต้องทำเบื้องหลัง (เช่น ผู้ใช้กดปุ่ม "สร้างรายงาน") แอปของเราจะใช้คำสั่ง LPUSH เพื่อ "โยน" ข้อมูลงานนั้น ๆ เข้าไปใน Redis List (คิว)
  • Consumer/Worker: มีโปรแกรมเล็ก ๆ (Worker) อีกตัว ที่คอย BRPOP (Blocking Right Pop) ดึงงานออกจากคิวไปประมวลผลเบื้องหลัง โดยที่ผู้ใช้ไม่ต้องรอ

Redis Queue (Concept)

// Producer (ใน API ของเรา)
app.post('/api/report', async (req, res) => {
  const userId = req.body.userId;
  // โยนงานสร้างรายงานเข้าคิว
  await client.LPUSH('report_queue', JSON.stringify({ type: 'generate_report', userId: userId }));
  res.status(202).send('Generating report in background...');
});
 
// Consumer / Worker (อีกโปรแกรมหนึ่ง)
async function processQueue() {
  while (true) {
    // ดึงงานออกจากคิวแบบ Blocking (รอจนกว่าจะมีงาน)
    const [listName, jobData] = await client.BRPOP('report_queue', 0); // 0 คือรอตลอดไป
    const job = JSON.parse(jobData);
    console.log(`Processing job: ${job.type} for user ${job.userId}`);
    // ... ทำงานที่ใช้เวลานานตรงนี้ ...
    console.log(`Job for user ${job.userId} completed.`);
  }
}
processQueue();

วิธีนี้ช่วยให้ระบบของเราตอบสนองผู้ใช้ได้เร็วขึ้น เพราะงานหนัก ๆ ถูกส่งไปทำเบื้องหลัง ทำให้แอปของเราลื่นไหลและมีประสิทธิภาพมากขึ้นครับ!

สรุป

Redis เป็นเครื่องมือที่ยอดเยี่ยมและหลากหลายความสามารถมาก ๆ ครับ โดยเฉพาะในบทบาทของ Caching ที่ช่วยลดภาระของฐานข้อมูลและเพิ่มความเร็วในการตอบสนองของแอปพลิเคชันได้อย่างมหาศาล

การทำความเข้าใจเรื่อง TTL และ Cache Invalidation เป็นสิ่งสำคัญที่จะช่วยให้ Cache ของเรามีประโยชน์สูงสุดและไม่สร้างปัญหาเรื่องข้อมูลเก่าให้กับผู้ใช้ครับ และการใช้ Redis เป็น Message Queue ก็เปิดโลกให้เราสร้างระบบที่ยืดหยุ่นและรองรับงานหนักได้ดียิ่งขึ้นไปอีก

หวังว่าบทความนี้จะทำให้ทุกคนมองเห็นพลังของ Redis และอยากลองนำไปใช้ในโปรเจกต์ของตัวเองกันดูนะครับ! รับรองว่าไม่ผิดหวังแน่นอน!

Tags
Redis
Caching
Performance
Back-end
Database
Queue

Related Blogs

knot-dev.tech

September 28, 2025