ข้ามไปยังเนื้อหา

Session Store

Application server ทำงานแบบ stateless ดังนั้นเซสชันต้องถูกจัดเก็บไว้ที่ใดที่หนึ่งภายนอก Redis เหมาะสมอย่างมาก เพราะทำงานได้รวดเร็ว รองรับ expiration ของ key โดยธรรมชาติ และ hash type ของ Redis สอดรับกับ session object ที่มีหลายฟิลด์ได้เป็นอย่างดี

เซสชันแต่ละอันถูกจัดเก็บที่ key ชื่อ session:<id> ฟิลด์ต่างๆ เช่น userId, email และ role จะถูกแมปตรงไปยัง hash fields คำสั่ง EXPIRE กำหนด idle timeout และการรีเซ็ต expiry ในทุกคำขอที่ผ่านการยืนยันตัวตนจะสร้าง sliding TTL

127.0.0.1:6379> HSET session:abc123 userId 42 email "[email protected]" role "admin"
(integer) 3
127.0.0.1:6379> EXPIRE session:abc123 1800
(integer) 1
127.0.0.1:6379> HGETALL session:abc123
1) "userId"
2) "42"
3) "email"
5) "role"
6) "admin"
127.0.0.1:6379> HGET session:abc123 role
"admin"
127.0.0.1:6379> EXPIRE session:abc123 1800
(integer) 1
127.0.0.1:6379> TTL session:abc123
(integer) 1799

HSET ที่ระบุ field-value หลายคู่จะสร้างเซสชันใน round trip เดียว HGETALL คืนทุก field และ HGET ดึงเฉพาะ field ที่ต้องการ การเรียก EXPIRE อีกครั้งจะรีเซ็ตการนับถอยหลัง ที่เป็นการสร้าง sliding idle timeout

HSET session:abc123 userId 42 email "[email protected]" role "admin"
EXPIRE session:abc123 1800
HGETALL session:abc123
HGET session:abc123 role
EXPIRE session:abc123 1800
TTL session:abc123

การเก็บเซสชันเป็น JSON string เดียวอาจดูน่าสะดวก แต่บังคับให้ต้อง deserialise ทั้ง blob เพียงเพื่ออ่านหรือเปลี่ยนแปลงฟิลด์เดียว เมื่อใช้ hash คำสั่ง HGET ดึงเฉพาะฟิลด์ที่ต้องการ และ HSET อัปเดตเฉพาะฟิลด์ที่เปลี่ยน โดยไม่ต้องรับส่งค่าทั้งหมดของเซสชัน และไม่มีความเสี่ยงที่การเขียนจะทับการอัปเดตพร้อมกันของฟิลด์อื่น

127.0.0.1:6379> HSET session:abc123 role "superadmin"
(integer) 0
127.0.0.1:6379> HGET session:abc123 role
"superadmin"

HSET คืนค่า 0 เมื่ออัปเดต field ที่มีอยู่แล้ว (ไม่มีการเพิ่ม field ใหม่) เฉพาะ field role เท่านั้นที่ถูกแก้ไข ทุก field อื่นยังคงไม่เปลี่ยนแปลง

HSET session:abc123 role "superadmin"
HGET session:abc123 role
ตัวเลือกBenefitCost
Hash ต่อเซสชันอ่าน/อัปเดตทีละ field ได้ ไม่ต้อง deserialize ทั้งก้อนต้องรู้ชื่อ field ล่วงหน้า schema ไม่บังคับใน Redis เอง
JSON string เดียวเขียนอ่านง่าย เก็บโครงสร้างซับซ้อนได้ต้อง deserialize/serialize ทั้ง blob แม้แก้แค่ field เดียว
Sliding TTL (EXPIRE ทุก request)เซสชันที่ active ไม่หมดอายุกลางคันต้องเรียก EXPIRE เพิ่มทุก request ซึ่งเพิ่ม round-trip
  • ลืมเรียก EXPIRE ซ้ำในทุกคำขอ — ถ้าตั้ง TTL แค่ตอน login ครั้งเดียว ผู้ใช้ที่ active อยู่จะถูก logout กลางคันเมื่อ TTL เดิมหมดอายุ
  • ไม่ DEL session key ตอน logout — ถ้าปล่อยให้หมดอายุเองตาม TTL เท่านั้น session token ที่ถูกขโมยจะยังใช้งานได้จนกว่า TTL จะหมด แม้ผู้ใช้จะกด logout ไปแล้ว
  • เก็บข้อมูลอ่อนไหว (เช่น password) ไว้ใน session hash — session store ควรเก็บเฉพาะข้อมูลที่จำเป็นสำหรับ authorization ไม่ใช่ credential ดิบ

💡 ตัวอย่างจากของจริง

Express + connect-redis — ใช้ Redis hash เก็บ session ของแอป Node.js แบบเดียวกับบทนี้ พร้อม sliding TTL ต่อ request

Instagram — ใช้ Redis เป็น session store ระดับ production เพื่อรองรับ session lookup ที่รวดเร็วในสเกลผู้ใช้จำนวนมาก

คำสั่งใดอ่านทุก field และค่าของ hash?
จะสร้าง sliding idle timeout สำหรับเซสชันได้อย่างไร?
ทำไมจึงเก็บเซสชันเป็น hash แทน JSON string?
คำสั่งใดลบเซสชันเมื่อ logout?