Redis命令,五大數據型別,數據持久化,主從複製,事務,叢集總結

2020-08-11 18:21:08

Redis簡介

簡單介紹

Redis:開源、免費、非關係型數據庫、K-V數據庫、記憶體數據庫,支援持久化、事務和備份,叢集(支援16個庫)等高可用功能。並且效能極高(可以達到100000+的QPS),易擴充套件,豐富的數據型別,所有操作都是單執行緒,原子性的。

NOSQL:非關係型數據庫,數據與數據之間沒有關聯關係。就是爲了解決大規模數據集合多重數據種類帶來的挑戰,尤其是大數據應用難題

型別

  1. 鍵值(key-value)儲存數據庫
  2. 列儲存數據庫:鍵仍然存在,但是指向了多個列,HBase (eg:部落格平臺(標籤和文章),日誌)
  3. 文件型數據庫 MongoDb (eg:淘寶商品的評價)
  4. 圖形數據庫 Neo4j (eg:好友列表)

擴充套件:

MongoDB是一個基於分佈式檔案儲存的數據庫。有C++語言編寫。旨在爲WEB應用提供可延伸的高效能數據儲存解決方案。

MongoDB是一個介於關係型數據庫和非關係型數據庫之間的產品,是非關係數據庫當中功能最豐富,最像關係型數據庫的。

文件(document)是MongoDB中數據的基本單元,非常類似於關係型數據庫系統中的行(但是比行要複雜的多);
集合(collection)就是一組文件,如果說MongoDB中的文件類似於關係型數據庫中的行,那麼集合就如同表;

使用場景:

  1. 數據模型比較簡單
  2. 需要靈活更強的IT系統
  3. 對數據庫效能要求比較高
  4. 不需要高度的數據一致性
  5. 對於給定的key,比較容易對映覆雜值的環境

SQL:關係型數據庫,表與表之間建立關聯關係

redis的安裝

#拉取映象
docker pull redis
#掛載數據卷並執行容器
docker run -p 6379:6379 --name redis -v /root/redis/data:/data -v /root/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis redis-server /usr/local/etc/redis/redis.conf --appendonly yes --requirepass "xxx"

爲什麼使用NOSQL

單機 MySQL 的美好時代

在90年代,一個網站的存取量一般都不大,用單個數據庫完全可以輕鬆應付。
在那個時候,更多的都是靜態網頁,動態互動型別的網站不多。

创建

DAL : Data Access Layer(數據存取層 – Hibernate,MyBatis)

上述架構下,我們來看看數據儲存的瓶頸是什麼?

  1. 數據量的總大小一個機器放不下時。
  2. 數據的索引(B+ Tree)一個機器的記憶體放不下時。
  3. 存取量(讀寫混合)一個範例不能承受。

如果滿足了上述1 or 3個時,只能對數據庫的整體架構進行重構。


Memcached(快取)+MySQL+垂直拆分

關於垂直拆分和水平拆分的簡單介紹

後來,隨着存取量的上升,幾乎大部分使用MySQL架構的網站在數據庫上都開始出現了效能問題,web程式不再僅僅專注在功能上,同時也在追求效能。程式設計師們開始大量的使用快取技術來緩解數據庫的壓力,優化數據庫的結構和索引。開始比較流行的是通過檔案快取來緩解數據庫壓力,但是當存取量繼續增大的時候,多臺web機器通過檔案快取不能共用,大量的小檔案快取也帶了了比較高的IO壓力。在這個時候,Memcached就自然的成爲一個非常時尚的技術產品。

Memcached作爲一個獨立的分佈式的快取伺服器,爲多個web伺服器提供了一個共用的高效能快取服務,在Memcached伺服器上,又發展了根據hash演算法來進行多臺Memcached快取服務的擴充套件,然後又出現了一致性hash來解決增加或減少快取伺服器導致重新hash帶來的大量快取失效的弊端。

Mysql主從讀寫分離

由於數據庫的寫入壓力增加,Memcached只能緩解數據庫的讀取壓力。讀寫集中在一個數據庫上讓數據庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫效能和讀庫的可延伸性。Mysql的master-slave模式成爲這個時候的網站標配了。

[外連圖片轉存失敗,源站可能有防盜鏈機制 機製,建議將圖片儲存下來直接上傳(img-WnXNOtIQ-1597140519885)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20200326205904264.png)]

分庫分表+水平拆分+mysql叢集

在Memcached的快取記憶體,MySQL的主從複製,讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而數據量的持續猛增,由於MyISAM在寫數據的時候會使用表鎖,在高併發寫數據的情況下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM。

ps:這就是爲什麼 MySQL 在 5.6 版本之後使用 InnoDB 做爲預設儲存引擎的原因 – MyISAM 寫會鎖表,InnoDB 有行鎖,,並且是事務優先,發生衝突的機率低,併發效能高。

注意鎖的幾個概念:行鎖和表鎖,讀鎖和寫鎖,樂觀鎖和悲觀鎖,還有一個間隙鎖

詳情請看鎖的介紹

四種NoSQL對比

Nosql对比

3V+3高

大數據時代的3V
網際網路需求的3高
海量Volumn
3v
多樣Variety
實時Velocity
高併發
3高
高可用
高效能

ACID

事務是由一組SQL語句組成的邏輯處理單元,事務具有4屬性,通常稱爲事務的ACID屬性。

  • 原子性(Actomicity):事務是一個原子操作單元,其對數據的修改,要麼全都執行,要麼全都不執行。

  • 一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。這意味着所有相關的數據規則都必須應用於事務的修改,以操持完整性;事務結束時,所有的內部數據結構(如B樹索引或雙向鏈表)也都必須是正確的。

    eg:有3個人進行轉賬操作,爲了保證一致性(即3個人 的賬號金額總數不變),那在我寫程式碼的時候,如果寫了程式碼:A=A-5000;此時數據時不一致的。那就必須要寫上,B=B+5000,或者是C=C+5000,這樣的程式碼才能 纔能保證了數據庫的一致性狀態。

  • 隔離性(Isolation):數據庫系統提供一定的隔離機制 機製,保證事務在不受外部併發操作影響的「獨立」環境執行。這意味着事務處理過程中的中間狀態對外部是不可見的,反之亦然。具體看下面 下麪的幾個隔離級別和併發問題。

  • 永續性(Durable):事務完成之後,它對於數據的修改是永久性的,即使出現系統故障也能夠保持

CAP

C:consistency,數據在多個副本中能保持一致的狀態。

A:Availability,整個系統在任何時刻都能提供可用的服務,通常達到99.99%四個九可以稱爲高可用

P:Partition tolerance,分割區容錯性,在分佈式中,由於網路的原因無法避免有時候出現數據不一致的情況,系統如果不能在時限內達成數據一致性,就意味着發生了分割區的情況,必須就當前操作在C和A之間做出選擇,換句話說,系統可以跨網路分割區線性的伸縮和擴充套件。

CAP理論的核心:一個分佈式系統不可能同時很好的滿足一致性,可用性和分割區容錯性這三個需求,最多隻能同時較好的滿足兩個

  • CA:單點叢集,滿足一致性,可用性的系統,通常在可延伸上不太強大。應用:傳統的Oracle數據庫
  • CP:滿足一致性,分割區容錯性的系統,通常效能不是特別高。應用:Redis,MongoDB,銀行
  • AP:滿足可用性,分割區容錯性,通常可能對一致性要求低一些。應用:大多數網站架構的選擇

CAP理論就是說在分佈式儲存系統中,最多隻能實現上面的兩個。而由於當前的網路硬體肯定會出現延遲丟包等問題。所以

分割區容忍性是我們必須需要實現的

所以我們只能在一致性和高可用之間進行權衡,沒有NoSQL系統能同時保證三點。爲什麼呢?

爲何CAP三者不可兼得

現在我們就來證明一下,爲什麼不能同時滿足三個特性?

假設有兩臺伺服器,一臺放着應用A和數據庫V,一臺放着應用B和數據庫V,他們之間的網路可以互通,也就相當於分佈式系統的兩個部分。

在滿足一致性的時候,兩臺伺服器 N1和N2,一開始兩臺伺服器的數據是一樣的,DB0=DB0。在滿足可用性的時候,使用者不管是請求N1或者N2,都會得到立即響應。在滿足分割區容錯性的情況下,N1和N2有任何一方宕機,或者網路不通的時候,都不會影響N1和N2彼此之間的正常運作。

當使用者通過N1中的A應用請求數據更新到伺服器DB0後,這時N1中的伺服器DB0變爲DB1,通過分佈式系統的數據同步更新操作,N2伺服器中的數據庫V0也更新爲了DB1,這時,使用者通過B向數據庫發起請求得到的數據就是即時更新後的數據DB1。

上面是正常運作的情況,但分佈式系統中,最大的問題就是網路傳輸問題,現在假設一種極端情況,N1和N2之間的網路斷開了,但我們仍要支援這種網路異常,也就是滿足分割區容錯性,那麼這樣能不能同時滿足一致性和可用性呢?

假設N1和N2之間通訊的時候網路突然出現故障,有使用者向N1發送數據更新請求,那N1中的數據DB0將被更新爲DB1,由於網路是斷開的,N2中的數據庫仍舊是DB0;

如果這個時候,有使用者向N2發送數據讀取請求,由於數據還沒有進行同步,應用程式沒辦法立即給使用者返回最新的數據DB1,怎麼辦呢?有二種選擇,第一,犧牲數據一致性,響應舊的數據DB0給使用者;第二,犧牲可用性,阻塞等待,直到網路連線恢復,數據更新操作完成之後,再給使用者響應最新的數據DB1。

上面的過程比較簡單,但也說明了要滿足分割區容錯性的分佈式系統,只能在一致性和可用性兩者中,選擇其中一個。也就是說分佈式系統不可能同時滿足三個特性。這就需要我們在搭建系統時進行取捨了。

Base

Base就是爲了解決關係型數據庫強一致性引起的問題而引起的可用性降低而提出的解決方案。

Base其實是下面 下麪三個術語的縮寫:

  • 基本可用(Basically Available)
  • 軟狀態(Soft state)狀態可以有一段時間不同步
  • 最終一致(Eventually consistent)最終數據是一致的就可以了,而不是時時保持強一致

它的思想是通過讓系統放鬆對某一時刻數據一致性的要求來換取系統整體伸縮性和效能上改觀。爲什麼這麼說呢,緣由就在於大型系統往往由於地域分佈和極高效能的要求,不可能採用分佈式事務來完成這些指標,要想獲得這些指標,我們必須採用另外一種方式來完成,這裏BASE就是解決這個問題的辦法。

案例轉賬爲例,我們把使用者A給使用者B轉賬分成四個階段,第一個階段使用者A準備轉賬,第二個階段從使用者A賬戶扣減餘額,第三個階段對使用者B增加餘額,第四個階段完成轉賬。系統需要記錄操作過程中每一步驟的狀態,一旦系統出現故障,系統能夠自動發現沒有完成的任務,然後,根據任務所處的狀態,繼續執行任務,最終完成任務,達到一致的最終狀態。

在實際應用中,上面這個過程通常是通過持久化執行任務的狀態和環境資訊,一旦出現問題,定時任務會撈取未執行完的任務,繼續未執行完的任務,直到執行完成爲止,或者取消已經完成的部分操作回到原始狀態。這種方法在任務完成每個階段的時候,都要更新數據庫中任務的狀態,這在大規模高併發系統中不會有太好的效能,一個更好的辦法是用Write-Ahead Log(寫前日誌),這和數據庫的Bin Log(操作日誌)相似,在做每一個操作步驟,都先寫入日誌,如果操作遇到問題而停止的時候,可以讀取日誌按照步驟進行恢復,並且繼續執行未完成的工作,最後達到一致。寫前日誌可以利用機械硬碟的追加寫而達到較好效能,因此,這是一種專業化的實現方式,多數業務繫系統還是使用數據庫記錄的欄位來記錄任務的執行狀態,也就是記錄中間的「軟狀態」,一個任務的狀態流轉一般可以通過數據庫的行級鎖來實現,這比使用Write-Ahead Log實現更簡單、更快速。

分佈式和叢集

分佈式:不同的多臺伺服器上面部署不同的服務模組(工程)

叢集:不同的多臺伺服器上面部署相同的服務模組。通過分佈式排程軟體進行統一的排程,對外提供服務和存取。

Redis的數據型別

Redis五種數據型別:string、hash、list、set、zset

公用命令

  • del key
  • dump key:序列化給定key,返回被序列化的值
  • exists key:檢查key是否存在
  • expire key second:爲key設定過期時間,以秒計算,可以不寫second,預設爲秒
  • ttl key:返回key剩餘時間,-1爲永久,-2爲失效
  • persist key:移除key的過期時間,key將持久儲存
  • keys pattern:查詢所有符號給定模式的key eg:keys *
  • randomkey:隨機返回一個key
  • rename key newkey:修改key的名稱
  • move key db:移動key至指定數據庫中 eg:move a 1
  • type key:返回key所儲存的值的型別

expirekey second的使用場景
1、限時的優惠活動
2、網站數據快取
3、手機驗證碼
4、限制網站訪客頻率

key的命名建議

  1. key不要太長,儘量不要超過1024位元組。不僅消耗記憶體,也會降低查詢的效率
  2. key不要太短,太短可讀性會降低
  3. 在一個專案中,key最好使用統一的命名模式,如user:123:password
  4. key區分大小寫

String

string型別是二進制安全的,redis的string可以包含任何數據,如影象、序列化物件。一個鍵最多能儲存512MB。二進制安全是指,在傳輸數據的時候,能保證二進制數據的資訊保安,也就是不會被篡改、破譯;如果被攻擊,能夠及時檢測出來

  • set key_name value:命令不區分大小寫,但是key_name區分大小寫
  • setnx key value:當key不存在時設定key的值。(SET if Not eXists),分佈式鎖的問題
  • setex:建立一個key,並且設定他的過期時間
  • get key_name
  • getrange key start end:獲取key中字串的子字串,從start開始,end結束
  • setrange key offset value:設定從offset往後的值
  • mget key1 [key2 …]:獲取多個key
  • getset key_name value:返回key的舊值,並設定key的值。當key不存在,返回nil
  • strlen key:返回key所儲存的字串的長度
  • incr key_name :INCR命令key中儲存的值+1,如果不存在key,則key中的值話先被初始化爲0再加1
  • INCRBY KEY_NAME 增量
  • DECR KEY_NAME:key中的值自減一
  • DECRBY KEY_NAME
  • append key_name value:字串拼接,追加至末尾,如果不存在,爲其賦值

String應用場景
1、String通常用於儲存單個字串或JSON字串數據
2、因爲String是二進制安全的,所以可以把保密要求高的圖片檔案內容作爲字串來儲存
3、計數器:常規Key-Value快取應用,如微博數、粉絲數。INCR本身就具有原子性特性,所以不會有執行緒安全問題

hash

Redis hash是一個string型別的field和value的對映表,hash特別適用於儲存物件。每個hash可以儲存232-1(40億左右)鍵值對。可以看成KEY和VALUE的MAP容器。相比於JSON,hash佔用很少的記憶體空間。

常用命令

  • hset key_name field value:爲指定的key設定field和value
  • hmset key field value[field1,value1]
  • hsetnx:當不存在才建立該field
  • hget key field
  • hmget key field[field1]
  • hgetall key:返回hash表中所有欄位和值
  • hkeys key:獲取hash表所有欄位
  • hvals key:獲取hash表所有值
  • hlen key:獲取hash表中的欄位數量
  • hdel key field [field1]:刪除一個或多個hash表的欄位
  • hexists:在key裏面是否存在指定的field
  • hincrby key field increment:增加某個field的值

應用場景

Hash的應用場景,通常用來儲存一個使用者資訊的物件數據。

  1. 相比於儲存物件的string型別的json串,json串修改單個屬性需要將整個值取出來。而hash不需要。
  2. 相比於多個key-value儲存物件,hash節省了很多記憶體空間
  3. 如果hash的屬性值被刪除完,那麼hash的key也會被redis刪除

list

類似於Java中的LinkedList。

常用命令

  • lpush key value1 [value2]:從左側插入,右邊的先出,相當於一個棧

  • eg:lpush list 1 2 3 lrange list 0 -1 輸出:3 2 1

  • rpush key value1 [value2]: 從右側插入,左邊的先出

  • eg:rpush list 1 2 3 lrange list 0 -1 輸出:1 2 3

  • lpushx key value:從左側插入值,如果list不存在,則不操作

  • rpushx key value:從右側插入值,如果list不存在,則不操作

  • llen key:獲取列表長度

  • lindex key index:獲取指定索引的元素,從零開始

  • lrange key start stop:獲取列表指定範圍的元素

  • lpop key :從左側移除第一個元素

  • prop key:移除列表最後一個元素

  • irem:刪除指定個數的同一元素

  • eg:irem list 2 3 刪掉了集閤中的兩個三

  • blpop key [key1] timeout:移除並獲取列表第一個元素,如果列表沒有元素會阻塞列表到等待超時或發現可彈出元素爲止

  • brpop key [key1] timeout:移除並獲取列表最後一個元素,如果列表沒有元素會阻塞列表到等待超時或發現可彈出元素爲止

  • ltrim key start stop :對列表進行修改,讓列表只保留指定區間的元素,不在指定區間的元素就會被刪除

  • eg:list1中元素1 2 3 4 5 ltrim list1 2 3 list1剩餘元素:3 4

  • lset key index value :指定索引的值

  • linsert key before|after world value:在列表元素前或則後插入元素

應用場景

  1. 對數據大的集合數據刪減

       列表顯示、關注列表、粉絲列表、留言評價…分頁、熱點新聞等

  2. 任務佇列
       list通常用來實現一個訊息佇列,而且可以確保先後順序,不必像MySQL那樣通過order by來排序

補充:

  • rpoplpush list1 list2 移除list1最後一個元素,並將該元素新增到list2並返回此元素
    用此命令可以實現訂單下單流程、使用者系統登錄註冊簡訊等。

效能總結

它是一個字串鏈表,left、right都可以插入新增;
如果鍵不存在,建立新的鏈表;
如果鍵已存在,新增內容;
如果值全移除,對應的鍵也就消失了。
鏈表的操作無論是頭和尾效率都極高,但假如是對中間元素進行操作,效率就很慘淡了。

set

唯一、無序

  • sadd key value1[value2]:向集合新增成員

  • scard key:返回集合成員數

  • smembers key:返回集閤中所有成員

  • sismember key member:判斷memeber元素是否是集合key成員的成員

  • srandmember key [count]:返回集閤中一個或多個亂數

  • srem key member1 [member2]:移除集閤中一個或多個成員

  • spop key:移除並返回集閤中的一個隨機元素

  • smove source destination member:將member元素從source集合移動到destination集合

  • sdiff key1 [key2]:返回給定的第一個集合和其他集合的差集(即在key1中的值而在其他key中找不到)

  • sdiffstore destination key1[key2]:返回給定的第一個集合與其他的集合的差集並儲存在destination中

    eg:set1:1 2 3 set2:3 4 5 6 sdiffstore set3 set1 set2 smembers set3 result:1 2

  • sinter key1 [key2]:返回所有集合的交集

  • sunion key1 [key2]:返回所有集合的並集

對兩個集合間的數據[計算]進行交集、並集、差集運算
1、以非常方便的實現如共同關注、共同喜好、二度好友等功能。對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給用戶端還是儲存到一個新的集閤中。
2、利用唯一性,可以統計存取網站的所有獨立 IP

zset

有序且不重複。每個元素都會關聯一個double型別的分數,Redis通過分數進行從小到大的排序。分數可以重複

  • zadd key score1 memeber1

  • zcard key :獲取集閤中的元素數量

  • zcount key min max 計算在有序集閤中指定區間分數的成員數

  • zcount key min max 計算在有序集閤中指定區間分數的成員數

  • zrange key start stop 指定輸出索引範圍內的成員

  • zrangebyscore key min max 指定輸出score區間內的成員

  • zrank key member:返回有序集合指定成員的索引

  • zrevrange key start stop :返回有序集中指定區間內的成員,通過索引,分數從高到底

  • zrem key member [member …] 移除有序集閤中的一個或多個成員

  • zremrangebyrank key start stop 移除有序集閤中給定的索引區間的所有成員(第一名是0)(低到高排序)

  • zremrangebyscore key min max 移除有序集閤中給定的分數區間的所有成員

常用於排行榜:

  1. 如推特可以以發表時間作爲score來儲存
  2. 儲存成績
  3. 還可以用zset來做帶權重的佇列,讓重要的任務先執行

解析組態檔

#是否在後台執行;no:不是後臺執行
daemonize yes
 
#是否開啓保護模式,預設開啓。要是設定裡沒有指定bind和密碼。開啓該參數後,redis只會本地進行存取,拒絕外部存取。
protected-mode yes
 
#redis的進程檔案
pidfile /var/run/redis/redis-server.pid
 
#redis監聽的埠號。
port 6379
 
#此參數確定了TCP連線中已完成佇列(完成三次握手之後)的長度, 當然此值必須不大於Linux系統定義的/proc/sys/net/core/somaxconn值,預設是511,而Linux的預設參數值是128。當系統併發量大並且用戶端速度緩慢的時候,可以將這二個參數一起參考設定。該內核參數預設值一般是128,對於負載很大的服務程式來說大大的不夠。一般會將它修改爲2048或者更大。在/etc/sysctl.conf中新增:net.core.somaxconn = 2048,然後在終端中執行sysctl -p。
tcp-backlog 511
 
#指定 redis 只接收來自於該 IP 地址的請求,如果不進行設定,那麼將處理所有請求
#bind 127.0.0.1
#bind 0.0.0.0
 
#設定unix socket來讓redis支援監聽本地連線。
# unixsocket /var/run/redis/redis.sock
 
#設定unix socket使用檔案的許可權
# unixsocketperm 700
 
# 此參數爲設定用戶端空閒超過timeout,伺服器端會斷開連線,爲0則伺服器端不會主動斷開連線,不能小於0。
timeout 0
 
#tcp keepalive參數。如果設定不爲0,就使用設定tcp的SO_KEEPALIVE值,使用keepalive有兩個好處:檢測掛掉的對端。降低中間裝置出問題而導致網路看似連線卻已經與對端埠的問題。在Linux內核中,設定了keepalive,redis會定時給對端發送ack。檢測到對端關閉需要兩倍的設定值。
tcp-keepalive 0
 
#指定了伺服器端日誌的級別。級別包括:debug(很多資訊,方便開發、測試),verbose(許多有用的資訊,但是沒有debug級別資訊多),notice(適當的日誌級別,適合生產環境),warn(只有非常重要的資訊)
loglevel notice
 
#指定了記錄日誌的檔案。空字串的話,日誌會列印到標準輸出裝置。後臺執行的redis標準輸出是/dev/null。
logfile /var/log/redis/redis-server.log
 
#是否開啓記錄syslog功能
# syslog-enabled no
 
#syslog的識別符號。
# syslog-ident redis
 
#日誌的來源、裝置
# syslog-facility local0
 
#數據庫的數量,預設使用的數據庫是DB 0。可以通過SELECT命令選擇一個db
databases 16
 
# redis是基於記憶體的數據庫,可以通過設定該值定期寫入磁碟。
# 註釋掉「save」這一行設定項就可以讓儲存數據庫功能失效
# 900秒(15分鐘)內至少1個key值改變(則進行數據庫儲存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行數據庫儲存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行數據庫儲存--持久化)
save 900 1
save 300 10
save 60 10000
 
#當RDB持久化出現錯誤後,是否依然進行繼續進行工作,yes:不能進行工作,no:可以繼續進行工作,可以通過info中的rdb_last_bgsave_status瞭解RDB持久化是否有錯誤
stop-writes-on-bgsave-error yes
 
#使用壓縮rdb檔案,rdb檔案壓縮使用LZF壓縮演算法,yes:壓縮,但是需要一些cpu的消耗。no:不壓縮,需要更多的磁碟空間
rdbcompression yes
 
#是否校驗rdb檔案。從rdb格式的第五個版本開始,在rdb檔案的末尾會帶上CRC64的校驗和。這跟有利於檔案的容錯性,但是在儲存rdb檔案的時候,會有大概10%的效能損耗,所以如果你追求高效能,可以關閉該設定。
rdbchecksum yes
 
#rdb檔案的名稱
dbfilename dump.rdb
 
#數據目錄,數據庫的寫入會在這個目錄。rdb、aof檔案也會寫在這個目錄
dir /data
 
 
############### 主從複製 ###############
 
#複製選項,slave複製對應的master。
# slaveof <masterip> <masterport>
 
#如果master設定了requirepass,那麼slave要連上master,需要有master的密碼才行。masterauth就是用來設定master的密碼,這樣可以在連上master後進行認證。
# masterauth <master-password>
 
#當從庫同主機失去連線或者複製正在進行,從機庫有兩種執行方式:1) 如果slave-serve-stale-data設定爲yes(預設設定),從庫會繼續響應用戶端的請求。2) 如果slave-serve-stale-data設定爲no,除去INFO和SLAVOF命令之外的任何請求都會返回一個錯誤」SYNC with master in progress」。
slave-serve-stale-data yes
 
#作爲從伺服器,預設情況下是隻讀的(yes),可以修改成NO,用於寫(不建議)。
slave-read-only yes
 
#是否使用socket方式複製數據。目前redis複製提供兩種方式,disk和socket。如果新的slave連上來或者重連的slave無法部分同步,就會執行全量同步,master會生成rdb檔案。有2種方式:disk方式是master建立一個新的進程把rdb檔案儲存到磁碟,再把磁碟上的rdb檔案傳遞給slave。socket是master建立一個新的進程,直接把rdb檔案以socket的方式發給slave。disk方式的時候,當一個rdb儲存的過程中,多個slave都能共用這個rdb檔案。socket的方式就的一個個slave順序複製。在磁碟速度緩慢,網速快的情況下推薦用socket方式。
repl-diskless-sync no
 
#diskless複製的延遲時間,防止設定爲0。一旦複製開始,節點不會再接收新slave的複製請求直到下一個rdb傳輸。所以最好等待一段時間,等更多的slave連上來。
repl-diskless-sync-delay 5
 
#slave根據指定的時間間隔向伺服器發送ping請求。時間間隔可以通過 repl_ping_slave_period 來設定,預設10秒。
# repl-ping-slave-period 10
 
#複製連線超時時間。master和slave都有超時時間的設定。master檢測到slave上次發送的時間超過repl-timeout,即認爲slave離線,清除該slave資訊。slave檢測到上次和master互動的時間超過repl-timeout,則認爲master離線。需要注意的是repl-timeout需要設定一個比repl-ping-slave-period更大的值,不然會經常檢測到超時。
# repl-timeout 60
 
#是否禁止複製tcp鏈接的tcp nodelay參數,可傳遞yes或者no。預設是no,即使用tcp nodelay。如果master設定了yes來禁止tcp nodelay設定,在把數據複製給slave的時候,會減少包的數量和更小的網路頻寬。但是這也可能帶來數據的延遲。預設我們推薦更小的延遲,但是在數據量傳輸很大的場景下,建議選擇yes。
repl-disable-tcp-nodelay no
 
#複製緩衝區大小,這是一個環形複製緩衝區,用來儲存最新複製的命令。這樣在slave離線的時候,不需要完全複製master的數據,如果可以執行部分同步,只需要把緩衝區的部分數據複製給slave,就能恢復正常複製狀態。緩衝區的大小越大,slave離線的時間可以更長,複製緩衝區只有在有slave連線的時候才分配記憶體。沒有slave的一段時間,記憶體會被釋放出來,預設1m。
# repl-backlog-size 5mb
 
#master沒有slave一段時間會釋放複製緩衝區的記憶體,repl-backlog-ttl用來設定該時間長度。單位爲秒。
# repl-backlog-ttl 3600
 
#當master不可用,Sentinel會根據slave的優先順序選舉一個master。最低的優先順序的slave,當選master。而設定成0,永遠不會被選舉。
slave-priority 100
 
#redis提供了可以讓master停止寫入的方式,如果設定了min-slaves-to-write,健康的slave的個數小於N,mater就禁止寫入。master最少得有多少個健康的slave存活才能 纔能執行寫命令。這個設定雖然不能保證N個slave都一定能接收到master的寫操作,但是能避免沒有足夠健康的slave的時候,master不能寫入來避免數據丟失。設定爲0是關閉該功能。
# min-slaves-to-write 3
 
#延遲小於min-slaves-max-lag秒的slave才認爲是健康的slave。
# min-slaves-max-lag 10
 
# 設定1或另一個設定爲0禁用這個特性。
# Setting one or the other to 0 disables the feature.
# By default min-slaves-to-write is set to 0 (feature disabled) and
# min-slaves-max-lag is set to 10.
 
 
############### 安全相關 ###############
 
#requirepass設定可以讓使用者使用AUTH命令來認證密碼,才能 纔能使用其他命令。這讓redis可以使用在不受信任的網路中。爲了保持向後的相容性,可以註釋該命令,因爲大部分使用者也不需要認證。使用requirepass的時候需要注意,因爲redis太快了,每秒可以認證15w次密碼,簡單的密碼很容易被攻破,所以最好使用一個更復雜的密碼。注意只有密碼沒有使用者名稱。
# requirepass foobared
 
#把危險的命令給修改成其他名稱。比如CONFIG命令可以重新命名爲一個很難被猜到的命令,這樣使用者不能使用,而內部工具還能接着使用。
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
 
#設定成一個空的值,可以禁止一個命令
# rename-command CONFIG ""
 
 
############### 進程限制相關 ###############
 
# 設定能連上redis的最大用戶端連線數量。預設是10000個用戶端連線。由於redis不區分連線是用戶端連線還是內部開啓檔案或者和slave連線等,所以maxclients最小建議設定到32。如果超過了maxclients,redis會給新的連線發送’max number of clients reached’,並關閉連線。
# maxclients 10000
 
#redis設定的最大記憶體容量。當記憶體滿了,需要配合maxmemory-policy策略進行處理。注意slave的輸出緩衝區是不計算在maxmemory內的。所以爲了防止主機記憶體使用完,建議設定的maxmemory需要更小一些。
# maxmemory <bytes>
 
#記憶體容量超過maxmemory後的處理策略。
#volatile-lru:利用LRU演算法移除設定過過期時間的key。
#volatile-random:隨機移除設定過過期時間的key。
#volatile-ttl:移除即將過期的key,根據最近過期時間來刪除(輔以TTL)
#allkeys-lru:利用LRU演算法移除任何key。
#allkeys-random:隨機移除任何key。
#noeviction:不移除任何key,只是返回一個寫錯誤。
#上面的這些驅逐策略,如果redis沒有合適的key驅逐,對於寫命令,還是會返回錯誤。redis將不再接收寫請求,只接收get請求。寫命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec sort。
# maxmemory-policy noeviction
 
#lru檢測的樣本數。使用lru或者ttl淘汰演算法,從需要淘汰的列表中隨機選擇sample個key,選出閒置時間最長的key移除。
# maxmemory-samples 5
 
 
############### APPEND ONLY 持久化方式 ###############
 
#預設redis使用的是rdb方式持久化,這種方式在許多應用中已經足夠用了。但是redis如果中途宕機,會導致可能有幾分鐘的數據丟失,根據save來策略進行持久化,Append Only File是另一種持久化方式,可以提供更好的持久化特性。Redis會把每次寫入的數據在接收後都寫入 appendonly.aof 檔案,每次啓動時Redis都會先把這個檔案的數據讀入記憶體裡,先忽略RDB檔案。
appendonly no
 
#aof檔名
appendfilename "appendonly.aof"
 
#aof持久化策略的設定
#no表示不執行fsync,由操作系統保證數據同步到磁碟,速度最快。
#always表示每次寫入都執行fsync,以保證數據同步到磁碟。
#everysec表示每秒執行一次fsync,可能會導致丟失這1s數據。
appendfsync everysec
 
# 在aof重寫或者寫入rdb檔案的時候,會執行大量IO,此時對於everysec和always的aof模式來說,執行fsync會造成阻塞過長時間,no-appendfsync-on-rewrite欄位設定爲預設設定爲no,是最安全的方式,不會丟失數據,但是要忍受阻塞的問題。如果對延遲要求很高的應用,這個欄位可以設定爲yes,,設定爲yes表示rewrite期間對新寫操作不fsync,暫時存在記憶體中,不會造成阻塞的問題(因爲沒有磁碟競爭),等rewrite完成後再寫入,這個時候redis會丟失數據。Linux的預設fsync策略是30秒。可能丟失30秒數據。因此,如果應用系統無法忍受延遲,而可以容忍少量的數據丟失,則設定爲yes。如果應用系統無法忍受數據丟失,則設定爲no。
no-appendfsync-on-rewrite no
 
#aof自動重寫設定。當目前aof檔案大小超過上一次重寫的aof檔案大小的百分之多少進行重寫,即當aof檔案增長到一定大小的時候Redis能夠呼叫bgrewriteaof對日誌檔案進行重寫。當前AOF檔案大小是上次日誌重寫得到AOF檔案大小的二倍(設定爲100)時,自動啓動新的日誌重寫過程。
auto-aof-rewrite-percentage 100
#設定允許重寫的最小aof檔案大小,避免了達到約定百分比但尺寸仍然很小的情況還要重寫
auto-aof-rewrite-min-size 64mb
 
#aof檔案可能在尾部是不完整的,當redis啓動的時候,aof檔案的數據被載入記憶體。重新啓動可能發生在redis所在的主機操作系統宕機後,尤其在ext4檔案系統沒有加上data=ordered選項(redis宕機或者異常終止不會造成尾部不完整現象。)出現這種現象,可以選擇讓redis退出,或者匯入儘可能多的數據。如果選擇的是yes,當截斷的aof檔案被匯入的時候,會自動發佈一個log給用戶端然後load。如果是no,使用者必須手動redis-check-aof修復AOF檔案纔可以。
aof-load-truncated yes
 
 
############### LUA SCRIPTING ###############
 
# 如果達到最大時間限制(毫秒),redis會記個log,然後返回error。當一個指令碼超過了最大時限。只有SCRIPT KILL和SHUTDOWN NOSAVE可以用。第一個可以殺沒有調write命令的東西。要是已經呼叫了write,只能用第二個命令殺。
lua-time-limit 5000
 
 
############### 叢集相關 ###############
 
#叢集開關,預設是不開啓叢集模式。
# cluster-enabled yes
 
#叢集組態檔的名稱,每個節點都有一個叢集相關的組態檔,持久化儲存叢集的資訊。這個檔案並不需要手動設定,這個組態檔有Redis生成並更新,每個Redis叢集節點需要一個單獨的組態檔,請確保與範例執行的系統中組態檔名稱不衝突
# cluster-config-file nodes-6379.conf
 
#節點互連超時的閥值。叢集節點超時毫秒數
# cluster-node-timeout 15000
 
#在進行故障轉移的時候,全部slave都會請求申請爲master,但是有些slave可能與master斷開連線一段時間了,導致數據過於陳舊,這樣的slave不應該被提升爲master。該參數就是用來判斷slave節點與master斷線的時間是否過長。判斷方法是:
#比較slave斷開連線的時間和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果節點超時時間爲三十秒, 並且slave-validity-factor爲10,假設預設的repl-ping-slave-period是10秒,即如果超過310秒slave將不會嘗試進行故障轉移 
# cluster-slave-validity-factor 10
 
#master的slave數量大於該值,slave才能 纔能遷移到其他孤立master上,如這個參數若被設爲2,那麼只有當一個主節點擁有2 個可工作的從節點時,它的一個從節點會嘗試遷移。
# cluster-migration-barrier 1
 
#預設情況下,叢集全部的slot有節點負責,叢集狀態才爲ok,才能 纔能提供服務。設定爲no,可以在slot沒有全部分配的時候提供服務。不建議開啓該設定。
# cluster-require-full-coverage yes
 
 
############### SLOW LOG 慢查詢日誌 ###############
 
###slog log是用來記錄redis執行中執行比較慢的命令耗時。當命令的執行超過了指定時間,就記錄在slow log中,slog log儲存在記憶體中,所以沒有IO操作。
#執行時間比slowlog-log-slower-than大的請求記錄到slowlog裏面,單位是微秒,所以1000000就是1秒。注意,負數時間會禁用慢查詢日誌,而0則會強制記錄所有命令。
slowlog-log-slower-than 10000
 
#慢查詢日誌長度。當一個新的命令被寫進日誌的時候,最老的那個記錄會被刪掉。這個長度沒有限制。只要有足夠的記憶體就行。你可以通過 SLOWLOG RESET 來釋放記憶體。
slowlog-max-len 128
 
############### 延遲監控 ###############
#延遲監控功能是用來監控redis中執行比較緩慢的一些操作,用LATENCY列印redis範例在跑命令時的耗時圖表。只記錄大於等於下邊設定的值的操作。0的話,就是關閉監視。預設延遲監控功能是關閉的,如果你需要開啓,也可以通過CONFIG SET命令動態設定。
latency-monitor-threshold 0
 
############### EVENT NOTIFICATION 訂閱通知 ###############
#鍵空間通知使得用戶端可以通過訂閱頻道或模式,來接收那些以某種方式改動了 Redis 數據集的事件。因爲開啓鍵空間通知功能需要消耗一些 CPU ,所以在預設設定下,該功能處於關閉狀態。
#notify-keyspace-events 的參數可以是以下字元的任意組合,它指定了伺服器該發送哪些型別的通知:
##K 鍵空間通知,所有通知以 __keyspace@__ 爲字首
##E 鍵事件通知,所有通知以 __keyevent@__ 爲字首
##g DEL 、 EXPIRE 、 RENAME 等型別無關的通用命令的通知
##$ 字串命令的通知
##l 列表命令的通知
##s 集合命令的通知
##h 雜湊命令的通知
##z 有序集合命令的通知
##x 過期事件:每當有過期鍵被刪除時發送
##e 驅逐(evict)事件:每當有鍵因爲 maxmemory 政策而被刪除時發送
##A 參數 g$lshzxe 的別名
#輸入的參數中至少要有一個 K 或者 E,否則的話,不管其餘的參數是什麼,都不會有任何 通知被分發。詳細使用可以參考http://redis.io/topics/notifications
 
notify-keyspace-events ""
 
############### ADVANCED CONFIG 高階設定 ###############
#數據量小於等於hash-max-ziplist-entries的用ziplist,大於hash-max-ziplist-entries用hash
hash-max-ziplist-entries 512
#value大小小於等於hash-max-ziplist-value的用ziplist,大於hash-max-ziplist-value用hash。
hash-max-ziplist-value 64
 
#數據量小於等於list-max-ziplist-entries用ziplist,大於list-max-ziplist-entries用list。
list-max-ziplist-entries 512
#value大小小於等於list-max-ziplist-value的用ziplist,大於list-max-ziplist-value用list。
list-max-ziplist-value 64
 
#數據量小於等於set-max-intset-entries用iniset,大於set-max-intset-entries用set。
set-max-intset-entries 512
 
#數據量小於等於zset-max-ziplist-entries用ziplist,大於zset-max-ziplist-entries用zset。
zset-max-ziplist-entries 128
#value大小小於等於zset-max-ziplist-value用ziplist,大於zset-max-ziplist-value用zset。
zset-max-ziplist-value 64
 
#value大小小於等於hll-sparse-max-bytes使用稀疏數據結構(sparse),大於hll-sparse-max-bytes使用稠密的數據結構(dense)。一個比16000大的value是幾乎沒用的,建議的value大概爲3000。如果對CPU要求不高,對空間要求較高的,建議設定到10000左右。
hll-sparse-max-bytes 3000
 
#Redis將在每100毫秒時使用1毫秒的CPU時間來對redis的hash表進行重新hash,可以降低記憶體的使用。當你的使用場景中,有非常嚴格的實時性需要,不能夠接受Redis時不時的對請求有2毫秒的延遲的話,把這項設定爲no。如果沒有這麼嚴格的實時性要求,可以設定爲yes,以便能夠儘可能快的釋放記憶體。
activerehashing yes
 
##對用戶端輸出緩衝進行限制可以強迫那些不從伺服器讀取數據的用戶端斷開連線,用來強制關閉傳輸緩慢的用戶端。
#對於normal client,第一個0表示取消hard limit,第二個0和第三個0表示取消soft limit,normal client預設取消限制,因爲如果沒有尋問,他們是不會接收數據的。
client-output-buffer-limit normal 0 0 0
#對於slave client和MONITER client,如果client-output-buffer一旦超過256mb,又或者超過64mb持續60秒,那麼伺服器就會立即斷開用戶端連線。
client-output-buffer-limit slave 256mb 64mb 60
#對於pubsub client,如果client-output-buffer一旦超過32mb,又或者超過8mb持續60秒,那麼伺服器就會立即斷開用戶端連線。
client-output-buffer-limit pubsub 32mb 8mb 60
 
#redis執行任務的頻率爲1s除以hz。
hz 10
 
#在aof重寫的時候,如果打開了aof-rewrite-incremental-fsync開關,系統會每32MB執行一次fsync。這對於把檔案寫入磁碟是有幫助的,可以避免過大的延遲峯值。
aof-rewrite-incremental-fsync yes

Redis的持久化

RDB

介紹

       在指定的時間間隔內生成記憶體中整個數據集的持久化快照。快照檔案預設被儲存在當前資料夾中,名稱爲dump.rdb,可以通過dir和dbfilename參數來修改預設值。

        Redis會單獨建立(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。  整個過程中,主進程是不進行任何的IO操作的,這就確保了極高的效能。

組態檔

# redis是基於記憶體的數據庫,可以通過設定該值定期寫入磁碟。
# 註釋掉「save」這一行設定項就可以讓儲存數據庫功能失效
# 900秒(15分鐘)內至少1個key值改變(則進行數據庫儲存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行數據庫儲存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行數據庫儲存--持久化)
save 900 1
save 300 10
save 60 10000
 
#當RDB持久化出現錯誤後,是否依然進行繼續進行工作,yes:不能進行工作,no:可以繼續進行工作,可以通過info中的rdb_last_bgsave_status瞭解RDB持久化是否有錯誤
stop-writes-on-bgsave-error yes
 
#使用壓縮rdb檔案,rdb檔案壓縮使用LZF壓縮演算法,yes:壓縮,但是需要一些cpu的消耗。no:不壓縮,需要更多的磁碟空間
rdbcompression yes
 
#是否校驗rdb檔案。從rdb格式的第五個版本開始,在rdb檔案的末尾會帶上CRC64的校驗和。這跟有利於檔案的容錯性,但是在儲存rdb檔案的時候,會有大概10%的效能損耗,所以如果你追求高效能,可以關閉該設定。
rdbchecksum yes
 
#rdb檔案的名稱
dbfilename dump.rdb
 
#數據目錄,數據庫的寫入會在這個目錄。rdb、aof檔案也會寫在這個目錄
dir /data

Fork

      fork的作用相當於複製一個與當前進程一樣的進程。但是是一個全新的進程,並作爲原進程的子進程。

觸發條件

  1. 通過配製檔案中的save條件(可自己設定)

    save 900 1
    save 300 10
    save 60 10000
    
  2. 手動通過save和bgsave命令

  • save:save時只管儲存,其他不管,全部阻塞
  • bgsave:redis會在後台非同步的進行快照操作,同時還可以響應用戶端請求。可以通過lastsave命令獲取最後一次成功執行快照的事件
  1. 通過flushall命令,也會產生dump.rdb檔案,但是裏面是空的,無意義。
  2. 通過shutdown命令,安全退出,也會生成快照檔案(和異常退出形成對比,比如:kill殺死進程的方式)

如何恢復

appendonly no
dbfilename dump.rdb
dir /var/lib/redis  #可以自行指定

appendonly 設定成no,redis啓動時會把/var/lib/redis 目錄下的dump.rdb 中的數據恢復。dir 和dbfilename 都可以設定。我測試時appendonly 設定成yes 時候不會將dump.rdb檔案中的數據恢復

優勢

  1. 恢復數據的速度很快,適合大規模的數據恢復,而又對部分數據不敏感的情況
  2. dump.db檔案是一個壓縮的二進制檔案,檔案暫用空間小

劣勢

  1. 當出現異常退出時,會丟失最後一次快照後的數據
  2. 當fork的時候,記憶體的中的數據會被克隆一份,大致兩倍的膨脹需要考慮。而且,當數據過大時,fork操作佔用過多的系統資源,造成主伺服器進程假死。

使用場景

  1. 數據備份
  2. 可容忍部分數據丟失
  3. 跨數據中心的容災備份

AOF

介紹

以日誌的形式來記錄每個寫操作,將Redis執行過的所有寫指令記錄下來(讀操作補不可記錄),只許追加檔案但不可以改寫檔案,redis啓動之初會讀取改檔案重新構建數據。儲存的是appendonly.aof檔案

aof機制 機製預設關閉,可以通過appendonly = yes參數開啓aof機制 機製,通過appendfilename = myaoffile.aof指定aof檔名稱。

aof持久化的一些策略設定

#aof持久化策略的設定
#no表示不執行fsync,由操作系統保證數據同步到磁碟,速度最快。
#always表示每次寫入都執行fsync,以保證數據同步到磁碟。
#everysec表示每秒執行一次fsync,可能會導致丟失這1s數據。
appendfsync everysec

對於觸發aof重寫機制 機製也可以通過組態檔來進行設定:

# aof自動重寫設定。當目前aof檔案大小超過上一次重寫的aof檔案大小的百分之多少進行重寫,即當aof檔案增長到一定大小的時候Redis能夠呼叫bgrewriteaof對日誌檔案進行重寫。當前AOF檔案大小是上次日誌重寫得到AOF檔案大小的二倍(設定爲100)時,自動啓動新的日誌重寫過程。
auto-aof-rewrite-percentage 100
# 設定允許重寫的最小aof檔案大小,避免了達到約定百分比但尺寸仍然很小的情況還要重寫
auto-aof-rewrite-min-size 64mb

當aop重寫時會引發重寫和持久化追加同時發生的問題,可以通過no-appendfsync-on-rewrite no進行設定

# 在aof重寫或者寫入rdb檔案的時候,會執行大量IO,此時對於everysec和always的aof模式來說,執行fsync會造成阻塞過長時間,no-appendfsync-on-rewrite欄位設定爲預設設定爲no,是最安全的方式,不會丟失數據,但是要忍受阻塞的問題。如果對延遲要求很高的應用,這個欄位可以設定爲yes,,設定爲yes表示rewrite期間對新寫操作不fsync,暫時存在記憶體中,不會造成阻塞的問題(因爲沒有磁碟競爭),等rewrite完成後再寫入,這個時候redis會丟失數據。Linux的預設fsync策略是30秒。可能丟失30秒數據。因此,如果應用系統無法忍受延遲,而可以容忍少量的數據丟失,則設定爲yes。如果應用系統無法忍受數據丟失,則設定爲no。
no-appendfsync-on-rewrite no

如何恢復

正常恢復

       將檔案放到dir指定的資料夾下,當redis啓動的時候會自動載入數據,注意:aof檔案的優先順序比dump大

異常恢復
  • 有些操作可以直接到appendonly.aof檔案裡去修改。

    eg:使用了flushall這個命令,此刻持久化檔案中就會有這麼一條命令記錄,把它刪掉就可以了

  • 寫壞的檔案可以通過 redis-check-aof --fix進行修復

優勢

  1. 根據不同的策略,可以實現每秒,每一次修改操作的同步持久化,就算在最惡劣的情況下只會丟失不會超過兩秒數據。

  2. 當檔案太大時,會觸發重寫機制 機製,確保檔案不會太大。

  3. 檔案可以簡單的讀懂

劣勢

  1. aof檔案的大小太大,就算有重寫機制 機製,但重寫所造成的阻塞問題是不可避免的
  2. aof檔案恢復速度慢

總結

  1. 如果你只希望你的數據在伺服器執行的時候存在,可以不使用任何的持久化方式

  2. 一般建議同時開啓兩種持久化方式。AOF進行數據的持久化,確保數據不會丟失太多,而RDB更適合用於備份數據庫,留着一個做萬一的手段。

  3. 效能建議:

    因爲RDB檔案只用做後備用途,建議只在slave上持久化RDB檔案,而且只要在15分鐘備份一次就夠了,只保留900 1這條規則。

    如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒數據,啓動指令碼較簡單隻load自己的AOF檔案就可以了。代價:1、帶來了持續的IO;2、AOF rewrite的最後將rewrite過程中產生的新數據寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。預設超過原大小100%大小時重寫可以改到適當的數值。

    如果不Enable AOF,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時宕掉,會丟失10幾分鐘的數據,啓動指令碼也要比較兩個Master/Slave中的RDB檔案,載入較新的那個。新浪微博就選用了這種架構。

Redis的事務

是什麼?

可以一次執行多個命令,本質是一組命令的集合。一個事物中的所有命令都會被序列化,按順序的序列執行而不會被其他命令插入,不許加塞。

能幹嘛?

一個佇列中,一次性的,順序的,排他的執行一系列命令。

常用命令

命令 描述
multi 標記一個事務的開始
exec 執行所有事務塊內的命令
discard 取消事務,放棄執行事務塊內的所有命令
watch key [key] 監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。
unwatch 取消watch命令對所有 key 的監視。

這麼玩?

  1. 正常執行

  2. 放棄事務

  3. 全體連坐

    [外連圖片轉存失敗,源站可能有防盜鏈機制 機製,建議將圖片儲存下來直接上傳(img-XUfGA0Ip-1597140519888)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20200329153701009.png)]

  4. 冤頭債主

樂觀鎖和悲觀鎖

參考

Watch監控

watch指令,類似樂觀鎖,如果key的值已經被修改了,那麼整個事務佇列都不會被執行,同時返回一個Nullmulti-bulk應答以通知呼叫者事務執行失敗。

注意:一旦執行了exec或者discard,之前加的所有監控鎖都會被取消掉了。

例子:

  • 初始化信用卡的可用餘額和欠額

  • 無加塞篡改

  • 有加塞篡改,當watch的key被修改,後面的那個事務全部執行失敗

  • unwatch

3階段

開啓:以multi開啓事務

入隊:將多個命令入隊到事務中,接到這些命令不會立刻執行,而是放到等待執行的事務佇列裏面

執行:有exec命令觸發事務

開啓
入隊
執行

3特性

單獨的隔離操作:事務中的所有命令都會序列化,按順序的執行。事務在等待執行的時候,不會被其他用戶端發送來的米命令請求打斷

沒有隔離級別的概念:佇列中的所有命令沒有提交exec之前都是不會被執行的

不保證原子性:redis中如果一條命令執行失敗,其後的命令仍然會被執行,沒有回滾,參考冤頭債主

Redis的發佈訂閱(一般不用)

發佈訂閱

Redis 發佈訂閱(pub/sub)是一種訊息通訊模式:發送者(pub)發送訊息,訂閱者(sub)接收訊息。

Redis 用戶端可以訂閱任意數量的頻道。

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個用戶端 —— client2 、 client5 和 client1 之間的關係:


當有新訊息通過 PUBLISH 命令發送給頻道 channel1 時, 這個訊息就會被髮送給訂閱它的三個用戶端:



      命令

  • subscribe channel [channel…]:訂閱一個或多個頻道的資訊
  • psubscribe pattern [pattern…]:訂閱一個或多個符合規定模式的頻道
  • publish channel message :將資訊發送到指定頻道
  • unsubscribe [channel[channel…]]:退訂頻道
  • punsubscribe [pattern[pattern…]]:退訂所有給定模式的頻道

      應用場景

構建實時的訊息系統,比如普通聊天、羣聊等功能。 1、部落格網站訂閱,當作者發佈就可以推播給粉絲 2、微信公衆號模式

Redis的複製(Master/Slave)

是什麼?

​ 就是我們常說的主從複製,主機數據更新後根據設定和策略,自動同步到備機的master/slaver機制 機製,Master以寫爲主,Slave以讀爲主

能幹嘛?

讀寫分離

容災恢復

怎麼玩?

配從(庫)不配主(庫)

從庫設定

#設定從庫
slaveof 主庫ip 主庫埠
#檢視主從資訊
info replication

​ 每次與master斷開後,都需要重新連線,除非你設定進redis.conf檔案

常用的主從方式

一主二僕

含義:就是一個Master兩個Slave

一仆二主

通過info replication檢視主從資訊

# Replication
role:master
connected_slaves:0
master_replid:f6baff9abfda12ca58048cfce4b0e2c1f4683da1
master_replid2:e8fe596d47d9d1d923d56d884b28128b78d2c1e0
master_repl_offset:0
second_repl_offset:1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:0
master_link_down_since_seconds:1585217521
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:adbec19afa734e84a333b07ea2f33c43c73fe743
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

注意:

  1. 第一次slave1 和slave2切入點,是全量複製,之後是增量複製

    一主二仆

  2. 主機可以寫,但是從機不可以寫,從機只能讀

    从机写的报错

  3. 主機shutdowm後從機待機狀態,等主機回來後,主機新增記錄從機可以順利複製

  4. 從機shutdowm後,每次與master斷開之後,都需要重新連線,除非你設定進redis.conf檔案

  5. 從機複製到的數據,會被本機持久化。就算shutdown斷開連線依然會有數據。

  6. 重新連線或者變更master,會清除之前的數據,重新建立拷貝最新的數據

薪火相傳

含義:就是上一個Slave可以是下一個slave的Master,Slave同樣可以接收其他slaves的連線和同步請求,那麼該slave作爲了鏈條中下一個的master,可以有效減輕master的寫壓力。

薪火相传

注意事項和一主二僕差不多,但注意雖然有slave是相對master,但是依然是slave [檢視](#zhu yi)

反客爲主

SLAVEOF no one

使當前數據庫停止與其他數據庫的同步,轉成主數據庫

哨兵模式(sentinel)

反客爲主的自動版,能夠後臺監控Master庫是否故障,如果故障了根據投票數自動將slave庫轉換爲主庫。一組sentinel能

同時監控多個Master。

使用步驟:

  1. 在Master對應redis.conf同目錄下新建sentinel.conf檔案,名字絕對不能錯;

  2. 設定哨兵,在sentinel.conf檔案中填入內容(可以設定多個):

    #說明:最後一個數字1,表示主機掛掉後slave投票看讓誰接替成爲主機,得票數多少後成爲主機。
    sentinel monitor 被監控數據庫名字(自己起名字) ip port 1
    
  3. 啓動哨兵模式(路徑按照自己的需求進行設定):

    redis-sentinel  /myredis/sentinel.conf
    

注意:

  1. 當master掛掉後,會通過選票進行選出下一個master。而且只有使用了sentinel.conf啓動的才能 纔能開啓選票

  2. 當原來的master後來後,很不幸變成了slave。

複製原理

  1. Slave啓動成功連線到master後會發送一個sync命令;

  2. Master接到命令啓動後的存檔進程,同時收集所有接收到的用於修改數據集命令,在後台進程執行完畢之後,master

    將傳送整個數據檔案到slave,以完成一次完全同步;

  3. 全量複製:而slave服務在數據庫檔案數據後,將其存檔並載入到記憶體中;

  4. 增量複製:Master繼續將新的所有收集到的修改命令依次傳給slave,完成同步;

  5. 但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行。

[結合這幾個注意事項](#zhu yi)

複製的缺點

​ 延時,由於所有的寫操作都是在Master上操作,然後同步更新到Slave上,所以從Master同步到Slave機器有一定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增加也會使得這個問題更加嚴重。

命令

命令 作用
slaveof 主庫ip 主庫埠 設定從庫
info replication 檢視redis主從複製的情況
slaveof no one 使當前數據庫停止與其他數據庫的同步,轉成主數據庫
sentinel monitor 被監控數據庫名字(自己起名字) 127.0.0.1 6379 1 設定哨兵,監視master
redis-sentinel /myredis/sentinel.conf 以哨兵模式啓動redis

Redis叢集

容量不夠,redis如何擴容?

併發寫操作,redis如何分攤?

什麼是Redis叢集?

Redis叢集實現了對Redis的水平擴容,即啓動N個redis節點,將整個數據庫分佈儲存在這N個節點中,每個節點儲存總數據的1/N

Redis叢集通過分割區(partition)來提供一定程度的可用性(availability):即使叢集中有一部分節點失效或者無法進行通訊,叢集也可以繼續處理命令請求。

叢集搭建

搭建看這篇文章,有效

啓動6個容器
cluster meet
匯入安裝包
修改組態檔
建立基本映象
建立節點映象
進入一個redis-cli
叢集新增節點
設定槽點
設定主從高可用

叢集命令

CLUSTER INFO 列印叢集的資訊 
CLUSTER NODES 列出叢集當前已知的所有節點(node),以及這些節點的相關資訊。  

//節點(node) 
CLUSTER MEET <ip> <port> 將 ip 和 port 所指定的節點新增到叢集當中,讓它成爲叢集的一份子。 
CLUSTER FORGET <node_id> 從叢集中移除 node_id 指定的節點。 
CLUSTER REPLICATE <node_id> 將當前節點設定爲 node_id 指定的節點的從節點。 
CLUSTER SAVECONFIG 將節點的組態檔儲存到硬盤裏面。  

//槽(slot) 
CLUSTER ADDSLOTS <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。 
CLUSTER DELSLOTS <slot> [slot ...] 移除一個或多個槽對當前節點的指派。 
CLUSTER FLUSHSLOTS 移除指派給當前節點的所有槽,讓當前節點變成一個沒有指派任何槽的節點。 
CLUSTER SETSLOT <slot> NODE <node_id> 將槽 slot 指派給 node_id 指定的節點,如果槽已經指派給另一個節點,那麼先讓另一個節點刪除該槽>,然後再進行指派。 
CLUSTER SETSLOT <slot> MIGRATING <node_id> 將本節點的槽 slot 遷移到 node_id 指定的節點中。 
CLUSTER SETSLOT <slot> IMPORTING <node_id> 從 node_id 指定的節點中匯入槽 slot 到本節點。 
CLUSTER SETSLOT <slot> STABLE 取消對槽 slot 的匯入(import)或者遷移(migrate)。  

//鍵 (key) 
CLUSTER KEYSLOT <key> 計算鍵 key 應該被放置在哪個槽上。 
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的鍵值對數量。 
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 個 slot 槽中的鍵。

節點

  1. 一個叢集至少要有三個主節點,即要有六個節點。

  2. 分配原則儘量保證每個主數據庫執行在不同的ip地址,每個從庫和主庫不在一個ip地址。

  3. 當主節點崩了,從節點能自動升爲主節點;當主節點再次恢復時,主節點變爲slave。參考哨兵模式。

  4. redis.conf有個參數cluster-require-full-coverage

    #預設情況下,叢集全部的slot有節點負責,叢集狀態才爲ok,才能 纔能提供服務。設定爲no,可以在slot沒有全部分配的時候提供服務。不建議開啓該設定。
    # cluster-require-full-coverage yes
    

SLOTS

  • 一個Redis 叢集包含16384個插槽(hash slot), 數據庫中的每個鍵都屬於這16384個插槽的其中一個,叢集使用公式CRC1 6(key)% 16384來計算鍵key屬於哪個槽(如果有組的話就只算組的部分),其中CRC16(key)語句用於計算鍵key的CRC16校驗和。

  • 叢集中的每個節點負責處理一部分插槽。 舉個例子, 如果一個叢集可以有主節點。其中:

    • 節點A負責處理0號至5500號插槽
    • 節點B負責處理5501號至11000號插槽
    • 節點C負責處理11001號至16383號插槽

             (注意:每個節點分配的插槽具體數位可能不同,當然可以通過一個小指令碼來指定)

一個疑問:爲什麼是16384(214),而不是65535(216)呢?

在redis節點發送心跳包時需要把所有的槽放到這個心跳包裡,以便讓節點知道當前叢集資訊,16384=16k,在發送心跳包時使用char進行bitmap壓縮後是2kb(16384÷8÷1024=2kb),也就是說使用2k的空間建立了16k的槽數65535=65k,壓縮後就是8kb(65536÷8÷1024=8kb),也就是說需要需要8k的心跳包。

Redis Cluster原理

  1. node1和node2首先進行握手meet,知道彼此的存在
  2. 握手成功後,兩個節點會定期發送ping/pong訊息,交換數據資訊(訊息頭,訊息體)
  3. 訊息頭裏面有個欄位:unsigned char myslots[CLUSTER_SLOTS/8],每一位代表一個槽,如果該位是1,代表該槽屬於這個節點
  4. 訊息體中會攜帶一定數量的其他節點的資訊,大約佔叢集節點總數量的十分之一,至少是3個節點的資訊。節點數量越多,訊息體內容越大。
  5. 每秒都在發送ping訊息。每秒隨機選取5個節點,找出最久沒有通訊的節點發送ping訊息。
  6. 每100毫秒都會掃描本地節點列表,如果發現節點最近一次接受pong訊息的時間大於cluster-node-timeout/2,則立即發送ping訊息

redis叢集的主節點數量基本不可能超過1000個,超過的話可能會導致網路擁堵。

在叢集中錄入值(組的概念)

redis-cli用戶端提供-c參數實現自動重定向

redis-cli -c -p 6379

不在一個slot下的鍵值,是不能使用mget,mset等多鍵操作

可以通過{}來定義組的概念,從而使key中{}內相同內容的鍵值對放到一個slot中去。

set user:{info}:name xxx
set age{info} 12
set {info}email [email protected]
hset user{info} name jiang
hset user{info} age 19
hset user{info} eamil [email protected]

#結果
172.17.0.3:6379> keys *
1) "user{info}"
2) "{info}email"
3) "user:{info}:name"
4) "age{info}"
------------------------------------------------------
172.17.0.3:6379> hkeys user{info}
1) "name"
2) "age"
3) "eamil"