跳至主要内容

[Redis] Getting Started

TL;DR

# 進入 Redis,預設會是 localhost:6379
$ redis-cli # local redis

# 基本操作
> SET framework react
> GET framework # react
> KEYS * # 取得 redis 中所有的 key
> DEL framework

# 其他操作
> TYPE <key> # 檢視型別

# EXPIRE key seconds # 設定 key 過期的時間(自動刪除)
# TTL key # 檢視 key 剩多久會過期
> SET notification "some people fall down"
> EXPIRE notification 30 # 30 秒後會過期
> TTL notification # 檢視剩餘時間(秒);-1 表示該 key 沒有設定過期時間;-2 表示該 key 曾經存在但已過期或被刪除

# 根據 pattern 刪除多筆資料
> redis-cli --scan --pattern "cache:user:*" | xargs redis-cli unlink

安裝 Redis

brew install redis
brew services start redis

另外 Redis 也有還不錯用的 GUI 工具,雖然長得有點像強國國旗:

AnotherRedisDesktopManager @ GitHub

連接到 Redis

  • Connect to Redis:連結到 redis 的各種方式(包括 localhost、remote、Redis Cloud、Docker container 等等)
# 進入 Redis,預設會是 localhost:6379
$ redis-cli # local redis
$ redis-cli -h 192.168.0.10 -p 7000 # remote redis

測試連線:

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> get foo
"bar"

Key

  • Redis 當中的 Key 就是 binary safe 的 string,可以是 "foo", 42, 3.1415, 0xff
  • 由於 Key 本身是 binary 的序列,因此大小寫是有區別的(case sensitive),下面這三組分別都是不同的 Key
    • registeredusers:1000:followers
    • registeredUsers:1000:followers
    • RegisteredUsers:1000:followers
  • 太長的 key 是不建議的,必須在「容易閱讀的 Key」和「使用的記憶體容量」間做取捨
  • 命名慣例上會用冒號(:)做為區隔,例如 user:1000:followers
    • user: object name
    • 1000: user ID
    • followers: composed object

Logical Databases

  • Logical Database 中並沒有 name space 的概念,也就是所有的 key 都是在水平的同一層內,而沒有以 documents 或 collections 的概念
  • Logical Database 會用 zero-based 的 index 來辨別(也就是以 0 開始)。
  • 同一 database 中的 key 不能重複;但不同 database 中的 key 可以重複

搜尋 Keys:KEYS and SCAN

如果要取得一系列的 Key 可以使用 KEYSSCAN 這兩個指令:

  • KEYS可以在本地開發時除錯(Debug)用,但千萬不要用在 Production 上。直到全部完成前會阻塞。
  • SCAN:用在 production 中,雖然它也阻塞,但一次只會迭代(iterate)一定數量的 keys。

使用 KEYS

# 使用 * 表示萬用字元(wild card)
> keys customer:10*

使用 SCAN

  • COUNT 越大則會一次會搜尋越多的量,但因為是阻塞操作的緣故,對效能影響越大
  • 當沒有更多的 KEY 要 iterate 時,cursor 會回傳 0
# SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
> SCAN 0 MATCH customer:10*
1) "15" # cursor 是 15
2) 1) "customer:1000"
2) "customer:1001"

> SCAN 15 MATCH customer:10*
1) "0"
2) (empty array)
  • DEL 會移除掉 KEY 及其相關的記憶體,處理的方式是阻塞的
  • UNLINK 會把 KEY 給移除,而和該 KEY 有關記憶體的清理則是以非同步的方式處理(non-blocking)
> UNLINK customer:1000
(integer) 1

確認 Key 是否存在:EXISTS

> EXISTS customer:1001
(integer) 1

Data Types

Data types @ redis

  • Binary-safe Strings:可以儲存任何的字串,不論是 PNG 或序列化過的物件
  • Lists:本質上是 linked-list,根據被建立的順序可以進行排序。由於是 linked-list 的緣故,它在新增和刪除元素的速度是快的,但搜尋速度是相對慢的
  • Sets:一系列未排序(unsorted)且唯一(unique)的字串
  • Sorted Sets:一系列唯一的字串,但每一個字串都和 float number 連結在一起(稱作 score),因此可以透過 score 進行排序
  • Hashes:類似 map,其 key 和 value 都是字串
  • Bit arrays:又稱作 bitmaps,它讓開發者可以把字串作為 array of bits 處理。
  • HyperLogLogs:用來測量 set 中 element 的數量

String

keywords: SET, GET, SETNX, SETEX, INCR, DECR, INCRBY, DECRBY
  • Binary-safe String 的意思是可以儲存任何形式的字串,例如 JPEG 檔或序列化過的物件
  • String 最大可以到 512MB
# SET key value [EX seconds|PX milliseconds|KEEPTTL] [NX|XX]
> SET phone Note10 EX 10 # 10 秒過期
> SET price 23900

# SETNX key value # SET if Not Exist,如果該 key 不存在才儲存
> SETNX frameworks "react vue angular" # 回傳 1 表示成功,0 表示失敗(該 key 已經存在)

# SETEX key seconds value # 設定過期時間


# 增加或減少數值
> INCR price # 23901,一次增加 1
> DECR price # 23900,一次減少 1
> INCRBY price 1000 # 24900,一次增加 1000
> DECRBY price 1000 # 23900,一次減少 1000

List

keywords: RPUSH, LPUSH, LRANGE, LLEN, LPOP, RPOP
  • 有順序性
  • 新增刪除相對快:適合用在只要取出頭尾元素的情況(例如 Queue)
  • 搜尋速度相對慢
  • 適用時機
    • Message Queue:因為只需要取出頭、尾的元素而不需要搜尋

由於 Lists 本質上是 linked-list 的緣故,它在新增和刪除元素的速度是快的,但搜尋速度是相對慢的。可以使用 RPUSHLPUSH 來新增元素,如果該 key 尚不存在的話,會回傳新的 List,如果該 key 已經存在,或它不是 List 的話,則會回傳錯誤。

# 在 List 中新增元素
# RPUSH <key> <element> [element ...] / LPUSH <key> <element> [element ...]
> RPUSH frameworks react vue angular # 3
> LPUSH frameworks svelte # 4

# 檢視 List 中的元素
# LRANGE <key> <start> <stop>
> LRANGE frameworks 0 -1 # 列出所有元素,-1 表示 list 中的最後一個元素

# 檢視 List 數目
# LLEN <key>
> LLEN frameworks

# 移除 list 中的元素
# RPOP <key> / LPOP <key>
> RPOP frameworks # 移除 list 最後一個元素
> LPOP frameworks

Set

keywords: SADD, SREM, SMEMBERS, SISMEMBER, SUNION
  • 沒有順序性
  • 元素值會是唯一:重複的話不會新增,因此不需要在添加元素前先檢查該元素是否存在
  • 使用時機
    • 紀錄每一個造訪的 IP(因為重複的話不會再次被記錄)
    • 商品的標籤(Tag)

Sets 和 List 很類似,但它並「沒有順序性」而且元素需要是「唯一」的使用 SADD 來建立 Set:

# SADD <key> <member> [member ...]   # 新增元素到 Set 中
> SADD languages english # 1,新增的元素數目
> SADD languages frensh chinese # 2,新增的元素數目
> SADD languages english # 0,如果元素已經在該 Sets 中,會回傳 0

# SREM <key> <member> [member...] # 從 Set 中移除元素
> SREM languages english # 1,移除的元素數目

# SMEMBERS <key> # 檢視 Set 中所有元素
> SMEMBERS languages # 回傳的元素沒有順序性

# SISMEMBER <key> <member> # 檢視元素是否存在該 Set 中
> SISMEMBER languages chinese # 1,存在的話回傳 1,不存在則回傳 0

# SUNION <key> [key...] # 合併多個 Sets
> SUNION languages programming-languages
  • 使用 SADD 時,如果新增的元素已經存在 SET 中,則不會新增
  • 使用 SUNION 時,如果欲合併的 Set 不存在,則會視為合併了一個空的 Set

Hash

keywords: HSET, HGET, HGETALL, HMSET, HMGET

在 Redis 中,Hash 可以用來保存類似物件,也就是 key 配到的是「field-value pairs」

# HSET <key> <field> <value> [field value...]   # 新增 field-value pairs 到 Hash 中
> HSET phone name "iphone" # 1,新增的數目
> HSET phone price 22500 # 1,新增的數目
> HSET phone storage 128 ram 4 # 2,新增的數目
> HSET phone name "iphone mini" # 0,表示該 field 已經存在 hash 中,將會「更新」其 value

# HGET <key> <field> # 取得 field 的 value
> HGET phone name # "iphone mini"

# HGETALL <key> # 取得所該 hash 對所有值
> HGETALL phone

# HMSET <key> <field> <value> [field value...] # 和 HSET 相同
# HMGET <key> <field> [field...] # 一次取出多個 field 的值
> HMGET phone name price

Sorted Set

keywords: ZADD, ZRANGE, ZCARD, ZSCORE, ZCOUNT, ZINCRBY
  • 有順序性,透過與 score 產生連結來達到排序的作用,score 本身會是 float
  • 元素值仍然是唯一,但 score 可以不是唯一
  • 不論是 Add, Remove 或 Update 的速度都很快,同時可以快速搜尋位於中間的項目
  • 可以視為 Set 和 Hash 的混合
  • 使用上指令和 Set 相似,只要把最開頭的 S 改成 Z
  • 使用時機
    • 遊戲的計分板
# ZADD <key> [NX|XX] [CH] [INCR] <score> <member> [score member ...],新增 sorted Set
> ZADD students 1 aaron # 1
> ZADD students 2 allison # 1
> ZADD students 3 bruce 4 derek # 2

# XX:只更新已存在的 member 的 score,絕不新增 member
# NX:不更新以存在的 member 的 score,總是新增 member
> ZADD students XX 10 aaron # 如果 aaron 存在,則將 score 更新為 10
> ZADD students NX
> ZADD students NX 777 jen # 如果 jen 不存在,則新增且將 score 設為 777

# ZRANGE <key> <start> <stop> [WITHSCORES],檢視 sorted set
> ZRANGE students 0 -1 # 檢視 sorted set 中所有元素

# ZCARD <key>,檢視該 set 中的元素數目
> ZCARD students

# ZCOUNT <key> <min> <max> # 檢視分數介於 min ~ max 間的元素拭目
> ZCOUNT students 0 10

# ZSCORE <key> <member> # 檢視某 member 的 score
> ZSCORE students aaron

# ZINCRBY <key> <increment> <member> # 幫 member 的 score 分數增加
> ZINCRBY students 10 aaron # 幫 aaron 的 score 加 10

Bitmaps and HyperLogLogs

參考資料