2021-05-12 14:32:11
Redis從入門到精通
【前言:本文主要介紹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 隨機移除一個任意key6) no-enviction 禁止驅逐資料 |
關注微信公眾號:巨量資料學習與分享,獲取更對技術乾貨
相關文章