首頁 > 軟體

Redis從入門到精通

2020-11-02 09:30:17

【前言:本文主要介紹redis,內容豐富且實用,旨在幫助大家對redis有一個更深入、全面的瞭解以及在實際工作中更好的應用redis,篇幅較長,建議大家收藏,仔細閱讀】

Redis簡介

Redis是用C語言開發的一個基於記憶體的、高效能key-value鍵值對的、開源nosql資料庫。目前,redis的key是字串型別的,但value支援多種資料型別:字串(string)、雜湊(hash)、列表(list)、集合(set)、有序集合(sortedset),通過提供多種鍵值資料型別來適應不同場景下的儲存需求。

 

 

Redis應用場景

介紹幾種常見的應用:

1. 構建佇列系統

可以用list可以構建佇列系統,使用sorted set甚至可以構建有優先順序的佇列系統

2. pub、sub釋出訂閱構建實時訊息系統、訊息佇列

3. 計數器應用

redis的命令如INCR,DECR都是原子性的,可以通過這些命令來構建計數器系統4.分散式叢集架構中session共用

Redis特性

 

1. 基於記憶體儲存,資料存取速度快,效能好

根據官方提供的測試資料:50個並行執行100000個請求,讀的速度是110000次/s,寫的速度是81000次/s【資料僅供參考,根據伺服器設定會有不同結果】

 

2. 資料持久化機制

目前支援APF和RDB兩種持久化機制,下文會詳細闡述

3. 支援叢集模式,容量可以線性擴充套件

注意:Redis3.X開始才支援叢集模式

4.支援豐富的資料結構

這一點是相比其他快取工具如memcache比較鮮明的優勢

Redis資料結構

首先強調一點,redis的key是字串型別,但value支援多種資料型別。關於key的定義,有幾點建議:

1.key不要太長,太長不僅消耗記憶體還會降低查詢效率。建議不要超過1024個位元組

2.key不要太短,要具有可讀性3.在實際專案中,key最好有一個統一的命名規範

下面詳細介紹一下redis的value目前支援的資料型別:

 

>> string型別

字串是redis支援的最基礎的資料型別,它在redis中是二進位制安全的,應用最多。

操作redis的string型別資料常用命令:

set(設定)、get(獲取)、getset(獲取並設定)、del(刪除)

 


一次性插入或者獲取多條資料:

MGET  key1  key2

MSET  key1  value1   key2  value2  …..

在插入一條string型別資料的同時為它指定一個存活期限:

setex  username  10  張三對string型別資料進行增減操作的幾個命令:

incr:將指定的key的value原子性的遞增1。如果該key不存在,其初始值為0,在incr之後其值為1    

decr:將指定的key的value原子性的遞減1。如果該key不存在,其初始值為0,在decr之後其值為-1

incrby key increment:將指定的key的value原子性增加increment。如果該key不存在,其初始值為0,在incrby之後,該值為increment

decrby key decrement:將指定的key的value原子性減少decrement,如果該key不存在,其初始值為0,在decrby之後,該值為decrement。

append key value:拼湊字串。如果該key存在,則在原有的value後追加該值;如果該key不存在,則重新建立一個key/value。

注意:

decr incr decrby incrby 都是原子性操作。進行增減前提是:key可以轉換為整型否則報錯。相信做過SparkStreaming流式計算統計pv、uv中,中間狀態儲存會熟悉該特性的應用。

 

>> list型別

筆者強調一點:redis中list底層是雙端連結串列結構,這個在面試中經常會問。redis為什麼這麼快,其實不僅僅是因為基於記憶體儲存,底層還多了很多的優化,這只是其中之一,下圖是對雙端連結串列的一個圖形描述:

常用的操作命令:
lpush:從頭部(左邊)插入資料

rpush:從尾部(右邊)插入資料

lrange key  start  end:讀取list中指定範圍的values。start、end從0開始計數;也可為負數,若為-1則表示連結串列尾部的元素,-2則表示倒數第二個,依次類推…

lpop:從頭部彈出一個元素

rpop:從尾部彈出一個元素

rpoplpush:從一個list的尾部彈出一個元素插入到另一個list。原子性操作,沒有key2會建立key2,一旦key1的list元素被取完,key1會被清除

llen key:返回指定的key關聯的連結串列中的元素的數量

list資料型別應用案例訊息佇列比如有這樣一個需求:實現一個任務排程系統==>生產者不斷產生任務,放入task-queue排隊,消費者不斷拿出任務來處理,同時放入一個tmp-queue暫存,如果任務處理成功,則清除tmp-queue;否則,將任務彈回task-queue。筆者這裡提供一個實現思路,就不貼程式碼了,其實就是上述API的簡單應用:

1. 生產者將生產的任務lpush進task-queue中

2. 消費者通過rpoplpush將taks-queue中取任務並暫存任務到tmp-queue中

3. 如果任務處理成功,tmp-queue通過rpop清除相應任務;任務處理失敗,則rpoplpush將任務從tmp-queue中清除並存入task-queue中

4. 為了避免消費者程式在處理任務失敗之後沒有及時將rpoplpush失敗的任務時就已經掛掉,可以加入一個管理tmp-queque的角色,以便在這種情況時也能將處理失敗的任務lpush進task-queue中。

 

>> hash型別

redis中的hash型別可以看成具有map容器,適合儲存值物件的資訊。如username、password等。

常用命令:

hset key  field  value:為指定的key設定field/value對(鍵值對)

hmset key field value [field2 value2 …]:設定key中的多個filed/value

hincrby key field increment:設定key中filed的值增加increment

hexists key field:判斷指定的key中的filed是否存在

 

>> set型別

無序、無重複元素。和list型別相比,set型別在功能上還存在著一個非常重要的特性,即在伺服器端完成多個set之間的聚合計算操作,如並集、交集、差集的計算。由於這些操作均在伺服器端完成,因此效率極高,而且也節省了大量的網路IO開銷。

常用命令:

新增:  sadd key values[value1、value2…]  [多個value間空格分隔]

刪除:srem key members[member1、member2…] 刪除set中指定的成員(成員可以是多個)[]

查詢:smembers key 檢視指定key的set中的資料

判斷:sismember key value [判斷引數中指定的成員是否在該set中,1表示存在,0表示不存在或者該key本身就不存在。(無論集合中有多少元素都可以極速的返回結果)]

統計set元素個數:scard key [指定key對應的set的元素數]srandmember key:隨機返回set中的一個成員
sdiff、sunion、sinter:差集、並集、交集

>> sortedset型別

sortedset中的每一個元素都會有一個分數與之關聯,redis正是通過分數來為集合中的元素進行排序,預設正序。注意:sortedset中的資料不能重複,但分數卻可以重複。

常用命令:

zadd key score member score2 member2 … :將所有成員以及該成員的分數存放到sorted-set中。如果該元素已經存在則會用新的分數替換原有的分數。返回值是新加入到集合中的元素個數,不包含之前已經存在的元素。(score可以重複,member不可以重複)

zscore key member:返回指定成員的分數

zcard key:獲取集合中的成員數量zrem key member[member…]:移除集合中指定的成員,可以指定多個成員

zrange key start end [withscores]:獲取集合中腳標為start-end的成員,[withscores]參數列明返回的成員包含其分數。(withscores可選引數)

zrevrange key start stop [withscores]:按照元素分數從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素)

 

Redis事務

首先強調一點,redis2.X是弱事務,redis3.X無事務。

1. 在事務中的所有命令都將會被序列化的順序執行,事務執行期間,redis不會再為其它使用者端的請求提供任何服務,從而保證了事物中的所有命令被原子的執行

2. 和關係型資料庫中的事務相比,在redis事務中如果有某一條命令執行失敗,其後的命令仍然會被繼續執行。

3. 我們可以通過MULTI命令開啟一個事務,可以將其理解為關係型資料庫的"BEGIN TRANSACTION"語句。在該語句之後執行的命令都將被視為事務之內的操作,最後我們可以通過執行EXEC/DISCARD命令來提交/回滾該事務內的所有操作。這兩個Redis命令可被視為等同於關係型資料庫中的COMMIT/ROLLBACK語句。

4. 在事務開啟之前,如果使用者端與伺服器之間出現通訊故障並導致網路斷開,其後所有待執行的語句都將不會被伺服器執行。然而如果網路中斷事件是發生在使用者端執行EXEC命令之後,那麼該事務中的所有命令都會被伺服器執行。

5. Append-Only模式時,redis會通過呼叫系統函數write將該事務內的所有寫操作在本次呼叫中全部寫入磁碟。然而如果在寫入的過程中出現系統宕機,導致資料丟失。redis伺服器會在重新啟動時執行一系列必要的一致性檢測,一旦發現類似問題,就會立即退出並給出相應的錯誤提示。此時,我們就要充分利用redis工具包中提供的redis-check-aof工具,該工具可以幫助我們定位到資料不一致的錯誤,並將已經寫入的部分資料進行回滾。修復之後我們就可以再次重新啟動redis伺服器了

命令解釋:

multi:開啟事務用於標記事務的開始,其後執行的命令都將被存入命令佇列,直到執行EXEC時,這些命令才會被原子的執行,類似於關係型資料庫中的:begin transaction ,相當於MySQL的 start transaction

exec:提交事務,類似與關係型資料庫中的:commit

discard:事務回滾,類似與關係型資料庫中的:rollback


Redis持久化


>> RDB快照

根據一定的設定規則,將記憶體中的資料快照持久化到磁碟。除了自動的快照方式,也可以通過命令進行快照持久化:

1. save

redis會先阻塞所有使用者端的請求,然後將資料同步儲存到磁碟

2. bgsave

將資料非同步儲存到磁碟。通過fork出子程序,父程序繼續處理請求,子程序將資料非同步儲存到磁碟

3. lastsave

返回上次成功將資料儲存到磁碟的時間戳

4. shundown

將資料同步儲存到磁碟,然後關閉服務

1/10/10000個鍵被更改是指觸發了某些規則(如事務,寫,插入等操作)的次數。由於快照方式是在一定間隔時間做一次的,所以如果redis意外宕機的話,就會丟失最後一次快照後的所有修改。

>> AOF

將對redis操作的每一個命令記錄在appendonly.aof檔案中,應用的較多。

開啟方式:在redis.conf中,appendonly yes。

aof方式的缺點:時間久了,appendonly.aof檔案會越來越大,在恢復的時候很耗時==>如可能操作了500w次,但最終只是更新了1000個key,即很多命令是冗餘的。

可以通過在使用者端執行命令bgrewriteaof,將冗餘命令進行刪除

AOF具體設定方式:

1. 修改redis.conf組態檔 :執行命令vim redis.conf,輸入/aof搜尋appendonly no

2. 輸入命令i進入編輯模式,將appendonly no修改為appendonly yes 儲存退出 esc ==>Shift zz或者:wq

3. 把之前的資料刪掉dump.rdb 執行命令 rm -rf dump.rdb

4. 啟動 ./redis-server redis.conf,檢視啟動狀態 ps -ef | grep redis

5. 輸入命令 ll,出現appendonly.aof檔案

 

 

AOF應用範例:

啟動使用者端 ./redis-cli,執行命令set a a ,set b b,不小心輸入誤操作flushall,將所有資料清除了。恢復步驟:

a. 先關閉redis伺服器,檢視aof檔案中的資料

b. 將appendonly.aof中誤刪除的操作刪掉然後儲存退出

c. 重新啟動redis伺服器,然後登陸redis使用者端查詢還原後的資料

通過上述的介紹會發現,AOF相對RDB持久化更安全,但效率稍微低一些,恢復慢

 

Redis主從設定

 

修改redis.conf設定

1)master不需要修改

2)slave修改以下標籤

如:#slaveof <masterip> <masterport>

啟動伺服器時先啟動master,通過info命令檢視主從服務狀態命令。實際生產環境中,僅僅如此設定主從還不行,還要考慮單點故障問題,實現主從容錯自動切換,這需要用到哨兵模式。

Redis主從災難恢復策略

1. master宕機

步驟:

a)修改主從組態檔:redis.conf中的daemonize no改為yes

b)使用命令:redis-cli -p 埠號==》slaveof NO ONE(關掉主從,轉為主伺服器)

c)等到出問題的伺服器修復好後,在修復好的伺服器上使用命令slaveof ip port讓其變為從,這樣資料就可以同步了

2. master和slave同時崩潰

啟動伺服器後,將備份伺服器最新的AOF備份拷貝到master端,啟動master,一切完成後,再啟動slave(否則在master沒有完全啟動時啟動slave,slave發現master資料比自身還少,會刪除掉自身攜帶的」多餘」的資料)

 

哨兵模式

哨兵通過監控master,如果master無法心跳回應,哨兵進行投票從slave中(如果多個)選出一個master,然後進行容錯切換。

哨兵設定

首先介紹幾個組態檔:

sentinel.conf:redis哨兵模式組態檔

redis-sentinel:哨兵啟動指令碼

啟動:./redis-sentinel /usr/local/redis-cluster/sentinel.conf

port 26379  #埠daemonize yes  #後臺執行  守護行程

#當前機器監測master名字及埠號,2:當有幾臺哨兵監控到主機出錯後執行主從切換(sentinel做決策的時候需要投贊同票的最少的sentinel的數量)

sentinel monitor master1 ip port 2

#當哨兵對master執行ping操作時,超過指定時間沒有迴應即認為master處於(s_down狀態)subjectively #down預設30秒

sentinel down-after-milliseconds master1 30000/**failover-timeout 可以用在以下這些方面:1.同一個sentinel對同一個master兩次failover之間的間隔時間2.當一個slave從一個錯誤的master那裡同步資料開始計算時間。直到slave被糾正為向正確的master那裡同步資料的時間3.當想要取消一個正在進行的failover所需要的時間
4.當進行failover時,設定所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確設定為指向master,但是就不按parallel-syncs所設定的規則來了*/

#sentinel在該設定值內未能完成failover操作(即故障時master/slave自動切換),則認為本次failover失敗

sentinel failover-timeout master1 900000

#在執行故障轉移時,最多可以有多少個從伺服器同時對新的主伺服器進行同步

sentinel config-epoch master1 0

#sentinel auth-pass mymaster 123456#如果你的redis叢集有密碼

logfile "/usr/local/log/sentinel.log"   #當前哨兵模式存放的紀錄檔檔案

(哨兵模式一旦啟動,會在後臺修改sentinel.conf檔案,所以此時不要去手動修改組態檔了)

哨兵作用

哨兵監測master狀態通過心跳

1.不時地監控redis是否按照預期良好地執行2.如果發現某個redis節點執行出現狀況,能夠通知另外一個程序(例如它的使用者端)3.能夠進行自動切換。當一個master節點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節點會將它所追隨的master的地址改為被提升為master的slave的新地址

4.哨兵為使用者端提供服務發現,使用者端連結哨兵,哨兵提供當前master的地址然後提供服務,如果出現切換,也就是master掛了,哨兵會提供使用者端一個新地址

Redis安全性

redis.conf檔案中新增:requirepass 密碼,以後在使用者端登入的時候必須得給出密碼:./redis-cli.sh 密碼。一般公司環境都會設定密碼

在redis主從設定中,密碼一般相同。如果master設定了密碼,slave需要授權master密碼,如:#masterauth <master-password>

 

Redis資料遷移

 

介紹幾種常用的方式:

1.RDB方式

如mini2機器掛掉,將正常執行的機器mini1上的資料同步到mini2上:使用命令scp -r dump.rdb mini2:$PWD,將mini1上dump.rdb檔案傳送到mini2上,重啟mini2上的redis服務

注意:這種方式必須修改redis.conf檔案中appendonly yes改為no

2.使用第三方工具進行資料恢復或者遷移

先安裝

yum install ruby rubygems ruby-devel

gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/

gem install redis-dump -V

命令(直接在linux命令列輸入):

redis-dump -u mini1:6379 > dump.json  #將dump.rdb檔案拷貝成一份dump.json

< dump.json redis-load -u mini1:6379然後重新進入使用者端檢視資料是否遷移成功

 

Redis回收策略

可以通過設定redis回收策略,淘汰redis中的冷資料,保持redis中是經常用到的熱資料。組態檔redis.conf,#maxmemory <bytes> (redis當前快取的最大記憶體數);#maxmemory-policy volatile-lru(移除超過生命週期的key)

 

maxmemory-policy:

1) volatile-lru

     從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰

2) volatile-ttl

    從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰

3) volatile-random

    從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰

4) allkeys-lru

    從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰

5) allkeys-random

    隨機移除一個任意key

6) no-enviction

    禁止驅逐資料


 

關注微信公眾號:巨量資料學習與分享,獲取更對技術乾貨


IT145.com E-mail:sddin#qq.com