#การใช้งาน 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

ขั้นตอนคือ

  1. Application ตรวจสอบข้อมูลใน Redis
  2. หากพบข้อมูล เรียกว่า Cache Hit
  3. ส่งข้อมูลจาก Redis กลับทันที
  4. หากไม่พบ เรียกว่า Cache Miss
  5. Query ข้อมูลจากฐานข้อมูลหลัก
  6. บันทึกผลลัพธ์ลง Redis
  7. กำหนด TTL
  8. ส่งข้อมูลกลับ 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