Redis 是什麼
Redis
是 開源,記憶體 中的資料結構儲存系統,它可以用作資料庫、快取和訊息中介軟體。它支援多種型別的資料結構,如 字串strings
, 雜湊 hashes
, 列表 lists
, 集合 sets
, 有序集合 sorted sets
與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。
Redis
還內建了 複製(replication
),LUA指令碼(Lua scripting
), LRU驅動事件(LRU eviction
),事務(transactions
) 和不同級別的 磁碟持久化(persistence
), 並通過 Redis哨兵(Sentinel
)和自動 分割槽(Cluster
)提供高可用性(high availability
)。
嗯,沒錯這就是 redis
中文官方網站上面的介紹,簡潔明瞭。
NoSQL 是什麼
我們知道 redis
是一種非關係型資料庫 NoSQL
。而為什麼出現 NoSQL
?NoSQL
又是什麼呢?
單機資料庫的年代
在一個網站訪問量不大的時候,我們使用一個資料庫就足以應對流量請求。
快取 + 拆分
隨著訪問量的上升,一個資料庫已經不能滿足我們的需求了。為了更高的效能,我們在中間加上了一個快取層並且將資料庫做了叢集、結構優化和讀寫分離。
而這裡的快取就是 NoSQL
,當然做快取也只是 NoSQL
的一種功能,就像 Redis
並不僅僅有快取這一種功能。比如它還能實現 簡單的訊息佇列,解決Session共享,計數器,排行榜,好友關係處理 等等功能,可見 Redis
是一個非常強大工具,讓我們來學習它吧!
Redis 通用命令
首先我們拋開資料型別來講關於 Redis
的通用命令。
操作 key 和 value
Redis
是一種 key
value
儲存的快取資料庫,所有的資料都有一個自己唯一的key。
這裡為了方便演示,我使用了字串相關的設定命令
keys [pattern]
獲取符合要求的所有key。時間複雜度為O(n)
,一般在生產環境中不使用,因為Redis
是單執行緒的,執行耗時的任務會阻塞其他任務。一般會使用scan
命令替代(非阻塞)。
dbsize
獲取當前儲存資料個數。exists key
判斷是否存在該keydel key
刪除指定資料type key
獲取指定key的資料型別rename key newkey
重新命名
過期時間
Redis
中很多資料都是用來作為快取資料的,而作為快取就需要有過期時間,在 Redis
中提供了很強大的過期時間設定功能。
expire key seconds
為某個 key 設定過期時間。ttl key
檢視某個 key 的剩餘時間,返回正數代表剩餘的時間,-1代表永久,-2代表已過期或不存在。
Redis 的五種基本資料型別
在上面我說到了很多 Redis
作為快取能實現的其他功能,比如計數器,排行榜,好友關係等,這些實現的依據就是靠著 Redis
的資料結構。在整個 Redis
中一共有五種基本的資料結構(還有些高階資料結構以後會講),他們分別是 字串strings
, 雜湊 hashes
, 列表 lists
, 集合 sets
, 有序集合 sorted sets
。
字串 string
在絕大部分程式語言中都有 String
字串型別,對於作為資料庫的 Redis
也是必不可少的。
set key value
設定值get key
獲取某個key的值mset key1 value1 key2 value2
批量設定並且是原子的,可以用來減少網路時間消耗mget key1 key2
批量獲取並且是原子的,可以用來減少網路時間消耗incr key
自增指定key的值decr key
自減指定key的值incrby key value
自增指定數值decrby key value
自減指定數值incrbyfloat key floatvalue
增加指定浮點數 前面幾個操作就可以用來實現計數器的功能。setnx key value
如果不存在該key則可以設定成功,否則會失敗,加上過期時間限制,則是redis實現分散式鎖的一種方式(後面會提到)。set key value xx
與前面相反,如果存在則設定成功,否則失敗(相當於更新操作)getset key newvalue
設定新值並返回舊值append key value
為原本內容追加內容strlen key
獲取字串長度getrange key start end
獲取指定範圍的內容setrange key index value
設定指定範圍的內容setex key seconds value
設定值且設定過期時間set key value ex seconds nx
為不存在的key設定值且設定過期時間,分散式鎖的實現方式。
hash
其實我們可以理解 hash
為 小型Redis ,Redis
在底層實現上和 Java
中的 HashMap
差不多,都是使用 陣列 + 連結串列 的二維結構實現的。
不同的是,在 Redis
中字典的值只能是字串,而且他們 rehash
的方式不一樣,在 Redis
中使用的是 漸進式rehash 。
在 rehash 的時候會保留新舊兩個 hash 字典,在資料遷移的時候會將舊字典中的內容一點一點遷移到新字典中,查詢的同時會查詢兩個 hash 字典,等資料全部遷移完成才會將新字典代替就字典。
下面我們來看一下關於 hash
的基本操作。
hset key field value
設定字典中某個key的值hsetnx key field value
設定字典中某個key的值(不存在的)hmset key field1 value1 field2 value2 ...
批量設定hget key field
獲取字典中某個key的值hmget key field1 field2
批量獲取hgetall key
獲取全部hdel key field
刪除某個keyhexists key field
判斷是否存在hlen key
獲取指定key對應的字典中的儲存個數hvals key
返回所有的valuehkeys key
返回所有的keyhincrby key field increValue
增加某個value的值(也可以增加負數)hincrbyfloat key field floatValue
增加某個value的值(浮點數)
list
Redis
中的列表相當於 Java
中的 LinkedList
(雙向連結串列) ,也就是底層是通過 連結串列 來實現的,所以對於 list
來說 插入刪除操作很快,但 索引定位非常慢。
Redis
提供了許多對於 list
的操作,如出,入等操作,你可以充分利用它們來實現一個 棧 或者 佇列。
下面我們來看一下關於 list
的基本操作。
lpush key item1 item2 item3...
從左入棧rpush key item1 item2 item3...
從右入棧lpop key
從左出棧rpop key
從右出棧lindex key index
獲取指定索引的元素 O(n)謹慎使用lrange key start end
獲取指定範圍的元素 O(n)謹慎使用linsert key before|after item newitem
在指定元素的前面或者後面新增新元素lrem key count value
刪除指定個數值為value的元素- count = 0 :刪除所有值為value的元素
- count > 0 :從左到右刪除 count 個值為 value 的元素
- count < 0 :從右到做刪除 |count| 個值為 value 的元素
ltrim key start end
保留指定範圍的元素lset key index newValue
更新某個索引的值blpop key timeout
沒有則阻塞(timeout指定阻塞時間 為0代表永久)brpop key timeout
沒有則阻塞(timeout指定阻塞時間 為0代表永久) 這兩個可以用來實現消費者生產者
總結來說我們可以使用 左入又出或者右入左出 來實現佇列,左入左出或者右入右出 來實現棧。
- lpush + lpop = Stack
- rpush + rpop = Stack**
- lpush + rpop = Queue
- rpush + lpop = Queue
- lpush/rpush + ltrim = Capped List (定長列表)
- lpush + brpop = Message Queue (訊息佇列)
- rpush + blpop = Message Queue (訊息佇列)
set
Redis
中的 set
相當於 Java
中的 HashSet
(無序集合),其中裡面的元素不可以重複,我們可以利用它實現一些去重的功能。我們還有對幾個集合進行取交集,取並集等操作,這些操作就可以獲取不同使用者之間的共同好友,共同愛好等等。
下面我們就來看一下關於 set
的一些基本操作。
sadd key value
新增元素sdel key value
刪除某個元素sismember key value
判斷是否是集合中的元素srandmember key count
隨機獲取指定個數的元素(不會影響集合結構)spop key count
從集合中隨機彈出元素(會破壞結合結構)smembers key
獲取集合所有元素 O(n)複雜度scard key
獲取集合個數sinter set1 set2 ...
獲取所有集合中的交集sdiff set1 set2 ...
獲取所有集合中的差集sunion set1 set2 ...
獲取所有集合中的並集
zset
Redis
中的 zset
是一個 有序集合,通過它可以實現很多有意思的功能,比如學生成績排行榜,視訊播放量排行榜等等。
zset
中是使用 跳錶 來實現的,我們知道只有陣列這種連續的空間才能使用二分查詢進行快速的定位,而連結串列是不可以的。跳錶幫助連結串列查詢的時候節省了很多時間(使用跳的方式來遍歷索引來進行有序插入),如果不瞭解跳錶的同學可以補習一下。
下面我們來看一下關於 zset
的一些基本操作。
zadd key score element
新增,score用於排序,value需要唯一,由於使用的跳錶,時間複雜度為 O(logn)。zrem key element
刪除某元素 O(1)時間複雜度zscore key element
獲取某個元素的分數zincrby key incrScore element
增加某個元素的分數zrange key start end [withscores]
獲取指定索引範圍的元素 加上withscores
則返回分數 O(logn + m)時間複雜度zrangebyscore key minScore maxScore [withscores]
獲取指定分數範圍的元素 加上withscores
則返回分數,O(logn + m)時間複雜度zcard key
獲取有序集合長度
Redis 中的事務和管道
管道 Pipeline
在某些場景下我們在一次操作中可能需要執行多個命令,而如果我們只是一個命令一個命令去執行則會浪費很多網路消耗時間,如果將命令一次性傳輸到 Redis
中去再執行,則會減少很多開銷時間。
但是需要注意的是 pipeline
中的命令並不是原子性執行的,也就是說管道中的命令到達 Redis
伺服器的時候可能會被其他的命令穿插。
事務
關係型資料庫具有 ACID
特性,Redis
能保證A(原子性)和I(隔離性),D(永續性)看是否有配置 RDB
或者 AOF
持久化操作,但無法保證一致性,因為 Redis
事務不支援回滾。
我們可以簡單理解為 Redis
中的事務只是比 Pipeline
多了個原子性操作,也就是不會被其他命令給分割,如上圖。
-
multi
事務開始的標誌 -
exec
事務執行 -
discard
清除在這個事務中放入佇列的所有命令,即解除整個事務。 -
watch key
在事務開始前監控某個元素,如果在提交事務的時候發現這個元素的值被其他客戶端更改了則事務會執行失敗。 -
unwatch key
解除監控
Redis常用命令總結
好了,這就是這篇文章全部的內容了,對於 Redis
你還有多少遺忘的或者沒學習到的呢?
如果文章對你有幫助的話,請給我點個贊哦(#^.^#)
關於 Redis
的文章接下來還會再寫,如果感興趣可以關注我(#^.^#)。