- การใช้งาน In-Memory Database: จากพื้นฐานสู่ Redis สำหรับ Web Application
- 1. In-Memory Database คืออะไร?
- 2. In-Memory Database ใช้ทำอะไร?
- 3. Redis คืออะไร?
- 4. ติดตั้ง Redis ด้วย Docker Compose
- 5. ทดลองใช้งาน Redis CLI
- 6. การใช้งาน String
- 7. การกำหนด TTL
- 8. การใช้งาน Hash
- 9. การใช้งาน List
- 10. การใช้งาน Set
- 11. การสร้าง Leaderboard ด้วย Sorted Set
- 12. Cache-Aside Pattern
- 13. Cache Invalidation
- 14. Redis สำหรับ Session Store
- 15. Redis สำหรับ Rate Limiting
- 16. Persistence
- 17. Redis กับ PostgreSQL/MySQL
- 18. ตัวอย่าง Flow ของระบบจริง
- 19. ข้อควรระวัง
- 20. Workshop ที่แนะนำ
- สรุป
#การใช้งาน In-Memory Database: จากพื้นฐานสู่ Redis สำหรับ Web Application
ในการพัฒนา Web Application หรือ API ที่มีผู้ใช้งานจำนวนมาก ปัญหาที่พบบ่อยคือ การเข้าถึงฐานข้อมูลซ้ำ ๆ จนทำให้ response time เพิ่มขึ้นและฐานข้อมูลหลักรับภาระมากเกินไป
หนึ่งในเทคนิคสำคัญที่ใช้แก้ปัญหานี้คือ In-Memory Database ซึ่งเก็บข้อมูลหลักไว้ในหน่วยความจำ RAM ทำให้สามารถอ่านและเขียนข้อมูลได้รวดเร็ว เหมาะกับงานประเภท Cache, Session, Rate Limiting, Counter และข้อมูลชั่วคราว
บทความนี้จะอธิบายแนวคิด In-Memory Database พร้อมทดลองใช้งาน Redis ตั้งแต่การติดตั้งด้วย Docker Compose ไปจนถึงการนำไปใช้กับ Web Application
#1. In-Memory Database คืออะไร?
In-Memory Database (IMDB) คือระบบฐานข้อมูลที่ออกแบบให้เก็บและประมวลผลข้อมูลหลักใน RAM แทนการเข้าถึง Disk หรือ SSD เป็นหลัก
แนวคิดทั่วไปสามารถเปรียบเทียบได้ดังนี้
Traditional Database
Application
|
v
Database
|
v
Disk / SSD
ส่วน In-Memory Database จะมีลักษณะ
Application
|
v
In-Memory Database
|
v
RAM
เนื่องจากการเข้าถึง RAM มี latency ต่ำ การอ่านข้อมูลจึงเหมาะกับ workload ที่ต้องตอบสนองรวดเร็ว
ตัวอย่างระบบที่นิยม ได้แก่
- Redis
- Valkey
- Memcached
- Apache Ignite
- Hazelcast
ในบทความนี้จะใช้ Redis เป็นตัวอย่างหลัก เพราะใช้งานง่ายและรองรับ data structures หลายประเภท
#2. In-Memory Database ใช้ทำอะไร?
กรณีใช้งานที่พบบ่อย ได้แก่
#2.1 Caching
เก็บข้อมูลที่ถูกเรียกใช้บ่อยเพื่อลดการ query ฐานข้อมูลหลัก
Client
|
v
REST API
|
v
Redis Cache
|
+-- Cache Hit --> Response
|
+-- Cache Miss
|
v
PostgreSQL/MySQL
#2.2 Session Store
เก็บ session ของผู้ใช้ไว้ในส่วนกลาง เพื่อให้ application หลาย instance ใช้งาน session เดียวกันได้
#2.3 Rate Limiting
นับจำนวน request ในช่วงเวลาหนึ่ง เช่น จำกัดผู้ใช้ไว้ที่ 100 requests ต่อนาที
#2.4 Temporary Data
เช่น
- OTP
- Verification token
- Password reset token
- Temporary authentication state
ข้อมูลเหล่านี้สามารถกำหนด TTL เพื่อให้หมดอายุอัตโนมัติ
#2.5 Counter และ Leaderboard
Redis มีคำสั่ง atomic และ Sorted Set ซึ่งเหมาะกับจำนวนยอดเข้าชม คะแนน หรืออันดับแบบ real-time
#3. Redis คืออะไร?
Redis เป็นระบบจัดเก็บข้อมูลแบบ in-memory key-value/data-structure store
Redis ไม่ได้รองรับเพียง String แต่มีโครงสร้างข้อมูลหลายประเภท เช่น
String
Hash
List
Set
Sorted Set
Stream
Bitmap
HyperLogLog
Geospatial
ตัวอย่างข้อมูลแบบ Key-Value
username -> alice
ใน Redis CLI สามารถเขียนได้ดังนี้
SET username "alice"
และอ่านข้อมูลด้วย
GET username
#4. ติดตั้ง Redis ด้วย Docker Compose
สร้าง directory สำหรับทดลอง
mkdir redis-demo
cd redis-demo
สร้างไฟล์
compose.yaml
กำหนด configuration ดังนี้
services:
redis:
image: redis:8-alpine
container_name: redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
volumes:
redis-data:
จากนั้นรัน
docker compose up -d
ตรวจสอบ container
docker compose ps
หากต้องการดู log
docker compose logs redis
#5. ทดลองใช้งาน Redis CLI
เข้าสู่ Redis CLI ภายใน container
docker exec -it redis redis-cli
ทดสอบการเชื่อมต่อ
PING
ควรได้
PONG
#6. การใช้งาน String
บันทึกข้อมูล
SET username "alice"
อ่านข้อมูล
GET username
ผลลัพธ์
"alice"
ตรวจสอบว่ามี key หรือไม่
EXISTS username
ลบข้อมูล
DEL username
#7. การกำหนด TTL
หนึ่งในความสามารถสำคัญของ Redis คือกำหนดอายุข้อมูลได้
ตัวอย่าง OTP อายุ 60 วินาที
SET otp:1001 "583921" EX 60
ตรวจสอบเวลาที่เหลือ
TTL otp:1001
เมื่อครบ 60 วินาที Redis จะลบ key นี้โดยอัตโนมัติ
TTL เหมาะกับ
OTP
Session
Cache
Reset Token
Verification Token
Rate Limit Counter
#8. การใช้งาน Hash
Hash เหมาะสำหรับเก็บ object ขนาดเล็ก
HSET user:1001 name "Alice" email "alice@example.com" role "admin"
อ่าน field
HGET user:1001 name
อ่านทั้งหมด
HGETALL user:1001
โครงสร้างเชิงแนวคิดคือ
user:1001
|
+-- name = Alice
+-- email = alice@example.com
+-- role = admin
#9. การใช้งาน List
เพิ่มข้อมูล
LPUSH notifications "New order"
LPUSH notifications "Payment received"
อ่านรายการ
LRANGE notifications 0 -1
List สามารถใช้กับงานประเภท queue แบบง่ายได้ แต่หากเป็นระบบ messaging ที่ซับซ้อนควรพิจารณา Redis Streams หรือ message broker ที่ออกแบบมาสำหรับ workload นั้นโดยตรง
#10. การใช้งาน Set
Set เก็บสมาชิกที่ไม่ซ้ำกัน
SADD online_users 1001
SADD online_users 1002
SADD online_users 1003
ดูสมาชิก
SMEMBERS online_users
ตรวจสอบสมาชิก
SISMEMBER online_users 1001
เหมาะกับข้อมูล เช่น
- Online users
- Unique tags
- User permissions
- Unique visitors
#11. การสร้าง Leaderboard ด้วย Sorted Set
เพิ่มคะแนน
ZADD leaderboard 950 alice
ZADD leaderboard 1200 bob
ZADD leaderboard 870 john
แสดงอันดับจากคะแนนสูงไปต่ำ
ZREVRANGE leaderboard 0 9 WITHSCORES
เหมาะกับระบบ
Game Ranking
Student Score
Sales Ranking
Top Products
Most Active Users
#12. Cache-Aside Pattern
รูปแบบที่นิยมใช้ Redis ร่วมกับ PostgreSQL หรือ MySQL คือ Cache-Aside
Client
|
v
Application
|
v
Check Redis
|
+----------+
| |
Cache Hit Cache Miss
| |
v v
Response Database
|
v
Save Cache
|
v
Response
ขั้นตอนคือ
- Application ตรวจสอบข้อมูลใน Redis
- หากพบข้อมูล เรียกว่า Cache Hit
- ส่งข้อมูลจาก Redis กลับทันที
- หากไม่พบ เรียกว่า Cache Miss
- Query ข้อมูลจากฐานข้อมูลหลัก
- บันทึกผลลัพธ์ลง Redis
- กำหนด TTL
- ส่งข้อมูลกลับ Client
Pseudo-code:
def get_product(product_id):
key = f"product:{product_id}"
product = redis.get(key)
if product:
return deserialize(product)
product = database.find_product(product_id)
redis.setex(
key,
300,
serialize(product)
)
return product
ตัวอย่างนี้กำหนด cache ไว้ 300 วินาที หรือ 5 นาที
#13. Cache Invalidation
ปัญหาสำคัญของ Cache คือข้อมูลใน Cache อาจไม่ตรงกับฐานข้อมูลหลัก
สมมติ
Redis
product:1001 = price 500
แต่มีการแก้ไขฐานข้อมูลเป็น
Database
product:1001 = price 450
ถ้าไม่จัดการ cache ผู้ใช้ยังอาจได้รับราคา 500
วิธีหนึ่งคือเมื่อ update database สำเร็จ ให้ลบ cache เดิม
UPDATE Database
|
v
DELETE Cache
เช่น
DEL product:1001
request ครั้งถัดไปจะเกิด Cache Miss และ application จะโหลดข้อมูลใหม่จากฐานข้อมูล
#14. Redis สำหรับ Session Store
หากมี API หลาย instance
Load Balancer
|
+------------+------------+
| | |
v v v
API 1 API 2 API 3
| | |
+------------+------------+
|
v
Redis
|
Sessions
สามารถกำหนด key เช่น
session:abc123
และกำหนด TTL
SET session:abc123 '{"user_id":1001}' EX 3600
ทำให้ session หมดอายุหลัง 1 ชั่วโมง
#15. Redis สำหรับ Rate Limiting
ตัวอย่างแบบง่าย:
INCR rate:user:1001
EXPIRE rate:user:1001 60
Application สามารถตรวจสอบจำนวน request
Request
|
v
Redis Counter
|
+-- <= 100 --> Allow
|
+-- > 100 --> HTTP 429
อย่างไรก็ตาม production system ควรออกแบบ algorithm และการกำหนด expiry แบบ atomic ให้ถูกต้อง โดยอาจใช้ Lua script หรือ transaction ตามความเหมาะสม
algorithm ที่พบได้บ่อย ได้แก่
- Fixed Window
- Sliding Window
- Token Bucket
- Leaky Bucket
#16. Persistence
คำว่า In-Memory ไม่ได้หมายความว่าข้อมูลจำเป็นต้องหายทั้งหมดเมื่อ restart
Redis มี persistence mechanisms เช่น
#RDB
สร้าง snapshot ของข้อมูลตามช่วงเวลา
RAM
|
v
Snapshot
|
v
dump.rdb
#AOF
บันทึก operation ที่เปลี่ยนแปลงข้อมูลลง append-only log
SET user:1 Alice
INCR counter
DEL cache:100
ตัวอย่าง Docker Compose ก่อนหน้านี้เปิด AOF ด้วย
command: redis-server --appendonly yes
การเลือกระดับ durability ต้องพิจารณาตาม workload และข้อกำหนดการกู้คืนข้อมูล
#17. Redis กับ PostgreSQL/MySQL
โดยทั่วไปไม่จำเป็นต้องเลือกระหว่าง Redis กับ relational database เพราะทั้งสองระบบมีหน้าที่ต่างกัน
คุณสมบัติ Redis PostgreSQL/MySQL
Storage หลัก RAM Disk/SSD Latency ต่ำมาก สูงกว่าโดยทั่วไป Cache เหมาะมาก ไม่ใช่หน้าที่หลัก Session เหมาะ ทำได้ SQL ไม่ใช่ SQL DB รองรับ JOIN ไม่ใช่จุดประสงค์หลัก รองรับ Transaction เชิง relational จำกัดกว่า เหมาะ Temporary Data เหมาะมาก ทำได้ Source of Truth ขึ้นกับการออกแบบ มักใช้เป็นฐานข้อมูลหลัก
architecture ที่พบบ่อยจึงเป็น
Frontend
React / Next.js
|
v
Backend API
|
+----+----------------+
| |
v v
Redis PostgreSQL
Cache Primary DB
#18. ตัวอย่าง Flow ของระบบจริง
สมมติผู้ใช้เรียก
GET /api/products/1001
ระบบตรวจ
product:1001
ใน Redis
#กรณี Cache Hit
Client
|
v
API
|
v
Redis
|
v
Response
ไม่จำเป็นต้อง query database
#กรณี Cache Miss
Client
|
v
API
|
v
Redis
|
MISS
|
v
PostgreSQL
|
v
Redis SET + TTL
|
v
Response
เมื่อ request ครั้งถัดไปเข้ามา ระบบสามารถอ่านข้อมูลจาก Redis ได้
#19. ข้อควรระวัง
การเพิ่ม Redis ไม่ได้ทำให้ระบบเร็วขึ้นโดยอัตโนมัติ จำเป็นต้องออกแบบให้เหมาะสม โดยเฉพาะเรื่องต่อไปนี้
#Cache Invalidation
ต้องกำหนดว่า cache จะถูกลบหรือ refresh เมื่อข้อมูลต้นทางเปลี่ยนเมื่อใด
#TTL
TTL สั้นเกินไปอาจทำให้ Cache Miss บ่อย ส่วน TTL ยาวเกินไปอาจทำให้ข้อมูลเก่า
#Memory
RAM มีต้นทุนสูงกว่า disk จึงควรกำหนด memory limit และ eviction policy ให้เหมาะสม
#Cache Stampede
เมื่อ cache สำคัญหมดอายุพร้อมกัน request จำนวนมากอาจวิ่งไปยัง database พร้อมกัน
#Security
Redis ที่ใช้งาน production ไม่ควรถูกเปิด port ให้ Internet เข้าถึงโดยตรง ควรใช้ private network, authentication/ACL และ TLS ตาม architecture
#High Availability
ระบบที่ใช้ Redis เป็น critical component ควรพิจารณา replication, failover, backup และ managed service ตามระดับ availability ที่ต้องการ
#20. Workshop ที่แนะนำ
สำหรับการเรียนหรือการอบรม สามารถทดลองตามลำดับนี้
1. Docker Compose
|
v
2. Redis CLI
|
v
3. String / Hash / List / Set
|
v
4. TTL
|
v
5. REST API + Redis
|
v
6. Cache-Aside
|
v
7. PostgreSQL + Redis
|
v
8. Session Store
|
v
9. Rate Limiting
|
v
10. Cache Invalidation
เมื่อเข้าใจ workflow นี้แล้วสามารถต่อยอดไปยัง Spring Boot, Laravel, Express/Node.js, ASP.NET Core, FastAPI หรือ Go ได้
#สรุป
In-Memory Database เป็นองค์ประกอบสำคัญของระบบสมัยใหม่ที่ต้องการ latency ต่ำและรองรับ request จำนวนมาก โดย Redis เป็นหนึ่งในเครื่องมือที่เหมาะสำหรับเริ่มต้นเรียนรู้แนวคิดนี้
หัวใจสำคัญไม่ได้อยู่ที่การนำ Redis มาแทนฐานข้อมูลหลัก แต่คือการเลือกใช้ให้เหมาะกับประเภทข้อมูล เช่น
- PostgreSQL/MySQL เป็นแหล่งข้อมูลหลัก
- Redis ใช้ Cache ข้อมูลที่ถูกอ่านบ่อย
- ใช้ TTL กับข้อมูลชั่วคราว
- ใช้ Redis เป็น Session Store
- ใช้ atomic counters สำหรับ Rate Limiting
- ใช้ Sorted Set สำหรับ Leaderboard
architecture ที่ใช้บ่อยจึงเป็น
Client
|
v
Web / Mobile
|
v
REST API
|
+-------- Redis
| |
| Cache
|
+-------- PostgreSQL/MySQL
|
Source of Truth
การเพิ่ม In-Memory Database อย่างถูกวิธีช่วยลดภาระฐานข้อมูลหลัก เพิ่ม throughput และลด response time ของระบบได้ แต่ควรออกแบบ TTL, invalidation, persistence, memory policy, security และ high availability ตั้งแต่ต้นเพื่อให้เหมาะกับ production workload