Redis ใช้เป็น Cache, Session และ Queue ต่างกันยังไง
Redis เป็นเครื่องมือที่หลายทีมเริ่มใช้เร็วมาก เพราะมันเร็ว ตรงไปตรงมา และหยิบไปเสียบกับงานหลายแบบได้ทันที แต่จุดที่ทำให้หลายระบบเริ่มสับสนก็คือ Redis ทำได้หลายอย่างเกินไป
บางทีมใช้ Redis เป็น cache
บางทีมใช้เก็บ session
บางทีมใช้เป็น queue หรือ background job backend
บางทีมใช้ rate limiting, lock, pub/sub, dedup และอีกหลายอย่างรวมกัน
ปัญหาคือพอทุกอย่างใช้ Redis เหมือนกัน คนในทีมจะเริ่มพูดรวม ๆ ว่า “เก็บไว้ใน Redis” ทั้งที่จริงแล้วสิ่งที่กำลังทำอยู่คนละแบบและมี trade-off คนละเรื่อง
การใช้ Redis เป็น cache ไม่เหมือนการใช้เป็น session store
การใช้เป็น session store ก็ไม่เหมือนการใช้เป็น queue
และถ้าคิดว่ามันเป็นแค่ key-value store เหมือนกันไปหมด วันหนึ่งระบบจะเริ่มพังตรงขอบเขตที่ไม่ชัด
บทความนี้อธิบายว่า Redis เมื่อใช้เป็น cache, session และ queue ต่างกันอย่างไร แต่ละแบบกำลังแก้ปัญหาอะไร และควรระวังอะไรใน production
TL;DR
สรุปให้สั้นที่สุด
Cache ใช้ลดการคำนวณหรือการอ่านซ้ำ
Session ใช้เก็บ state ชั่วคราวของผู้ใช้หรือ connection context
Queue ใช้แยกงานที่ไม่ควรรันใน request ตรง ๆ ออกไปทำภายหลัง
ทั้งสามอย่างอาจใช้ Redis เหมือนกัน แต่เป้าหมาย อายุข้อมูล และความคาดหวังเรื่องความทนทานไม่เหมือนกันเลย
ทำไมคนถึงชอบใช้ Redis กับหลายงาน
จุดแข็งของ Redis คือมันเร็ว ใช้ใน memory เป็นหลัก มี data structures ที่หลากหลาย และมี library รองรับเยอะมาก ทำให้มันกลายเป็นเครื่องมือสารพัดประโยชน์ของระบบ backend
ในงานจริง Redis มักถูกเลือกเพราะ
- latency ต่ำ
- อ่านเขียนง่าย
- ตั้ง TTL ได้ง่าย
- ใช้เป็น shared state ระหว่างหลาย instance ได้
- เหมาะกับข้อมูลชั่วคราวหรือข้อมูลที่เปลี่ยนเร็ว
- มี ecosystem รองรับงาน queue, rate limiting, distributed lock และ pub/sub
แต่ข้อดีนี้เองก็ทำให้หลายทีมใช้มันแบบ “อะไรก็ใส่ Redis ไปก่อน” ซึ่งนำไปสู่ปัญหาว่า data แต่ละชนิดมีความสำคัญไม่เท่ากัน แต่กลับถูกวางบนระบบเดียวกันโดยไม่แยก policy ให้ชัด
Redis แบบ Cache คืออะไร
การใช้ Redis เป็น cache คือการเก็บผลลัพธ์ของข้อมูลหรือการคำนวณที่แพงไว้ชั่วคราว เพื่อไม่ต้องไปดึงจากต้นทางหรือประมวลผลใหม่ทุกครั้ง
ตัวอย่างที่เจอบ่อย เช่น
- cache ผล query ที่อ่านบ่อย
- cache product details
- cache permissions หรือ config ที่โหลดซ้ำ
- cache rendered fragments
- cache expensive report summary
- cache external API response ชั่วคราว
แก่นของ cache คือ “ถ้าหายไป ระบบยังควรไปต่อได้” เพียงแต่อาจช้าลงหรือแพงขึ้นชั่วคราว
นี่คือจุดสำคัญมาก เพราะมันแปลว่า cache ไม่ควรเป็น single source of truth ของข้อมูลธุรกิจ
Cache กำลังแก้ปัญหาอะไร
cache ช่วยลดปัญหาหลัก ๆ แบบนี้
อย่างแรกคือ ลดการอ่านซ้ำจาก database หรือ service ปลายทาง
อย่างที่สองคือ ลด latency ของ endpoint ที่อ่านข้อมูลซ้ำบ่อย
อย่างที่สามคือ ลด cost ของ computation หรือ external API calls
อย่างที่สี่คือ ช่วยรับมือ burst traffic ที่อ่านข้อมูลชุดเดิมซ้ำ ๆ
ถ้า endpoint หนึ่งมี pattern ว่าอ่านข้อมูลเดิมเยอะมาก แต่ข้อมูลเปลี่ยนไม่ถี่ cache มักคุ้มมาก
สิ่งที่ต้องระวังเวลาใช้ Redis เป็น Cache
ปัญหาที่เจอบ่อยไม่ใช่แค่เรื่องเทคนิค แต่คือการลืมถามว่า data นี้ stale ได้แค่ไหน
ถ้าคุณ cache ข้อมูลไว้ 5 นาที แล้วธุรกิจยอมรับได้ ระบบก็จะง่าย
แต่ถ้าข้อมูลนี้เปลี่ยนแล้วห้าม stale แม้แต่วินาทีเดียว คุณอาจกำลังใช้ cache ผิดที่
จุดที่ต้องระวังมีพวกนี้
- cache invalidation
- TTL ที่สั้นหรือยาวเกินไป
- cache stampede
- key naming ที่ไม่มีระบบ
- เผลอพึ่ง cache จนต้นทางพังแล้วระบบไปต่อไม่ได้
- เก็บข้อมูลสำคัญเกินไปใน cache โดยไม่ตั้งใจ
พูดง่าย ๆ คือ cache ช่วยเรื่อง performance แต่จะสร้าง complexity เรื่อง freshness ตามมาเสมอ
Redis แบบ Session Store คืออะไร
session store คือการใช้ Redis เก็บ state ชั่วคราวที่ผูกกับผู้ใช้หรือการใช้งานช่วงหนึ่ง เช่น
- user login session
- session data หลัง auth
- temporary cart state
- MFA challenge state
- flash state บางอย่าง
- server-side session metadata
แก่นของ session คือ “state นี้เป็นของ interaction หรือ identity ชั่วคราว” ไม่ใช่ data หลักของธุรกิจโดยตรง
ถ้าพูดให้เห็นภาพ
- cache ตอบว่า “ข้อมูลนี้เคยคำนวณไว้แล้ว เอากลับมาใช้ได้ไหม”
- session ตอบว่า “ผู้ใช้นี้กำลังอยู่ในสถานะอะไรระหว่างใช้งานระบบ”
Session กำลังแก้ปัญหาอะไร
session store มีประโยชน์มากเมื่อระบบไม่ได้อยากให้ทุก instance เก็บ state ผู้ใช้ไว้ใน memory ของตัวเอง เพราะพอระบบ scale เป็นหลาย instance ปัญหาจะเกิดทันที
เช่น
- request รอบแรกไป instance A
- request รอบถัดไปไป instance B
- ถ้า session อยู่แค่ memory ของ A, B จะไม่รู้จักผู้ใช้คนนั้น
Redis จึงถูกใช้เป็น shared session backend เพื่อให้ทุก instance อ่าน session ชุดเดียวกันได้
Session ต่างจาก Cache ยังไง
แม้ทั้งสองอย่างมักมี TTL เหมือนกัน แต่ความหมายต่างกันมาก
cache เป็น optimization
session เป็น interaction state
ถ้า cache หาย ผู้ใช้มักยังทำงานต่อได้ แค่ช้าลง
แต่ถ้า session หาย ผู้ใช้อาจโดน logout, MFA flow หาย, cart หาย หรือ state ระหว่างใช้งานสะดุด
ดังนั้นแม้ session จะไม่ใช่ข้อมูลถาวรระดับเดียวกับ database หลัก แต่มักถูกคาดหวังเรื่องความสม่ำเสมอและผลกระทบต่อ UX สูงกว่า cache
สิ่งที่ต้องระวังเวลาใช้ Redis เป็น Session Store
จุดที่เจอบ่อยคือทีมคิดว่า session เป็นแค่ key-value ธรรมดา แล้วไม่คิดเรื่องอายุและ security ให้พอ
สิ่งที่ควรระวัง เช่น
- session fixation
- TTL ไม่เหมาะสม
- session ไม่ถูก revoke ตอน logout หรือ reset password
- เก็บข้อมูลอ่อนไหวมากเกินไปใน session
- session size โตเกินจำเป็น
- ไม่มี policy ว่า refresh session อย่างไร
- ใช้ Redis เป็น session store แต่ไม่มี fallback หรือ monitoring พอ
ถ้า Redis มีปัญหา session-based systems จะเห็นผลกับผู้ใช้เร็วมากกว่างาน cache ทั่วไป
Redis แบบ Queue คืออะไร
เมื่อใช้ Redis เป็น queue เป้าหมายจะต่างจากสองแบบแรกชัดเจน เพราะสิ่งที่เก็บไม่ใช่ “ข้อมูลเอาไว้หยิบกลับมาอ่าน” อย่างเดียว แต่เป็น “งานที่รอถูกประมวลผล”
ตัวอย่างเช่น
- ส่งอีเมลภายหลัง
- generate report
- resize image
- sync ข้อมูลไปยัง third-party
- scan file upload
- process webhook events
- run OCR หรือ AI jobs
- execute batch actions
แก่นของ queue คือ “งานนี้ไม่ควรทำให้ request หลักรอนาน” หรือ “งานนี้ต้องถูกประมวลผลตาม flow ที่ควบคุมได้มากกว่า direct request-response”
Queue กำลังแก้ปัญหาอะไร
queue ช่วยในเรื่องพวกนี้โดยตรง
- แยกงานหนักออกจาก request หลัก
- ทำให้ user response เร็วขึ้น
- คุม retry ได้
- คุม concurrency ได้
- รองรับ burst ได้
- ทำ async workflow ได้ง่ายขึ้น
- แยก responsibility ระหว่าง API กับ worker
ถ้า endpoint หนึ่งต้องทำงานแพง เช่น export, OCR, email fan-out, image processing หรือ reconciliation การโยนไป queue มักเหมาะกว่าให้ request รอจนเสร็จ
Queue ต่างจาก Cache และ Session ยังไง
นี่คือจุดที่สำคัญที่สุดข้อหนึ่ง
cache และ session มักเน้น “เก็บ state เพื่ออ่านกลับ”
queue เน้น “เก็บงานเพื่อให้ถูกหยิบไปทำ”
ดังนั้นความคาดหวังของ queue จะไปอยู่ที่เรื่องพวกนี้แทน
- งานตกหล่นไหม
- retry ยังไง
- process ซ้ำได้ไหม
- worker crash แล้วงานหายหรือไม่
- ต้องการ ordering หรือไม่
- dead-letter handling มีไหม
- visibility timeout หรือ lock ตอนประมวลผลงานมีไหม
พอคิดแบบนี้จะเห็นเลยว่า queue ไม่ใช่แค่ list ใน Redis แบบลวก ๆ ถ้าใช้ใน production จริง
ตัวอย่างเปรียบเทียบให้เห็นภาพ
สมมติระบบมี endpoint อัปโหลดเอกสาร
ใช้ Redis เป็น Cache
อาจ cache metadata ของเอกสารที่อ่านบ่อย เช่น document summary หรือ owner info เพื่อไม่ต้อง query DB ซ้ำ
ใช้ Redis เป็น Session
อาจเก็บ temporary upload flow state ว่าผู้ใช้กำลังอัปโหลดเอกสารชุดไหน หรือ MFA ผ่านแล้วหรือยัง
ใช้ Redis เป็น Queue
อาจ enqueue งาน scan virus, OCR, thumbnail generation หรือ verification หลัง upload เสร็จ
ทั้งสามอย่างเกี่ยวกับ “เอกสาร” เหมือนกัน แต่กำลังแก้ปัญหาคนละชั้นของระบบ
ปัญหาที่เกิดเมื่อใช้ Redis ปนกันแบบไม่แยก boundary
ระบบจำนวนมากใช้ Redis กล่องเดียวทำทุกอย่าง ซึ่งไม่ผิดเสมอไป แต่ถ้าไม่แยก namespace, eviction policy, memory expectations และ monitoring ให้ดี ปัญหาจะมาเร็ว
ตัวอย่างเช่น
- cache พุ่งจนดัน session หลุด
- queue backlog โตจน memory กินพื้นที่ของ cache
- session สำคัญโดน eviction เพราะ cache keys เยอะเกิน
- worker ดึง Redis หนักจน latency ของ session reads แย่ลง
ดังนั้นแม้จะใช้ Redis ตัวเดียวกัน ก็ควรแยกความหมายและควบคุมมันให้ชัด เช่น
- key prefix
- TTL policy
- memory policy
- database index หรือ instance แยก
- monitoring แยกตาม use case
แล้วควรใช้ Redis เป็นอะไรดี
คำตอบไม่ใช่ “เลือกอย่างเดียว” แต่คือ “รู้ว่ากำลังใช้มันเป็นอะไรในแต่ละจุด”
ถ้าปัญหาของคุณคือ query ช้าเพราะอ่านข้อมูลเดิมซ้ำเยอะ ใช้ cache
ถ้าปัญหาคือหลาย instance ต้องแชร์ login state หรือ temporary user state ใช้ session store
ถ้าปัญหาคืองานไม่ควรทำใน request หรืออยากมี retry/concurrency control ใช้ queue
สิ่งที่ไม่ควรทำคือใช้ชื่อ Redis เหมารวมแล้วค่อยคิดทีหลังว่า data ชุดนี้สำคัญแค่ไหน
ตัวอย่าง Express/Node.js แบบเริ่มต้น
ตัวอย่างนี้สาธิตให้เห็นสามหน้าที่ของ Redis แบบแยกบริบทกัน ไม่ได้ลงลึก library production เต็มรูปแบบ แต่พอเห็นภาพว่า logic ต่างกันอย่างไร
const express = require("express");
const Redis = require("ioredis");
const app = express();
app.use(express.json());
const redis = new Redis();
/**
* 1) Cache example
*/
app.get("/products/:id", async (req, res) => {
const cacheKey = `cache:product:${req.params.id}`;
const cached = await redis.get(cacheKey);
if (cached) {
return res.status(200).json({
source: "cache",
product: JSON.parse(cached)
});
}
const product = await fetchProductFromDatabase(req.params.id);
await redis.set(cacheKey, JSON.stringify(product), "EX", 60);
return res.status(200).json({
source: "database",
product
});
});
/**
* 2) Session example
*/
app.post("/session/start", async (req, res) => {
const sessionId = `sess_${Date.now()}`;
const sessionKey = `session:${sessionId}`;
await redis.set(
sessionKey,
JSON.stringify({
userId: req.body.userId,
step: "authenticated"
}),
"EX",
3600
);
return res.status(201).json({
sessionId
});
});
/**
* 3) Queue example
*/
app.post("/jobs/report", async (req, res) => {
const job = {
type: "generate_report",
reportId: req.body.reportId,
requestedAt: new Date().toISOString()
};
await redis.lpush("queue:reports", JSON.stringify(job));
return res.status(202).json({
accepted: true
});
});
async function fetchProductFromDatabase(productId) {
return {
id: productId,
name: "Demo Product",
price: 1200
};
}
app.listen(3000, () => {
console.log("Server listening on port 3000");
});
โค้ดชุดนี้กำลังสื่ออะไร
ประเด็นสำคัญของตัวอย่างนี้ไม่ใช่ syntax แต่คือความหมายของข้อมูลที่เก็บ
cache:product:123 คือข้อมูลที่เอาไว้ลดการอ่านซ้ำsession:sess_... คือ state ชั่วคราวของผู้ใช้queue:reports คือรายการงานที่รอ worker หยิบไปทำ
ถ้ามองสามอย่างนี้เป็นแค่ “string ใน Redis เหมือนกัน” คุณจะเริ่มพลาดเรื่อง TTL, durability, monitoring และ eviction ได้ง่ายมาก
จุดที่ต้องระวังใน production
1) อย่าคิดว่า Redis เร็วแล้วแปลว่าใช้ได้กับทุกอย่าง
Redis ช่วยเรื่อง latency ได้มาก แต่ไม่ได้ลบ requirement เรื่อง data semantics ออกไป
2) อย่าใช้ cache เป็น source of truth
ถ้า cache หายแล้วธุรกิจหยุด แปลว่าคุณอาจเอาความรับผิดชอบผิดไปวางไว้บน cache
3) อย่าดูเบาเรื่อง session integrity
session มีผลกับ auth flow และ UX โดยตรง ถ้า eviction หรือ TTL ผิด ผู้ใช้จะเจออาการเพี้ยนเร็วมาก
4) อย่าใช้ queue แบบไม่มี retry และ failure policy
งาน async ที่ fail แล้วหายหรือค้างเงียบ ๆ จะสร้าง operational debt หนักมาก
5) อย่าปล่อย namespace ปนกันมั่ว
ตั้งชื่อ key ให้ชัด เช่น
cache:*session:*queue:*lock:*rate_limit:*
เรื่องนี้ช่วยทั้ง debugging และการแยก policy
Redis Queue ในโลกจริงควรระวังอะไรเพิ่ม
ถ้าคุณใช้ Redis เป็น queue จริงจัง มักต้องคิดเกินกว่า LPUSH กับ BRPOP
เช่น
- at-least-once delivery
- idempotent workers
- retry count
- dead-letter queue
- job timeout
- visibility/claiming model
- concurrency per job type
- monitoring queue depth
- stuck job detection
ดังนั้นสำหรับ production หลายทีมจึงมักใช้ library หรือ framework ที่ห่อ Redis queue semantics มาให้ เช่น BullMQ หรือเครื่องมือที่คล้ายกัน แทนการเขียนดิบทั้งหมดเอง
Cache, Session, Queue กับ durability expectations
อีกมุมที่ช่วยตัดสินใจได้ดีคือถามว่า “ถ้าข้อมูลนี้หาย จะเกิดอะไรขึ้น”
ถ้า cache หาย ระบบควรช้าลงแต่ยังทำงานต่อได้
ถ้า session หาย ผู้ใช้อาจต้อง login ใหม่หรือ flow ระหว่างทางหาย
ถ้า queue job หาย งานอาจไม่ถูกทำเลย และนั่นอาจกระทบธุรกิจโดยตรง
คำถามนี้ช่วยให้คุณรู้ว่าข้อมูลชนิดไหนควรแบกความทนทานระดับใด และช่วยตัดสินว่าควรใช้ Redis เดิม, Redis แยก, หรือเครื่องมืออื่นแทนหรือไม่
รีวิวแนวทางนี้แบบ production-minded
Correctness
การแยกความหมายของ cache, session และ queue ให้ชัด ช่วยลดการออกแบบผิดชั้น เช่นเอา session ไปตั้ง eviction policy แบบ cache หรือเอา queue ไปปฏิบัติเหมือน key-value data ธรรมดา
Security
session เกี่ยวข้องกับ identity และ auth มากที่สุด จึงต้องระวัง access control, TTL, revoke flow และข้อมูลอ่อนไหว ส่วน cache และ queue ก็ต้องระวังไม่ให้เผลอเก็บข้อมูลสำคัญเกินจำเป็น
Efficiency
cache ให้ประโยชน์ด้าน performance ชัด
queue ให้ประโยชน์ด้าน latency และ work distribution
session ให้ประโยชน์ด้าน shared state across instances
แต่ประโยชน์เหล่านี้จะคุ้มก็ต่อเมื่อแยก use case ให้ถูก ไม่ใช้ Redis แบบถังรวมทุกอย่าง
Error handling
queue ต้องมี retry และ observability
cache ต้องมี fallback เมื่อตก miss
session ต้องมี behavior ที่คาดเดาได้เมื่อหมดอายุหรืออ่านไม่ได้
Checklist สั้น ๆ ก่อนใช้ Redis ใน production
- ตอบให้ได้ว่าข้อมูลนี้เป็น cache, session หรือ queue
- รู้ว่าถ้าข้อมูลหาย ผลกระทบคืออะไร
- ตั้ง TTL ให้เหมาะกับ semantics ของข้อมูล
- แยก key namespace ชัดเจน
- มี monitoring แยกตาม use case
- ไม่ใช้ cache เป็น source of truth
- session มี revoke และ expiry policy ชัด
- queue มี retry, timeout และ failure handling
- worker jobs ออกแบบให้ idempotent เมื่อจำเป็น
- memory policy และ eviction behavior ถูกประเมินแล้ว
บทความที่ควรอ่านต่อ
- Background Jobs ด้วย Node.js และ Redis ควรออกแบบยังไงให้ retry ได้จริง
- Redis Distributed Lock ใน Node.js จำเป็นตอนไหน และระวังอะไร
- Rate Limiting คืออะไร และควรวางไว้ตรงไหนของระบบ
สรุป
Redis เป็นเครื่องมือที่ยืดหยุ่นมาก แต่ยิ่งยืดหยุ่นมาก เราก็ยิ่งต้องรู้ว่ากำลังใช้มันเพื่ออะไร
cache, session และ queue อาจอยู่บน Redis เหมือนกัน แต่กำลังแก้ปัญหาคนละแบบ และมีความคาดหวังเรื่อง freshness, durability, retry และผลกระทบต่อผู้ใช้ต่างกันมาก
สรุปสั้นที่สุดคือ
ใช้ Redis เป็น cache เมื่ออยากลดการอ่านซ้ำ
ใช้เป็น session เมื่ออยากแชร์ state ของผู้ใช้
ใช้เป็น queue เมื่อต้องการแยกงานออกจาก request แล้วควบคุมการประมวลผลให้ดีขึ้น