SCAN & Key Operations
operation พื้นฐานของ key
หัวข้อที่มีชื่อว่า “operation พื้นฐานของ key”คำสั่งเหล่านี้ทำงานได้กับ key ทุกตัวไม่ว่าจะเป็น type ใด
คืน 1 ถ้า key มีอยู่ และคืน 0 ถ้าไม่มี คุณสามารถเช็กหลาย key พร้อมกันได้ — ค่าที่คืนกลับมาคือจำนวน key ที่มีอยู่
127.0.0.1:6379> SET user:1 "Ada"OK127.0.0.1:6379> EXISTS user:1(integer) 1127.0.0.1:6379> EXISTS user:99(integer) 0127.0.0.1:6379> EXISTS user:1 user:99 user:1(integer) 2ลบ key หนึ่งตัวหรือมากกว่า คืนจำนวน key ที่ถูกลบจริง ๆ (key ที่ไม่มีอยู่จะไม่ถูกนับ)
127.0.0.1:6379> SET a "1"OK127.0.0.1:6379> SET b "2"OK127.0.0.1:6379> DEL a b nonexistent(integer) 2127.0.0.1:6379> EXISTS a(integer) 0คืน type ของข้อมูลที่เก็บไว้ที่ key หนึ่ง: string, list, set, zset, hash หรือ stream
127.0.0.1:6379> SET mystr "hello"OK127.0.0.1:6379> TYPE mystrstring127.0.0.1:6379> TYPE nonexistent:keynoneเปลี่ยนชื่อ key ถ้า key ปลายทางมีอยู่แล้ว จะถูกเขียนทับ ใช้ RENAMENX เพื่อเปลี่ยนชื่อเฉพาะกรณีที่ปลายทางยังไม่มีอยู่
127.0.0.1:6379> SET old:key "value"OK127.0.0.1:6379> RENAME old:key new:keyOK127.0.0.1:6379> EXISTS old:key(integer) 0127.0.0.1:6379> GET new:key"value"SET user:1 "Ada"
EXISTS user:1
EXISTS user:99
SET a "1"
SET b "2"
DEL a b nonexistent
SET mystr "hello"
TYPE mystr
SET old:key "value"
RENAME old:key new:key
GET new:keyKEYS — และทำไมห้ามใช้บน production
หัวข้อที่มีชื่อว่า “KEYS — และทำไมห้ามใช้บน production”KEYS pattern คืน key ทุกตัวที่ตรงกับ pattern แบบ glob สะดวกมากสำหรับการพัฒนาและ debug
127.0.0.1:6379> MSET user:1 "Ada" user:2 "Bob" session:abc "tok" session:xyz "tok2"OK127.0.0.1:6379> KEYS user:*1) "user:2"2) "user:1"127.0.0.1:6379> KEYS *1) "user:2"2) "user:1"3) "session:abc"4) "session:xyz"KEYS เป็นการ scan ทั้ง keyspace แบบ blocking และ O(N) บน Redis server ที่มี key เป็นล้านตัว คำสั่งนี้อาจใช้เวลาหลายวินาที และ block client ตัวอื่นทั้งหมดตลอดช่วงนั้น อย่ารัน KEYS กับ production server เด็ดขาด — ใช้ SCAN แทน
SCAN — การวนไล่ keyspace อย่างปลอดภัย
หัวข้อที่มีชื่อว่า “SCAN — การวนไล่ keyspace อย่างปลอดภัย”SCAN เป็น iterator ที่ใช้ cursor การเรียกแต่ละครั้งจะประมวลผล key เป็น batch เล็ก ๆ และคืนค่ากลับมา:
- cursor ตัวใหม่ (เพื่อส่งต่อให้การเรียกครั้งถัดไป)
- รายการ key จาก batch นี้
เมื่อ cursor ที่คืนกลับมาเป็น 0 แสดงว่าการวนไล่เสร็จสมบูรณ์
127.0.0.1:6379> MSET k1 a k2 b k3 c k4 d k5 e k6 f k7 g k8 h k9 i k10 jOK127.0.0.1:6379> SCAN 0 MATCH k* COUNT 31) "7"2) 1) "k9" 2) "k3" 3) "k1"127.0.0.1:6379> SCAN 7 MATCH k* COUNT 31) "4"2) 1) "k8" 2) "k2"127.0.0.1:6379> SCAN 4 MATCH k* COUNT 31) "0"2) 1) "k10" 2) "k4" 3) "k7" 4) "k5" 5) "k6"COUNT เป็นเพียง คำใบ้ ไม่ใช่ขีดจำกัดตายตัว — Redis อาจคืน key มากกว่าหรือน้อยกว่านั้นในแต่ละครั้ง การวนไล่จะเสร็จสมบูรณ์เสมอเมื่อ cursor กลับมาเป็น 0
MSET k1 a k2 b k3 c k4 d k5 e k6 f k7 g k8 h k9 i k10 j
SCAN 0 MATCH k* COUNT 3
SCAN 0 MATCH k* COUNT 100option ของ SCAN
หัวข้อที่มีชื่อว่า “option ของ SCAN”| Option | คำอธิบาย |
|---|---|
MATCH pattern | กรองผลลัพธ์ด้วย pattern แบบ glob (การกรองเกิดขึ้นหลังการสุ่มตัวอย่าง) |
COUNT hint | แนะนำว่าจะสุ่มตัวอย่างกี่ item ต่อการเรียกหนึ่งครั้ง (ค่าเริ่มต้น 10) |
TYPE type | คืนเฉพาะ key ที่เป็น type ที่ระบุ (Redis 6.0+) |
loop สำหรับ scan ทั้งหมดที่ใช้จริงใน script จะมีหน้าตาประมาณนี้:
127.0.0.1:6379> SCAN 0 MATCH session:* COUNT 1001) "42"2) 1) "session:abc"127.0.0.1:6379> SCAN 42 MATCH session:* COUNT 1001) "0"2) 1) "session:xyz"เรียก SCAN ด้วย cursor ที่คืนกลับมาเรื่อย ๆ จนกว่า cursor จะกลับมาเป็น 0 แล้วรวบรวมผลลัพธ์จากทุกรอบเข้าด้วยกัน
SCAN 0 MATCH session:* COUNT 100ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
SCAN (cursor-based iteration) | ไม่ block server แบ่งงานเป็น batch เล็ก ๆ ปลอดภัยกับ production | ไม่ได้ snapshot ที่แน่นอน — key ที่ถูกเพิ่ม/ลบระหว่าง scan อาจโผล่มาซ้ำหรือถูกข้าม |
KEYS * (full blocking scan) | ง่าย เรียกครั้งเดียวได้ผลลัพธ์ครบ เหมาะกับ dataset เล็กใน dev | block event loop จนกว่าจะสแกนครบทุก key ห้ามใช้กับ production ที่มี key จำนวนมาก |
ตั้ง COUNT สูงใน SCAN เพื่อลดจำนวนรอบ | เรียก round-trip น้อยลง เร็วขึ้นในภาพรวม | แต่ละรอบทำงานหนักขึ้น อาจกระทบ latency ของคำสั่งอื่นที่รันคั่นอยู่ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ใช้
KEYS *เพื่อดู key ทั้งหมดบน production — คำสั่งนี้ block server จนกว่าจะสแกนครบทุก key บน dataset ใหญ่อาจทำให้ client อื่นค้างหลายวินาที ควรใช้SCANแทนเสมอ - เข้าใจผิดว่า
COUNTคือขีดจำกัดตายตัวของจำนวน key ที่คืนมา —COUNTเป็นเพียงคำใบ้ Redis อาจคืน key มากกว่าหรือน้อยกว่านั้นในแต่ละรอบก็ได้ - หยุด loop การเรียก
SCANก่อนที่ cursor จะกลับมาเป็น0— ทำให้ได้ผลลัพธ์ไม่ครบ การวนไล่ต้องเรียกต่อเนื่องจนกว่า cursor ที่คืนมาจะเป็น0เท่านั้นถึงจะถือว่าสมบูรณ์
💡 ตัวอย่างจากของจริง
GitHub-style rate-limit dashboards — ใช้
SCANแทนKEYSเมื่อต้อง audit key ที่ตรงกับ pattern บน production Redis instance ที่มี key นับล้านตัว เพื่อไม่ให้กระทบ traffic จริงCache invalidation tooling — ทีม ops มักเขียน script ที่ loop
SCANเพื่อหา key ที่ตรงกับ pattern (เช่นcache:user:*) แล้วลบเป็น batch แทนที่จะเสี่ยง block server ด้วยKEYS