redis最基礎的入門教程

  • 2019 年 10 月 3 日
  • 筆記
 

 

 

Redis最基礎入門教程

還記得第一次面試來也的時候,面試官問我,“會MongoDB嗎?”,“不會”;“知道redis嗎?”,“知道,但是沒用過”,“emm……”

 

 

 

簡介

在面對高並發的數據讀取的時候,當連表查詢的需求不是那麼的強烈,此時,非關係型數據庫得到了高速的發展。其中,非關係型數據庫中的鍵值數據庫中的redis便是我們今天需要講的內容。其中redis為了保證效率,會將數據保存在內存中(當然redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件)。

Redis亦被稱為數據機構服務器,因為它的值(Value)可以是字符串(String),哈希(Hash),列表(List),集合(Sets)和有序集合(sorted sets)。

Redis 在線測試:http://try.redis.io/

下面是一段來自於菜鳥教程的介紹

Redis 簡介

Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。

Redis 與其他 key – value 緩存產品有以下三個特點:

  • Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用。
  • Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
  • Redis支持數據的備份,即master-slave模式的數據備份。

Redis 優勢

  • 性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
  • 豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支持事務,即原子性,通過MULTI和EXEC指令包起來。
  • 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。

Redis與其他key-value存儲有什麼不同?

  • Redis有着更為複雜的數據結構並且提供對他們的原子性操作,這是一個不同於其他數據庫的進化路徑。Redis的數據類型都是基於基本數據結構的同時對程序員透明,無需進行額外的抽象。
  • Redis運行在內存中但是可以持久化到磁盤,所以在對不同數據集進行高速讀寫時需要權衡內存,因為數據量不能大於硬件內存。在內存數據庫方面的另一個優點是,相比在磁盤上相同的複雜的數據結構,在內存中操作起來非常簡單,這樣Redis可以做很多內部複雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機訪問。

redis怎麼安裝,我就不做介紹了,因為不同的系統安裝方式不一樣。如果不想安裝話可以使用在線的redis環境。不過還是推薦一下,因為接下來會使用python去實現一些操作。其中redis數據庫的可視化可以使用redis-desktop-manager。命令行操作使用redis-cli

接下來我將通過不同的數據結構來介紹redis的操作。

字符串(Strings)

字符串(Strings)是Redis的基本數據結構之一,由key和value組成。我們可以這樣類比成編程語言的變量:keya代表變量名,value代表變量值。

查看所有的key的命令

keys *

 

 

 

創建字符串

set key value

 

 

 

如果value中有空格,則需要使用**””**將value包起來。如:

set x "xxx xxx xxx"

讀取字符串

get key

 

 

 

如果獲取一個不存在的key,則會返回nil

修改key裏面的值

  1. 進行修改

    下面這個命令key存在則修改,不存在則創建

set key 新的值

​ 如果我們不希望set的命令覆蓋舊值怎麼辦?在使用”NX”參數即可。這樣,當key存在時,使用set key value NX並不能覆蓋原來的值。

set key value NX

  1. 進行增添

    如果我們想在value的末尾加上一些字符串,使用append命令。(當key不存在的時候,則會創建key)當然,如果如果值有空格的話,和set的處理方法一樣。

    append key value

  2. 數字進行修改

    注意下面的命令只針對於value為數字的情況,否則就會報錯。

    # 讓key裏面的數字加1  incr key  # 減1  decr key  # 加n  incrby key n  # 減n  decrby key n

刪除

如果key存在則放回1,否則返回0

del key

代碼實現

下面是使用python對以上的所有命令進行實現(任何編程語言都差不多)

import redis  client = redis.Redis()  # 獲得所有的key  keys = client.keys()  # 創建字符串  client.set("thisKey","thatValue")  # 獲得value  value = client.get("thisKey")  # 不覆蓋修改  client.set("thisKey","way",nx=True)  # 增添  client.append("thisKey","newMSg")  # 對數字就行修改  client.set("num",1)  client.incr("num")  client.incrby("num",10)  client.decr("num")  client.decrby("num",4)  # 進行刪除操作  client.delete("thisKey")

哈希(Hash)

在前面我們介紹了字符串類型的Redis儲存方案,這個時候我們可以想一想如果我需要儲存10w個人的分數,右需要儲存10w個人的密碼(假如這樣做),那麼我們需要多少多少個key?20w個key!!那麼我們的key又該怎樣分配呢(注意:key不能重複)?我們是不是得這樣:用戶名_score,用戶名_pwd,在用戶名後面加上不同的類型來代表不同的數據。那麼在redis如何解決這些問題呢?使用哈希表!!關於哈希表的數據結構我們可以看看這篇

Redis hash 是一個string類型的field和value的映射表(key任然為key),hash特別適合用於存儲對象,每個 hash 可以存儲 232 – 1 鍵值對(43多億)。使用Hash表不僅能夠減少Redis中key的個數,還能優化存儲空間,佔用的內存要比字符串小很多。

下面是redis的存儲示意圖:

 

 

 

添加數據:

一次添加一個鍵值對數據:

hset key field value

一次添加多個鍵值對數據:

hmset key field1 value1 [field2 value2 ]

當然如果我們不想對已經存在的field進行修改

hsetnx key field value

獲得數據:

獲得一個字段的值:

hget key field

獲得多個字段的值:

hmget key field1 [field2]

獲得所有的字段名和值

hgetall key

當然我們也可以分別獲得所有的field獲得value

hvals key

hkeys key

判斷是否存在某字段

HEXISTS key field

如果字段存在則返回1,如果不存在則返回0

獲得哈希表中字段的數量

hlen key

接下來我就不再使用python實現這些東西了,會更多的來介紹各種結構的特點。如果想了解更多的指令可以看菜鳥教程

列表(List)

列表是一種很神奇的結構,可以把列表成一根水管,數據從可以從一邊進,然後從另外一邊出來(當然,那一邊即可以進又可以出,只不過順序不同而已)。那麼這種結構有什麼用處呢?我們可以以發消息為例。發消息我們需要保證消息到達的順序,那麼我們是不是就可以使用列表了呢?例如:發送消息從左邊進,接受消息從右邊得到。下面介紹幾個簡單的指令:

插入數據

l代表left(左),r代表right(右)

從左邊插入數據

lpush key value

從右邊插入數據

rpush key value

獲得列表的長度

注意下面的第一個l並不是代表left,而是代表list

llen key

查看數據

lrang key 開始索引 結束索引

索引從最左邊開始編號,意思就是最後一個lpush的數據的索引是0(將列表想成一個小水管就行)。如果開始索引和結束索引一樣,就返回索引位置的值。那麼如果從右邊開始呢?使用“負索引”即可。其中**-1**代表最右邊的數據。-2代表最右邊的第二個數據。

彈出數據

彈出最左邊的數據

lpop key

彈出最右邊的數據

rpop key

彈出數據和查看數據的差別在於,彈出數據的同時也會將數據進行刪除。

集合(Sets)

這個集合和數學中的集合有着差不多的概念。怎麼說呢?在redis的集合中,數據是無序的不能重複

添加數據:

s代表集合(set)

sadd key value1 value2 value3……

獲得集合中元素的數量

如果不存在這個集合則返回0

scard key

從集合中獲取數據

spop key count

前面我們說道,集合是無序的,所以spop的獲取也是無序的。(獲得數據後會將數據刪除)count代表獲取幾條數據。

這個是獲得集合的所有數據(並不會刪除數據)。不過這個命令在生產環境中最好不要使用,因為數據量大的話你的服務器可能就炸了。

SMEMBERS key

判斷數據是否存在

sismember key value

存在返回1,否則返回0

刪除數據

srem key value1 value2……

下面便是數學上面的知識了

取交集

sinter key1 key2……

取並集

sunion key1 key2……

取差集

sdiff key1 key2……

有序集合(sorted sets)

有序集合,顧名思義就是集合裏面的數據是有序的。那麼它有什麼含義呢?我們想像一下,在一個高並發的場景中,數據是一直更新的,如果我們將數據存到數據庫中,如果需要實時獲取排名的話,那麼肯定會對數據的性能造成很大的影響。畢竟數據量越大,排序時間也就越緩慢。和集合不同的是,有序集合的元素會關聯一個double類型的分數,其中元素不能重複,但是分數可以重複。

添加數據

zadd key score1 member1 [score2 member2]

前面說過,score必須為double類型,所以如果輸入非double則會報錯。

修改數據

修改數據可以使用zadd進行修改數據的分數,同時可以添加NX參數

zadd key NX sorce member

還可以使用zincrby對數據對數據的分數進行加減操作

ZINCRBY key 改變量 member

其中改變量既可以為正數也可以為負數。如果member不存在則會創建,member的分數和改變量一致。

獲取數據

基於評分範圍內的排序

  1. 從小到大排序

zrangebyscore 有序集合名 評分下限 評分上限 [withsores limit 切片開始位置 結果數量]

  1. 從大到小排序

zrevrangebyscore 有序集合名 評分下限 評分上限 [withsores limit 切片開始位置 結果數量]

其中使用括號括起來的代表可以省略,如果withsores省略代表只返回值,不返回評分。省略“limit 切片開始位置 結果數量”代表不對結果進行切片。

基於位置的排序

  1. 從小到大排序

    位置是從零開始的

    zrange 有序集合名 開始位置(含) 結束位置 (含)[withsores]

  2. 從大到小排序

    zrevrange 有序集合名 開始位置(含) 結束位置 (含)[withsores]

獲得排名

zrank 有序集合名 值

zrevrank 有序集合名 值

zrank 和 zrevrank的區別在於,zrank排名是從0開始的,評分越小則排名越靠近0,評分最小的值排名為0。而zrevrank則是評分越大則越靠近0。相同點在於如果值不存在則返回None。

獲得一個值的評分

zscore 有序集合名 值

如果一個值不存在則返回None。

查看某個評分範圍內的值有多少

zcount 有序集合名 評分下限 評分上限

發佈消息/訂閱頻道

我們來說一個場景,還是以前面的發消息場景為例,如果服務端的消息在進行更新,那麼我們如何更新客戶端的信息呢?按照前面的方法,我們只有使用輪詢查詢的方式,按照一定的時間(比如說1s)檢查redis,看消息是否發生改變,如果消息發生了改變,則客戶端進行更新,那麼接下來就會有以下的問題:

  1. 不停地檢查redis,耗費系統資源
  2. 使用輪詢查詢,消息會有延時
  3. 即使1s(輪詢的時間)中發送了5條消息,那麼客戶端只會發生一次改變。

這個時候我們就是可以使用redis的“發佈/訂閱”模式實現消息通信。

  • 發佈:消息的發佈者
  • 訂閱:消息的接受者,可以為1個也可以為多個

發佈消息

publish 頻道名 信息

訂閱頻道

subscribe 頻道名1 頻道名2……

其中會返回3條消息:第一條是信息的類型,第二條是頻道名,第三條是被發佈的內容。其中需要注意,只能接受目前的消息,新加入的訂閱是沒辦法接受到以前的訂閱的。

結語

以上便是redis的一個很簡單的入門教程。只介紹了redis的簡單使用和一些基本操作,至於redis命令中更複雜的指令,百度或者google就行了。對於redis,我覺得我們(作為一個學生)應該關注的是redis為什麼能夠如此優秀?裏面用了什麼數據結構,以及如何能夠將redis應用到高並發的場景中,怎麼實現多服務器數據的保存以及備份問題。