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

Expiration & TTL

Redis มักถูกใช้เป็น cache หรือที่เก็บ session ในทั้งสองกรณีคุณอยากให้ key หายไปเองหลังผ่านไประยะหนึ่ง — คุณไม่ควรต้องเขียน cleanup job เอง Redis จัดการเรื่องนี้ให้แบบ native ผ่าน key expiration

คุณสามารถแนบ TTL (time-to-live) ตอนสร้าง key หรือเพิ่มเข้าไปกับ key ที่มีอยู่แล้วก็ได้:

Commandคำอธิบาย
SET key val EX secsสร้าง + หมดอายุเป็นวินาที
SET key val PX msสร้าง + หมดอายุเป็นมิลลิวินาที
EXPIRE key secsตั้ง/อัปเดต expiry เป็นวินาทีกับ key ที่มีอยู่
PEXPIRE key msตั้ง/อัปเดต expiry เป็นมิลลิวินาที
EXPIREAT key unix-secsหมดอายุที่ Unix timestamp แบบสัมบูรณ์ (วินาที)
PEXPIREAT key unix-msหมดอายุที่ Unix timestamp แบบสัมบูรณ์ (มิลลิวินาที)
127.0.0.1:6379> SET session:abc "user:42" EX 300
OK
127.0.0.1:6379> TTL session:abc
(integer) 299
127.0.0.1:6379> SET cache:home "<html>...</html>"
OK
127.0.0.1:6379> EXPIRE cache:home 60
(integer) 1
127.0.0.1:6379> TTL cache:home
(integer) 59
SET session:abc "user:42" EX 300
TTL session:abc
SET cache:home "<html>...</html>"
EXPIRE cache:home 60
TTL cache:home

TTL คืนค่าเป็นวินาที ส่วน PTTL คืนค่าเป็นมิลลิวินาที ทั้งคู่มีค่าคืนพิเศษอยู่สองค่า:

  • -1 — key มีอยู่แต่ ไม่มี expiry (เป็น persistent)
  • -2 — key ไม่มีอยู่ (หรือหมดอายุไปแล้ว)
127.0.0.1:6379> SET persistent "I live forever"
OK
127.0.0.1:6379> TTL persistent
(integer) -1
127.0.0.1:6379> TTL nonexistent:key
(integer) -2
127.0.0.1:6379> SET brief "gone soon" PX 5000
OK
127.0.0.1:6379> PTTL brief
(integer) 4987
SET persistent "I live forever"
TTL persistent
TTL nonexistent:key
SET brief "gone soon" PX 5000
PTTL brief

ถ้าคุณอยากยกเลิก expiry ของ key แล้วทำให้ key กลับมา persistent อีกครั้ง ให้ใช้ PERSIST:

127.0.0.1:6379> SET promo "SALE10" EX 3600
OK
127.0.0.1:6379> TTL promo
(integer) 3599
127.0.0.1:6379> PERSIST promo
(integer) 1
127.0.0.1:6379> TTL promo
(integer) -1
SET promo "SALE10" EX 3600
TTL promo
PERSIST promo
TTL promo

Redis ใช้สองกลยุทธ์ที่เสริมกัน — คุณไม่ต้องทำอะไรเลย แต่เข้าใจไว้ก็ช่วยให้คุณคิดเรื่อง memory ได้ดีขึ้น:

Lazy expiry — เมื่อคุณเข้าถึง key (GET, EXISTS ฯลฯ) Redis จะตรวจ expiry ของ key นั้นก่อน ถ้าหมดอายุแล้ว Redis จะลบทิ้งทันทีตรงนั้น และคืน (nil) ราวกับว่าไม่เคยมีอยู่

Active expiry — Redis รัน background cycle (ค่าเริ่มต้นประมาณ 10 ครั้งต่อวินาที) ที่สุ่มตัวอย่าง key ที่มี TTL และลบ key ที่หมดอายุออกไป วิธีนี้ป้องกันไม่ให้ keyspace เต็มไปด้วย key ที่ไม่เคยถูกเข้าถึง

สองกลยุทธ์นี้รวมกันช่วยให้การใช้ memory ถูกจำกัดอยู่ในขอบเขตโดยไม่ block แอปพลิเคชันของคุณ

ตัวเลือกBenefitCost
ตั้ง TTL ให้ key ทุกตัวที่เป็น cache/sessionmemory ถูกล้างอัตโนมัติ ไม่ต้องเขียน cleanup job เองถ้าคำนวณ TTL ผิดพลาด ข้อมูลอาจหายไปเร็วเกินไปทั้งที่ระบบยังต้องใช้อยู่
พึ่งพา lazy expiry (ตรวจตอนเข้าถึง key)ไม่มี overhead เพิ่มถ้าไม่มีใครอ่าน key นั้นเลยkey ที่หมดอายุแต่ไม่มีใครเข้าถึงจะยังกิน memory ค้างอยู่จนกว่า active expiry cycle จะมาเจอ
ใช้ PERSIST ยกเลิก TTL ของ key ที่เคยตั้งไว้ยืดอายุข้อมูลสำคัญได้โดยไม่ต้องสร้าง key ใหม่เสี่ยงลืมว่า key นั้นเคยตั้งใจให้เป็นข้อมูลชั่วคราว ทำให้ memory โตแบบไม่มีการล้าง
  • เช็ก TTL key == 0 เพื่อตรวจว่า key หายไปหรือไม่ — ค่าที่ถูกต้องสำหรับ key ที่ไม่มีอยู่คือ -2 ไม่ใช่ 0 เพราะ TTL จะไม่มีวันค้างอยู่ที่ศูนย์ ต้องแยกเงื่อนไข -2 (ไม่มีอยู่) กับ -1 (persistent) ให้ถูกต้อง
  • ลืมตั้ง TTL ให้ key ที่ควรเป็นข้อมูลชั่วคราว — ถ้า SET cache หรือ session โดยไม่ผูก EX/PX เลย ข้อมูลจะกลายเป็น persistent และสะสมจน maxmemory เต็ม
  • สับสนระหว่าง EXPIRE (relative) กับ EXPIREAT (absolute timestamp) — ใช้ผิดตัวจะทำให้ TTL คลาดเคลื่อนจากที่ตั้งใจ โดยเฉพาะเมื่อ clock ของ client กับ server ไม่ตรงกัน

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

Twitter timeline cache — ผูก TTL กับ key แคช timeline เพื่อให้ข้อมูลเก่าถูกล้างอัตโนมัติ แล้ว regenerate ใหม่จาก source of truth เมื่อมีคน request เข้ามาหลัง cache หมดอายุ

Stack Overflow — ใช้ TTL กับ session key เพื่อ log out ผู้ใช้อัตโนมัติหลังไม่มี activity ในช่วงเวลาที่กำหนด แทนที่จะต้องมี background job มาลบ session เก่า

TTL คืนค่าอะไรสำหรับ key ที่มีอยู่แต่ไม่ได้ตั้ง expiration ไว้?
คำสั่งใดยกเลิก expiration และทำให้ key เป็น persistent?
PEXPIRE ตั้งค่าต่างจาก EXPIRE อย่างไร?
lazy expiry ใน Redis หมายความว่าอย่างไร?