การใช้งาน redis-cli
ทดสอบบน Redis 8.10.2 (
redis:8.10.2-alpine,redis-cli8.10.2 จาก image เดียวกัน) บน Mac (Apple silicon) output เป็นของจริง; ตรงที่ output ขึ้นกับว่ามี terminal ต่ออยู่หรือไม่ บทจะบอกไว้
redis-cli — Redis client มาตรฐาน
หัวข้อที่มีชื่อว่า “redis-cli — Redis client มาตรฐาน”redis-cli คือ command-line interface ที่มากับทุกการติดตั้ง Redis (และมีใน official Docker image) รองรับสองโหมด: interactive (prompt แบบ REPL) และ inline (ส่งคำสั่งเดียวตรงจาก shell)
ตัวเลือกการเชื่อมต่อ
หัวข้อที่มีชื่อว่า “ตัวเลือกการเชื่อมต่อ”flag ที่ใช้บ่อย:
| Flag | ค่าเริ่มต้น | วัตถุประสงค์ |
|---|---|---|
-h host | 127.0.0.1 | hostname หรือ IP ของ Redis server |
-p port | 6379 | port ของ Redis server |
-n db-number | 0 | เลือกหมายเลข database (0–15) ตอนเชื่อมต่อ |
-u uri | — | ใช้ URI เดียวแทนสาม flag: redis://user:pass@host:6379/1 (rediss:// สำหรับ TLS) |
-3 | RESP2 | ใช้ RESP3 (เหมือนส่ง HELLO 3 ก่อน) |
# Connect to the default host and portredis-cli
# Connect explicitly — useful when targeting a remote serverredis-cli -h 127.0.0.1 -p 6379
# Connect and immediately switch to database 1redis-cli -n 1
# The same thing as one URI; -u redis://127.0.0.1:6379/1 DBSIZE ran against the real server and printed 0redis-cli -u redis://127.0.0.1:6379/1 DBSIZEInline mode vs interactive mode
หัวข้อที่มีชื่อว่า “Inline mode vs interactive mode”ใน inline mode คุณส่งคำสั่งเดียวเป็น argument ให้ redis-cli แล้วผลลัพธ์จะพิมพ์ออก stdout — สะดวกสำหรับ script:
redis-cli PINGใน interactive mode คุณรัน redis-cli โดยไม่มี argument ของคำสั่ง แล้วได้ prompt 127.0.0.1:6379> ให้พิมพ์คำสั่งทีละคำสั่ง
Reply เดียวกันแต่พิมพ์ต่างกัน ขึ้นกับว่าออกไปที่ไหน
หัวข้อที่มีชื่อว่า “Reply เดียวกันแต่พิมพ์ต่างกัน ขึ้นกับว่าออกไปที่ไหน”นี่คือสิ่งที่มีประโยชน์ที่สุดเกี่ยวกับ redis-cli และเป็นต้นเหตุของ shell script พังมากมาย เมื่อ stdout เป็น terminal redis-cli จะพิมพ์ reply แบบสวยงาม ((nil), (integer) 0, เครื่องหมายคำพูด, รายการมีเลขลำดับ) เมื่อ stdout ไม่ใช่ terminal (pipe, $(...), ไฟล์, การเรียกแบบ argument ใน script) มันจะพิมพ์ค่า raw แทน เซิร์ฟเวอร์เดียวกัน คำสั่งเดียวกัน:
# a terminal, or --no-raw # inside a pipe / $(...) / script (default)"v1" <- GET k1 v1(nil) <- GET nokey (an empty line)(integer) 0 <- DEL nokey 01) "v1" v12) (nil) <- MGET k1 nokey (an empty line)บังคับได้ทั้งสองทาง: --no-raw ให้รูปแบบสวยแม้ถูก pipe, --raw ให้รูปแบบ raw แม้บน terminal (harness ตรวจสอบของคอร์สนี้ใช้ --no-raw เพื่อให้ transcript ตรงกับที่เห็นที่ prompt) โหมดผลลัพธ์อีกแบบที่ควรรู้:
$ redis-cli RPUSH list a "b c" d # then:$ redis-cli --csv LRANGE list 0 -1"a","b c","d"PING — ตรวจสอบการเชื่อมต่อ
หัวข้อที่มีชื่อว่า “PING — ตรวจสอบการเชื่อมต่อ”PING คือการตรวจสอบที่เบาที่สุดว่าเข้าถึงเซิร์ฟเวอร์ได้:
127.0.0.1:6379> PINGPONGส่งข้อความเพิ่มได้ Redis จะ echo กลับ — มีประโยชน์ทดสอบ round-trip latency ใน script:
127.0.0.1:6379> PING "hello world""hello world"ECHO — ส่ง string กลับ
หัวข้อที่มีชื่อว่า “ECHO — ส่ง string กลับ”ECHO คืน argument กลับมาตามเดิม ใช้หลัก ๆ เพื่อทดสอบว่า client encode string ถูกต้อง:
127.0.0.1:6379> ECHO "Hello""Hello"SELECT — สลับ database
หัวข้อที่มีชื่อว่า “SELECT — สลับ database”Redis มี 16 logical database หมายเลข 0 ถึง 15 ใช้ process และหน่วยความจำเดียวกันแต่ keyspace แยกกันสมบูรณ์ ค่าเริ่มต้นคือ database 0 ต่อใน session เดิม:
127.0.0.1:6379> SELECT 1OK127.0.0.1:6379[1]> SET greeting "hi from db1"OK127.0.0.1:6379[1]> SELECT 0OK127.0.0.1:6379> GET greeting(nil)สังเกตว่า prompt เปลี่ยนเป็น 127.0.0.1:6379[1] เมื่ออยู่ใน database ที่ไม่ใช่ 0
DBSIZE — นับ key
หัวข้อที่มีชื่อว่า “DBSIZE — นับ key”DBSIZE คืนจำนวน key ใน database ที่เลือกอยู่ session ที่ผ่านมาเขียนแค่ใน database 1 ดังนั้น database 0 ว่าง:
127.0.0.1:6379> DBSIZE(integer) 0127.0.0.1:6379> SET a 1OK127.0.0.1:6379> SET b 2OK127.0.0.1:6379> DBSIZE(integer) 2FLUSHDB — ล้าง database ปัจจุบัน
หัวข้อที่มีชื่อว่า “FLUSHDB — ล้าง database ปัจจุบัน”FLUSHDB ลบทุก key ใน database ปัจจุบัน ย้อนกลับไม่ได้ — ใช้เฉพาะ development หรือ test เท่านั้น มีตัวเลือก ASYNC (คืนหน่วยความจำเบื้องหลัง) และ SYNC:
127.0.0.1:6379> FLUSHDBOK127.0.0.1:6379> DBSIZE(integer) 0127.0.0.1:6379> FLUSHDB ASYNCOKFLUSHALL ล้างทุก database ไม่ใช่แค่ปัจจุบัน: key greeting ใน database 1 รอดจาก FLUSHDB ข้างบน (มันล้างแค่ database 0) และจะหายก็ต่อเมื่อ FLUSHALL
HELP ในตัว
หัวข้อที่มีชื่อว่า “HELP ในตัว”redis-cli มีเอกสารในตัว ใช้ HELP ตามด้วยชื่อคำสั่งหรือ tag ของหมวด HELP SET ที่ prompt แบบ interactive พิมพ์ว่า (ของจริงจาก 8.10.2):
SET key value [NX|XX|IFEQ ifeq-value|IFNE ifne-value|IFDEQ ifdeq-digest|IFDNE ifdne-digest] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL] summary: Sets the string value of a key, ignoring its type. The key is created if it doesn't exist. since: 1.0.0 group: stringตัวเลือก IFEQ|IFNE|IFDEQ|IFDNE เพิ่งมาใน Redis 8.4 — redis-cli เก่าบนเครื่องคุณที่คุยกับเซิร์ฟเวอร์ใหม่จะไม่ autocomplete ให้ HELP @string แสดงคำสั่งทุกตัวในหมวด string (เริ่มด้วย APPEND, DECR, DECRBY, DELEX, DIGEST, GET, GETDEL, GETEX, …) พร้อม argument และ version ที่ระบุใน since: — วิธีเร็วในการดูว่าคำสั่งมีบนเซิร์ฟเวอร์ที่คุณรันอยู่หรือไม่
PING
ECHO "Hello"
SELECT 1
DBSIZE
SELECT 0flag สำหรับ script ที่ใช้จริง
หัวข้อที่มีชื่อว่า “flag สำหรับ script ที่ใช้จริง”redis-cli -r 3 -i 0.2 INCR hits # repeat 3 times, 0.2 s apart -> 1 2 3echo -n "from stdin" | redis-cli -x SET note # -x: last argument read from stdinredis-cli -e LPUSH note q # -e: exit code 1 on an error replyredis-cli --scan --pattern 'user:*' # SCAN in a loop, never KEYS (next module)redis-cli --latency # live min/avg/max round-trip until Ctrl-Cprintf 'SET a 1\r\nINCR a\r\nLPUSH a x\r\n' | redis-cli --pipe # mass insertผลจริง: -r 3 -i 0.2 INCR พิมพ์ 1 2 3 -x SET note แล้ว GET note ได้ from stdin -e LPUSH บน key string นั้นพิมพ์ WRONGTYPE Operation against a key holding the wrong kind of value และ exit ด้วย 1; คำสั่งเดียวกัน ไม่มี -e exit 0 — shell script ที่ไม่สนใจเรื่องนี้จึงไม่รู้ว่าล้มเหลว --latency พิมพ์ 0.059 1.396 0.143 89 (min, max, avg ms, จำนวน sample) หลังผ่านไป 3 วินาทีบน container และ --pipe ส่งสามคำสั่ง โดยตัวที่สามตั้งใจให้ error เรื่อง wrong-type:
WRONGTYPE Operation against a key holding the wrong kind of valueAll data transferred. Waiting for the last reply...Last reply received from server.errors: 1, replies: 3--pipe คือ bulk loader ระดับ protocol ที่จะพบอีกในบท Pipelines สังเกตการจบบรรทัดแบบ \r\n: มันพูด inline command แบบ raw RESP
RESP3 จาก CLI
หัวข้อที่มีชื่อว่า “RESP3 จาก CLI”HELLO 3 สลับ connection เป็น RESP3 และคืนข้อมูลของเซิร์ฟเวอร์:
127.0.0.1:6379> HELLO 31# "server" => "redis"2# "version" => "8.10.2"3# "proto" => (integer) 34# "id" => (integer) 43...(ตัดให้สั้น: reply ต่อด้วย mode, role และ array modules; id ของคุณจะต่างออกไป) RESP3 ให้ reply ที่มี type — map ยังเป็น map, HGETALL บน key ที่ไม่มีได้ map ว่างแทน array ว่าง — และทำให้ connection ที่ subscribe อยู่รันคำสั่งปกติได้ด้วย (บท Pub/Sub อธิบายว่าทำไมสำคัญ) คอร์สนี้ใช้ RESP2 เริ่มต้นใน CLI; ioredis 6 เจรจาด้วย HELLO ตอนเชื่อมต่อ
Reading AI-generated code
หัวข้อที่มีชื่อว่า “Reading AI-generated code”AI เขียน health-check script สำหรับ deploy pipeline:
🐛 หา bug ในโค้ดนี้
#!/bin/bash# fail the deploy if the session key is missingval=$(redis-cli GET session:42)if [ "$val" = "(nil)" ]; thenecho "no session" >&2exit 1fiecho "session ok"เฉลย
string (nil) ปรากฏเฉพาะตอน redis-cli เขียนไปที่ terminal ภายใน $(...) stdout เป็น pipe redis-cli จึงพิมพ์ output แบบ raw — สำหรับ key ที่ไม่มี นั่นคือ บรรทัดว่าง เรารันกับ key ที่ไม่มี: script เข้า branch “session found” พร้อม [] คือผ่านไปเงียบ ๆ วิธีแก้คือทดสอบสิ่งที่ script ได้รับจริง หรือดีกว่านั้นคือถามคำถามที่ตอบเป็นจำนวนเต็มชัดเจน:
#!/bin/bash# EXISTS returns 1 or 0 in raw mode; -e fails the script on server errorsn=$(redis-cli -e EXISTS session:42) || exit 2if [ "$n" -eq 0 ]; then echo "no session" >&2 exit 1fiecho "session ok"เมื่อ key ไม่มี script แรกพิมพ์ session found: [] ส่วน [ -z "$val" ] หรือการตรวจด้วย EXISTS พิมพ์ “no session” ทั้งคู่ — วิธีแก้ใช้ได้
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”redis-cli คือ protocol client ที่มีสองบุคลิก: แบบมนุษย์ (terminal — มี label, เครื่องหมายคำพูด, (nil)) และแบบเครื่อง (pipe — ค่าเปล่า ๆ, บรรทัดว่าง) ทุกอย่างที่คัดลอกจาก transcript ไปใส่ script ต้องอ่านใหม่ในภาษาแบบเครื่อง และมันเป็น client แบบ บาง: ไม่มี retry ไม่มี pool ไม่มี type — ไว้ดู Redis ไม่ใช่ไว้ให้แอปคุยกับ Redis
Trade-offs
หัวข้อที่มีชื่อว่า “Trade-offs”| ตัวเลือก | ข้อดี | ข้อเสีย |
|---|---|---|
ใช้ redis-cli แบบ interactive | ทดสอบคำสั่งเร็ว ได้ feedback ทันที เหมาะกับการ debug | ไม่มี connection pooling, retry หรือ error handling ที่แอปจริงต้องมี |
| ใช้ client library ในโค้ดแอป | จัดการ connection lifecycle, pipelining และ retry ให้อัตโนมัติ | ต้องเขียนโค้ดเพิ่ม และมี dependency เพิ่ม |
สลับ database ด้วย SELECT | สะดวกในการแยกข้อมูลชั่วคราวตอน dev | ไม่ใช่ multi-tenancy จริง — ทุก database ยังใช้ instance, หน่วยความจำ และประสิทธิภาพร่วมกัน |
parse output ของ redis-cli ใน shell script | ไม่ต้องมี dependency นอกจาก CLI | output ต่างกันระหว่าง terminal กับ pipe; error reply exit 0 ถ้าไม่ใส่ -e |
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “สิ่งที่เห็นที่ prompt คือสิ่งที่
$(redis-cli ...)คืนมา” ไม่ใช่:(nil),(integer), เครื่องหมายคำพูดและเลขลำดับหายไปเมื่อ stdout ไม่ใช่ terminal - “คำสั่งที่ล้มเหลวทำให้ redis-cli exit ค่าไม่ใช่ศูนย์” เฉพาะเมื่อใส่
-e; ตัวอย่าง WRONGTYPE exit 0 ถ้าไม่ใส่ - “
SELECTให้ Redis server แยกกัน” process เดียว หน่วยความจำเดียวFLUSHALLเดียว - “
-aคือวิธีส่งรหัสผ่านที่ปลอดภัย” มันรั่วใน process list; ใช้REDISCLI_AUTHหรือ-uจาก secret store
Common mistakes
หัวข้อที่มีชื่อว่า “Common mistakes”- เชื่อมต่อ
redis-cliเข้า production โดยตรงเพื่อรันคำสั่งแก้ไข — พิมพ์ผิดตัวเดียวอาจกลายเป็นFLUSHDBหรือDELบน key จริง ใช้ script ที่ผ่านการ review หรือ client library แทนเมื่อต้องแตะข้อมูล production - คิดว่า
SELECTแยก tenant ได้ปลอดภัย — 16 logical database ยังใช้ CPU และหน่วยความจำร่วมกัน และFLUSHALLครั้งเดียวกระทบทั้งหมด ไม่ใช่ตัวแทนของการแยก tenant จริง - มอง
redis-cliเป็นช่องทางเดียวที่แอปคุยกับ Redis — รูปแบบที่ดีคือredis-cliสำหรับ debug/สำรวจเท่านั้น ส่วนโค้ด production ผ่าน client library ที่จัดการ connection pooling และ retry