📢 [文章新增公告] 新增 為 Kubernetes 而生的 GitOps 工具 - ArgoCD 介紹與說明統一機密、身份與加密的管理系統 - HashiCorp Vault 介紹與說明 文章,歡迎點擊前方連結前往查看 💙
目前 Blog 頁籤支援折疊側邊欄功能,在閱讀文章會更方便,歡迎多加利用 💪
Redis 介紹

Redis 介紹

發布於 2022-03-08 · 最後更新於 2025-07-06

什麼是 Redis ?

Redis 全名是 Remote Dictionary Server ,是快速的開源記憶體鍵值資料庫 (keys-value database)。

由於 Redis 的回應時間極短,低於一毫秒,可以讓遊戲、金融服務、醫療保健等即時應用服務每秒處理幾百萬個請求。


Redis 的優勢

效能

所有的 Redis 資料都是存放在記憶體中,進而實現低延遲和高傳輸量的資料存取。


彈性的資料結構

一般的鍵值資料庫提供的資料結構有限,而 Redis 提供多樣化的資料結構來滿足服務的需求,包含字串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)、有序集合(Zset)。(後續會有詳細介紹)


簡單易用

Redis 可以用更少、更精簡的指令來取代傳統複雜的程式碼,可以存取應用程式的資料。並支援 Java、Python、PHP、C/C++、C#、JavaScript、Node.js、Ruby、R、GO。


複寫和持久性

Redis 採主要-複本架構,支援非同步複寫,可以將資料複寫到多個複本伺服器。不但可以提升讀取效能(因為請求可分割到多部伺服器),還可以再主服務器發生故障時快速恢復。至於持久性,Redis 支援時間點備份,會將資料複製到磁碟中。


實際操作

安裝 Redis

使用 Homebrew 來安裝 Redis (Mac OS:11.6)

$ brew install redis

安裝好用 -v 檢查版本

$ redis-server -v
Redis server v=6.2.6 sha=00000000:0 malloc=libc bits=64 build=c6f3693d1aced7d9
$ redis-cli -v
redis-cli 6.2.6

一個是 Server、另一個是 Cli,所以在稍後測試時,需要開啟兩個 Terminal 來執行歐!


執行 Redis

Server

$ redis-server
39403:C 08 Mar 2022 11:13:17.500 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
39403:C 08 Mar 2022 11:13:17.500 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=39403, just started
39403:C 08 Mar 2022 11:13:17.500
39403:M 08 Mar 2022 11:13:17.501 * Increased maximum number of open files to 10032 (it was originally set to 256).
39403:M 08 Mar 2022 11:13:17.501 * monotonic clock: POSIX clock_gettime
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 6.2.6 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 39403
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           https://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

39403:M 08 Mar 2022 11:13:17.503 # Server initialized
39403:M 08 Mar 2022 11:13:17.503 * Ready to accept connections

如果出現上面符號,就代表 Server 已經啟動,接下來再開另一個 Terminal 來執行 Cli。


Cli

開啟後,在下一個 ping 指令,該指令用於檢測 redis 服務是否啟動,正常會顯示 pong

$ redis-cli
127.0.0.1:6379> ping
PONG

接下來,我們都會在 Cli 視窗做測試,會詳細介紹每一個資料型態以及其適合情境。

後續會使用 Cli 畫面來做示範,但也有不錯的圖形化工具可以用於 redis 上 AnotherRedisDesktopManager 大家可以去試用看看~


資料型態

字串 (Strings)

set、get

這是最基本的型態,可以存放 binary, string, integer, float資料,一個 Strings 的欄位,最高可儲存 512 Megabytes,這裡會用到的指令是 setget ,分別用來儲存以及讀取字串,我們來看一下範例吧。

127.0.0.1:6379> set string hello-world
OK
127.0.0.1:6379> get string
"hello-world"

我們先用 set 將 hello-world 字串存到 string 這個 key,再用 get 顯示 string 裡面的 value。


incr、decr

Redis 還有一些方便的指令,如果存入的 value 是 integer 型態,就可以使用 incrdecr ,來累加與累減。分別代表累加,像是我們的 ++ ,以及累減,像是我們的 - -。

127.0.0.1:6379> set num 10
OK
127.0.0.1:6379> incr num
(integer) 11
127.0.0.1:6379> incr num
(integer) 12
127.0.0.1:6379> decr num
(integer) 11
127.0.0.1:6379> decr num
(integer) 10

append

如果 key 已經存在並且它是字串,可以使用 append 指令,會從字串最後面附加進去,如果不存在,則會直接建立一個,並把值存進去。

127.0.0.1:6379> exists str
(integer) 0
127.0.0.1:6379> append str "Hello"
(integer) 5
127.0.0.1:6379> append str " World~"
(integer) 12
127.0.0.1:6379> get str
"Hello World~"

getrange

可以輸入字串的開始位元與結束位元,會依照你輸入的去顯示字串。我把它理解成是陣列的 key 與 value 的關係。

127.0.0.1:6379> set a "This is a string"
OK
127.0.0.1:6379> getrange a 0 3
"This"
127.0.0.1:6379> getrange a -3 -1
"ing"
127.0.0.1:6379> getrange a 0 -1
"This is a string"
127.0.0.1:6379> getrange a 10 100
"string"

mset

我們也可以設定的時候,把要設定的值都一起設定,只需要使用 mset 就可以達成。

127.0.0.1:6379> mset 1 1 2 2
OK
127.0.0.1:6379> get 1
"1"
127.0.0.1:6379> get 2
"2"
127.0.0.1:6379> get 3
(nil)

如果用 get 顯示資料,若沒有對應的 key ,會顯示 (nil)。


字串型態適合場景

字串(strings) 型態適合用於圖片快取 (使用binary)、累計次數、觀看累計次數


String 適用場景圖

String 適用場景圖


哈希 (Hashes)

可以把他想像成二維陣列,應該會比較好理解,我網路上找了一張圖,應該會比較清楚!


Hashes 示意圖 (Redis 基本資料形態 )

Hashes 示意圖 (Redis 基本資料形態)


Hashes 是用來存放一組相同性質的資料,這些資料 Hashes 或是物件的某一屬性,與 String 較為不同的是他可以取回單一個欄位資料,但 String 必須取回所有資料,單一個 Key 可以存放2^32 - 1的資料欄位,

他的資料型態有像是,一個 user001 裡面是一個 Hashes,Hashes 裡面又會存放 name、phone、gender ,我們來實際操作看看。


hset、hget
127.0.0.1:6379> hset student name ian phone 0980123456 gender M
(integer) 3
127.0.0.1:6379> hget student name
"ian"
127.0.0.1:6379> hget student phone
"0980123456"
127.0.0.1:6379> hget student gender
"M"

Hashes 的話要使用 hsethget 來對 Hashes 做儲存以及讀取。


hgetall

想要一次顯示 Hashes 裡面的 key 跟 value ,可以使用 hgetall 來顯示全部資料。

127.0.0.1:6379> hset student name ian phone 0980123456 gender M
(integer) 3
127.0.0.1:6379> hgetall student
1) "name"
2) "ian"
3) "phone"
4) "0980123456"
5) "gender"
6) "M"

hkeys

想要單獨顯示 Hashes 裡面的 key ,可以使用 hkeys 來顯示。

127.0.0.1:6379> hset student name ian phone 0980123456 gender M
(integer) 3
127.0.0.1:6379> hkeys student
1) "name"
2) "phone"
3) "gender"

hvals

想要單獨顯示 Hashes 裡面的 value ,可以使用 hvals 來顯示。

127.0.0.1:6379> hset student name ian phone 0980123456 gender M
(integer) 3
127.0.0.1:6379> hvals student
1) "ian"
2) "0980123456"
3) "M"

hlen

想要顯示 Hashes 裡面的 key 長度,可以使用 hlen 來顯示。

127.0.0.1:6379> hgetall student
1) "name"
2) "ian"
3) "gender"
4) "M"
127.0.0.1:6379> hlen student
(integer) 2

hincrby

想要增加 Hashes 裡面的 value 整數,可以使用 hincrby 來新增。

127.0.0.1:6379> hset test a 10 b 20
(integer) 2
127.0.0.1:6379> hincrby test a 2
(integer) 12

hdel

想要刪除 Hashes 裡面的 key,可以使用 hdel 來刪除。

127.0.0.1:6379> hset student name ian phone 0980123456 gender M
(integer) 3
127.0.0.1:6379> hdel student phone
(integer) 1
127.0.0.1:6379> hgetall student
1) "name"
2) "ian"
3) "gender"
4) "M"

哈希型態適合場景

哈希(Hashes) 型態適合用於每次只需要取用一部分的資料


Hashes 適用場景圖

Hashes 適用場景圖


列表 (Lists)

lpush、lrange

Lists 資料型態可以想像成程式語言中的Array物件。Lists 單一個Key可以存放2^32 - 1,這邊會使用到 lpushlrange 來對 Lists 做儲存以及讀取。

127.0.0.1:6379> lpush list2 a a b b c d e
(integer) 7
127.0.0.1:6379> lrange list2 0 10
1) "e"
2) "d"
3) "c"
4) "b"
5) "b"
6) "a"
7) "a"

rpush

除了從隊伍頭放入資料,也可以用 rpush 從隊伍尾放入資料,如果使用 lrange 來顯示方向也會相反歐。

127.0.0.1:6379> rpush list3 a a b b c d e
(integer) 7
127.0.0.1:6379> lrange list3 0 10
1) "a"
2) "a"
3) "b"
4) "b"
5) "c"
6) "d"
7) "e"

lpop、rpop

也可以使用 lpoprpop 分別從隊伍頭或尾彈出一筆資料。

127.0.0.1:6379> rpush list3 a a b b c d e
(integer) 7
127.0.0.1:6379> lpop list3
"a"
127.0.0.1:6379> rpop list3
"e"

lset

可以使用 lset 來設定指定位置的資料。

127.0.0.1:6379> lrange list3 0 2
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> lset list3 1 w
OK
127.0.0.1:6379> lrange list3 0 2
1) "a"
2) "w"
3) "c"

列表型態適合場景

列表(Lists) 型態適合用於文章列表或者資料分頁展示的應用


Lists 適用場景圖

Lists 適用場景圖


集合 (Sets)

其實跟 Lists 一樣,就是資料的集合,只是 Sets 多了一層限制,就是集合中的值不能重複,這邊會使用到 saddsmembers 來對 Sets 做儲存以及讀取。

127.0.0.1:6379> sadd set1 a b c d a a b b
(integer) 4
127.0.0.1:6379> smembers set1
1) "c"
2) "a"
3) "b"
4) "d"

可以看到他實際寫入的只有 4 筆資料。


spop

set 集合中隨機跳出一定數量的資料。

127.0.0.1:6379> sadd set1 a a b b c d
(integer) 4
127.0.0.1:6379> spop set1 2
1) "c"
2) "d"
127.0.0.1:6379> spop set1 2
1) "a"
2) "b"

sismember

可以使用 sismember 來檢查輸入值是否為 Set 集合的成員。

127.0.0.1:6379> sadd set a b b c d
(integer) 4
127.0.0.1:6379> sismember set d
(integer) 1
127.0.0.1:6379> sismember set f
(integer) 0

srem

可以使用 srem 來刪除 Set 集合中的成員。

127.0.0.1:6379> sadd set a b b c d
(integer) 4
127.0.0.1:6379> srem set a d
(integer) 2
127.0.0.1:6379> smembers set
1) "b"
2) "c"

sdiff

會顯示第一個集合與其他集合不同的值。

127.0.0.1:6379> sadd set1 a b c d
(integer) 4
127.0.0.1:6379> sadd set2 a b
(integer) 2
127.0.0.1:6379> sadd set3 b
(integer) 1
127.0.0.1:6379> sdiff set1 set2 set3
1) "c"
2) "d"

集合型態適合場景

集合(Sets) 型態適合用於文章中的Tag標籤、或是要排除相同資料


Sets 適用場景圖

Sets 適用場景圖


有序集合 (Zset)

故名思義,有序集合就是有排序的集合,Sorted Sets 結構會 多一個數字值去為排序的權重 來決定先後順序,這邊會使用到 zaddzrangebyscore 來對 Zset 做儲存以及讀取。

127.0.0.1:6379> zadd sortset 10 '10'
(integer) 1
127.0.0.1:6379> zadd sortset 6 '6'
(integer) 1
127.0.0.1:6379> zadd sortset 2 '2'
(integer) 1
127.0.0.1:6379> zadd sortset 99 '99'
(integer) 1
127.0.0.1:6379> zrangebyscore sortset 0 100
1) "2"
2) "6"
3) "10"
4) "99"

就可以看出在顯示的時候並不是依照寫入順序,而是依照我們所設定的權重去排序的。


withscores

如果想要顯示 value 與 score ,可以使用 withscores 來顯示。

127.0.0.1:6379> zadd money 2000 tom
(integer) 1
127.0.0.1:6379> zadd money 3500 peter
(integer) 1
127.0.0.1:6379> zadd money 5000 jack
(integer) 1
127.0.0.1:6379> zrange money 0 -1 withscores
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

zremrangebyscore

移除有序集合中,指定分數內區間的所有成員。

127.0.0.1:6379> zadd money 2000 tom
(integer) 1
127.0.0.1:6379> zadd money 3500 peter
(integer) 1
127.0.0.1:6379> zadd money 5000 jack
(integer) 1
127.0.0.1:6379> zremrangebyscore money 1500 3500
(integer) 2
127.0.0.1:6379> zrange money 0 -1 withscores
1) "jack"
2) "5000"

zcard

可以使用 zcard 來計算集合中元素的數量。

127.0.0.1:6379> zadd sort 10 10
(integer) 1
127.0.0.1:6379> zadd sort 3 3
(integer) 1
127.0.0.1:6379> zadd sort 66 66
(integer) 1
127.0.0.1:6379> zadd sort 33 33
(integer) 1
127.0.0.1:6379> zcard sort
(integer) 4

有序集合型態適合場景

有序集合(Zset) 型態適合用於需要有序排列的資料


Zset 適用場景圖

Zset 適用場景圖


發布訂閱 (PUB/SUB)

Redis 發布訂閱 (pub/sub) 是一種消息通信模式,發送者 (pub) 發送消息,訂閱者 (sub) 接收消息。

Redis 客戶端可以使用 subscribe 來訂閱任意數量的頻道。

下面這張圖是頻道1,以及訂閱這個頻道的三個用戶端分別是客戶端2、客戶端7、客戶端5


Subscribe 示意圖

Subscribe 示意圖


當我們有新消息通過 publish 指令發送給頻道1 ,這個消息就會被發送給有訂閱頻道1的三個客戶端。


Publish 示意圖

Publish 示意圖


我們來模擬一下吧 ! 先開兩個 Terminal 來執行 redis-cli 一個當作發送(pub),另一個當作接收(sub)。

我們先用第一個 Terminal 訂閱一個頻道 channel_1

127.0.0.1:6379> subscribe channel_1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel_1"
3) (integer) 1

開啟另一個 Terminal 發送訊息到 channel_1

127.0.0.1:6379> publish channel_1 "Hello World~"
(integer) 1
127.0.0.1:6379> publish channel_1 "ian~"
(integer) 1
127.0.0.1:6379> publish channel_1 "test~"
(integer) 1

這時候再切換回來第一個 Terminal ,就可以看到他接收到我們傳送的訊息
127.0.0.1:6379> subscribe channel_1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel_1"
3) (integer) 1
1) "message"
2) "channel_1"
3) "Hello World~"
1) "message"
2) "channel_1"
3) "ian~"
1) "message"
2) "channel_1"
3) "test~"

參考資料

Redis 官網:https://redis.io

Redis:https://aws.amazon.com/tw/redis/

Redis 基本資料形態:https://blog.judysocute.com/2020/10/04/redis-%E5%9F%BA%E6%9C%AC%E8%B3%87%E6%96%99%E5%BD%A2%E6%85%8B/

Redis 發布訂閱:https://www.runoob.com/redis/redis-pub-sub.html