Redis總結(上)

劉裕龍發表於2020-11-09

簡介

Redis是一個開源的高效能的非關係型資料庫(NOSQL)。是以鍵值對(key-value)的形式將資料儲存在記憶體中。提供多種鍵值對的資料型別適應不同場景下的需求。同時redis的諸多高階功能使其可以勝任任務佇列訊息佇列等不同角色。

Redis特點/優勢
a. Redis將資料存放在記憶體中,但是也提供了redis持久化的方式資料。
b. 以key-value形式儲存,有著豐富的資料型別可以適用多種開發場景(支援list,set,zset,hash等資料結構)
c. redis效能極高能讀的速度是110000次/s,寫的速度是81000次/s
d. redis具有原子性,Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支援事務,即多個操作也可維護其具有原子性。
e. Redis支援資料的備份,叢集等高可用功能。
Redis缺點
a. 耗記憶體,佔用記憶體過高。
b. 持久化。Redis直接將資料儲存到記憶體中,要將資料儲存到磁碟上,Redis可以使用兩種方式實現持久化過程。定時快照(snapshot)(RDB):每隔一段時間將整個資料庫寫到磁碟上,每次均是寫全部資料,代價非常高。第二種方式基於語句追加(aof):所有的操作指令儲存到日誌中。只追蹤變化的資料,但是追加的log可能過大,同時所有的操作均重新執行一遍,回覆速度慢。
c. 由於資料與資料之間不存在關係無法根據一個資料查詢另一資料。
Redis和mysql的關係
redis不能完全取代MySQL,Redis和MySQL各有所長,實際的開發中我們通常配合使用。mysql支援sql查詢,可以實現一些關聯的查詢以及統計;redis對記憶體要求比較高在有限的條件下不能把所有資料都放在redis,mysql偏向於存資料,redis偏向於快速取資料,但redis維護複雜的資料關係時不如mysql,所以使用mysql存基本資料我們會將經常需要使用或者經常變化的資料(熱門資料)單獨拿出來存在redis中,而在MySQL中維繫這些資料之間的關係。用redis保證高併發場景的下的高速讀寫。

基本操作

常見的資料型別
Redis常見的資料型別有:string(字串),hash(雜湊),list(列表),set(集合)及zset(sorted set:有序集合)。正因為Redis有豐富的資料型別,所以Redis能夠被應用在非常多的應用場景之下,下面我們將分別學習Redis的這幾種常用的資料型別。

String型別
string是redis最基本的型別,一個key對應一個value。string型別是二進位制安全的。意思是redis的string可以包含任何資料。比如jpg圖片或者序列化的物件 。string型別是Redis最基本的資料型別,一個鍵最大能儲存512MB。 二進位制安全是指,在傳輸資料時,保證二進位制資料的資訊保安,也就是不被篡改、破譯等,如果被攻擊,能夠及時檢測出來
二進位制安全特點:
a. 編碼、解碼發生在客戶端完成,執行效率高
b. 不需要頻繁的編解碼,不會出現亂碼

賦值語法:
SET KEY_NAME VALUE
Redis SET 命令用於設定給定 key 的值。如果 key 已經儲存值, SET 就覆寫舊值,且無視型別
SETNX key value //解決分散式鎖 方案之一
只有在 key 不存在時設定 key 的值。Setnx(SET if Not eXists) 命令在指定的 key 不存在時,為 key 設定指定的值
MSET key value [key value …]同時設定一個或多個 key-value 對

取值語法:
GET KEY_NAME Redis GET命令用於獲取指定 key 的值。如果 key 不存在,返回 nil 。如果key 儲存的值不是字串型別,返回一個錯誤。
GETRANGE key start end
用於獲取儲存在指定 key 中字串的子字串。字串的擷取範圍由 start 和 end 兩個偏移量決定(包括 start 和 end 在內)
GETBIT key offset 對 key 所儲存的字串值,獲取指定偏移量上的位(bit)

MGET key1 [key2…]獲取所有(一個或多個)給定 key 的值
GETSET語法: GETSET KEY_NAME VALUE Getset 命令用於設定指定 key 的值,並返回 key 的舊值,當 key 不存在時,返回 nil
STRLEN key 返回 key 所儲存的字串值的長度

刪除語法:
DEL KEY_Name 刪除指定的KEY,如果存在,返回值數字型別。
自增/自減:
INCR KEY_Name
Incr 命令將 key 中儲存的數字值增1。如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCR 操作
自增:INCRBY KEY_Name 增量值 Incrby 命令將 key 中儲存的數字加上指定的增量值
自減:DECR KEY_NAME 或 DECYBY KEY_NAME 減值 decR 命令將 key 中儲存的數字減1
字串拼接:APPEND KEY_NAME VALUE Append 命令用於為指定的 key 追加至未尾,如果不存在,為其賦值

應用場景:
a. String通常用於儲存單個字串或JSON字串資料
b. 因String是二進位制安全的,所以你完全可以把一個圖片檔案的內容作為字串來儲存
c. 計數器(常規key-value快取應用。常規計數: 微博數, 粉絲數)
INCR等指令本身就具有原子操作的特性,所以我們完全可以利用redis的INCR、INCRBY、DECR、 DECRBY等指令來實現原子計數的效果。假如,在某種場景下有3個客戶端同 時讀取了mynum 的值(值為2),然後對其同時進行了加1的操作,那麼,最後mynum 的值一定是5。不少網站都利用redis的這個特性來實現業務上的統計計數需求。

字典型別
Redis hash 是一個string型別的field和value的對映表,hash特別適合用於儲存物件。 Redis 中每個 hash 可以儲存 2^32 - 1 鍵值對(40多億)可以看成具有KEY和VALUE的MAP容器,該型別非常適合於儲存值物件的資訊, 如:uname,upass,age等。該型別的資料僅佔用很少的磁碟空間(相比於JSON)

賦值語法:
HSET KEY FIELD VALUE //為指定的KEY,設定FILD/VALUE
HMSET KEY FIELD VALUE [FIELD1,VALUE1]…… 同時將多個 field-value (域 -值) 對設定到雜湊表 key 中。
如何儲存物件呢?

取值語法:
HGET KEY FIELD //獲取儲存在HASH中的值,根據FIELD得到VALUE
HMGET key field[field1] //獲取key所有給定欄位的值
HGETALL key //返回HASH表中所有的欄位和值
HKEYS key //獲取所有雜湊表中的欄位
HLEN key //獲取雜湊表中欄位的數量

刪除語法:
HDEL KEY field1[field2] //刪除一個或多個HASH表欄位

其它語法:
HSETNX key field value 只有在欄位 field 不存在時,設定雜湊表欄位的值
HINCRBY key field increment
為雜湊表 key 中的指定欄位的整數值加上增量 increment 。
HINCRBYFLOAT key field increment
為雜湊表 key 中的指定欄位的浮點數值加上增量 increment 。
HEXISTS key field //檢視雜湊表 key 中,指定的欄位是否存在

應用場景
(儲存一個使用者資訊物件資料)常用於儲存一個物件為什麼不用string儲存一個物件?hash是最接近關聯式資料庫結構的資料型別,可以將資料庫一條記錄或程式中一個物件轉換成hashmap存放在redis中。使用者ID為查詢key,儲存的value使用者物件包含姓名,年齡,生日等資訊,如果用普通的key/value結構來儲存,主要有以下2種儲存方式:
第一種方式將使用者ID作為查詢key,把其他資訊封裝成一個物件以序列化的方式儲存,這種方式的缺點是,增加了序列化/反序列化的開銷,並且在需要修改其中一項資訊時,需要把整個物件取回,並且修改操作需要對併發進行保護,引入CAS等複雜問題。
第二種方法是這個使用者資訊物件有多少成員就存成多少個key-value對兒,用使用者ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和併發問題,但是使用者ID為重複儲存,如果存在大量這樣的資料,記憶體浪費還是非常可觀的。總結:Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內部儲存的Value為一個HashMap,並提供了直接存取這個Map成員的介面

Redis 鍵命令
DEL key 該命令用於在 key 存在時刪除 key。
DUMP key 序列化給定 key ,並返回被序列化的值。
EXISTS key 檢查給定 key 是否存在。
EXPIRE key seconds 為給定 key 設定過期時間(以秒計)。
PEXPIRE key milliseconds 設定 key 的過期時間以毫秒計。
TTL key 以秒為單位,返回給定 key 的剩餘生存時間(TTL, time to live)
PTTL key
以毫秒為單位返回 key 的剩餘的過期時間。
PERSIST key
移除 key 的過期時間,key 將持久保持。
KEYS pattern
查詢所有符合給定模式( pattern)的 key 。
keys 萬用字元獲取所有與pattern匹配的key,返回所有與該匹配 萬用字元:
*代表所有
? 表示代表一個字元
RENAME key newkey 修改Key的名稱
MOVE key db 將當前資料庫的 key 移動到給定的資料庫 db 當中
TYPE key 返回 key 所儲存的值的型別

應用場景
EXPIRE key seconds
a. 限時的優惠活動資訊
b. 網站資料快取(對於一些需要定時更新的資料,例如:積分排行榜)
c. 手機驗證碼
d. 限制網站訪客訪問頻率(例如:1分鐘最多訪問10次)

Key的命名建議
Redis單個key 存入512M大小
a. key不要太長,儘量不要超過1024位元組,這不僅消耗記憶體,而且會降低查詢的效
b. key也不要太短,太短的話,key的可讀性會降低;
c. 在一個專案中,key最好使用統一的命名模式,例如user:123:password;
d. key名稱區分大小寫

List型別
Redis列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素到列表的頭部(左邊)或者尾部(右邊)一個列表最多可以包含 2^32 - 1 個元素 (4294967295, 每個列表超過40億個元素) 類似JAVA中LinkedList。那這個連結串列應該是LinkedList。

賦值語法
LPUSH key value1 [value2] //將一個或多個值插入到列表頭部(從左側新增)
RPUSH key value1 [value2] //在列表中新增一個或多個值(從右側新增)
LPUSHX key value //將一個值插入到已存在的列表頭部。如果列表不在,操作無效
RPUSHX key value //一個值插入已存在的列表尾部(最右邊)。如果列表不在,操作無效。

取值語法
LLEN key //獲取列表長度
LINDEX key index //通過索引獲取列表中的元素
LRANGE key start stop //獲取列表指定範圍內的元素
注意:返回列表中指定區間內的元素,區間以偏移量 START 和 END 指定。 其中 0 表示列表的第一個元素,1 表示列表的第二個元素,以此類推。也可以使用負數下標,以 -1 表示列表的最後一個元素, -2 表示列表的倒數第二個元素,以此類推。start: 頁大小(頁數-1) stop : (頁大小頁數)-1

刪除語法
LPOP key 移出並獲取列表的第一個元素(從左側刪除)
RPOP key 移除列表的最後一個元素,返回值為移除的元素(從右側刪除)
BLPOP key1 [key2 ] timeout 移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或 發現可彈出元素為止。
例項
redis 127.0.0.1:6379> BLPOP list1 100
在以上例項中,操作會被阻塞,如果指定的列表 key list1 存在資料則會返回第一個元素,否則在等待100秒後會返回 nil 。
BRPOP key1 [key2 ] timeout
移出並獲取列表的最後一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。
LTRIM key start stop
對一個列表進行修剪(trim),就是說,讓列表只保留指定區間內的元素,不在指定區間之內的元素都將被刪除。

修改語法
LSET key index value 通過索引設定列表元素的值
LINSERT key BEFORE|AFTER world value 在列表的元素前或者後插 入元素描述:將值 value 插入到列表 key 當中,位於值 world 之前或之後。

高階語法
RPOPLPUSH source destination 移除列表的最後一個元素,並將該元素新增到另一個列表並返回 示例描述:
RPOPLPUSH a1 a2 //a1的最後元素移到a2的左側
RPOPLPUSH a1 a1 //迴圈列表,將最後元素移到最左側
BRPOPLPUSH source destination timeout 從列表中彈出一個值,將彈出的元素插入到另外一個列表中並返回它; 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。

應用場景
對資料量大的集合資料刪減
列表資料顯示、關注列表、粉絲列表、留言評價等…分頁、熱點新聞(Top5)等利用LRANGE還可以很方便的實現分頁的功能,在部落格系統中,每篇博文的評論也可以存入一個單獨的list中。
任務佇列
(list通常用來實現一個訊息佇列,而且可以確保先後順序,不必像MySQL那樣還需要通過ORDER BY來進行排序)任務佇列介紹(生產者和消費者模式): 在處理Web客戶端傳送的命令請求時,某些操作的執行時間可能會比我們預期的更長一些,通過將待執行任務的相關資訊放入佇列裡面,並在之後對佇列進行處理,使用者可以推遲執行那些需要一段時間才能能完成的操作,這種將工作交給任務處理器來執行的做法被稱為任務佇列(task queue)。

Set型別
Redis 的 Set 是 String 型別的無序集合。集合成員是唯一的,這就意味著集合中不能出現重複的資料。Redis 中集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是 O(1)。集合中最大的成員數為 2^32 - 1 (4294967295, 每個集合可儲存40多億個成員)。類似於JAVA中的 Hashtable集合redis的集合物件set的底層儲存結構特別神奇,底層使用了intset和hashtable兩種資料結構儲存的,intset我們可以理解為陣列,hashtable就是普通的雜湊表(key為set的值,value為null)。intset內部其實是一個陣列(int8_t coentents[]陣列),而且儲存資料的時候是有序的,因為在查詢資料的時候是通過二分查詢來實現的。

賦值語法:
SADD key member1 [member2] 向集合新增一個或多個成員

取值語法:
SCARD key 獲取集合的成員數
SMEMBERS key 返回集合中的所有成員
SISMEMBER key member 判斷 member 元素是否是集合 key 的成員(開發中:驗證是否存在判斷)
SRANDMEMBER key [count] 返回集合中一個或多個隨機數

刪除語法
SREM key member1 [member2] 移除集合中一個或多個成員
SPOP key [count] 移除並返回集合中的一個隨機元素
SMOVE source destination member 將 member 元素從 source 集合移動到 destination 集合

差集語法
SDIFF key1 [key2] 返回給定所有集合的差集(左側)
SDIFFSTORE destination key1 [key2] 返回給定所有集合的差集並儲存在destination 中

交集語法
SINTER key1 [key2] 返回給定所有集合的交集(共有資料)
SINTERSTORE destination key1 [key2] 返回給定所有集合的交集並儲存在 destination 中

並集語法
SUNION key1 [key2] 返回所有給定集合的並集
SUNIONSTORE destination key1 [key2] 所有給定集合的並集儲存在 destination 集合中

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

有序集合(Sorted Set)
a. Redis 有序集合和集合一樣也是string型別元素的集合,且不允許重複的成員。
b. 不同的是每個元素都會關聯一個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
c. 有序集合的成員是唯一的,但分數(score)卻可以重複。
d. 集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是O(1)。 集合中最大的成員數為 2^32 - 1 (4294967295, 每個集合可儲存40多億個成員)。Redis的ZSet是有序、且不重複 (很多時候,我們都將redis中的有序集合叫做zsets,這是因為在redis中,有序集合相關的操作指令都是以z開頭的)

賦值語法:
ZADD key score1 member1 [score2 member2]
向有序集合新增一個或多個成員,或者更新已存在成員的分數

取值語法:
ZCARD key 獲取有序集合的成員數
ZCOUNT key min max 計算在有序集合中指定區間分數的成員數
ZRANK key member 返回有序集合中指定成員的索引
ZRANGE key start stop [WITHSCORES]
通過索引區間返回有序集合成指定區間內的成員(低到高)
ZREVRANGE key start stop [WITHSCORES]
返回有序集中指定區間內的成員,通過索引,分數從高到底

刪除語法:
del key 移除集合
ZREM key member [member …] 移除有序集合中的一個或多個成員
ZREMRANGEBYRANK key start stop 移除有序集合中給定的排名區間的所有成員(第一名是0)(低到高排序)
ZREMRANGEBYSCORE key min max 移除有序集合中給定的分數區間的所有成員
應用場景常應用於:
a. 比如微博的 的實時新聞可以以發表時間作為score來儲存,這樣獲取時就是自動按時間排好序的。
b. 比如一個儲存全班同學成績的Sorted Set,其集合value可以是同學的學號,而score就可以是其考試得分,這樣在資料插入集合的時候,就已經進行了天然的排序。
c. 還可以用Sorted Set來做帶權重的佇列,比如普通訊息的score為1,重要訊息的score為2,然後工作執行緒可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。
redis多資料庫操作
Redis的資料儲存比較特殊,他並不是儲存在一個資料庫下,redis內部支援多資料庫。Redis下,資料庫是由一個整數索引標識,而不是由一個資料庫名稱。預設情況下,一個客戶端連線到資料庫0。redis配置檔案中下面的引數來控制資料庫總數:database 16 //(從0開始 1 2 3 …15)
select 資料庫//資料庫的切換 select 0/1/2…
移動資料(將當前key移動另個庫) move key名稱 資料庫
資料庫清空
flushdb //清除當前資料庫的所有key
flushall //清除整個Redis的資料庫所有key

記憶體維護策略

問題描述
redis作為優秀的中間快取件,時常會儲存大量的資料,即使採取了叢集部署來動態擴容,也應該即使的整理記憶體,維持系統效能。
Redis官方也給出警告,當記憶體不足時,Redis會根據配置的快取策略淘汰大部分keys,以保證寫入成功。當無淘汰策略時或沒有找到合適的key時,Redis直接返回out of memory錯誤。
記憶體維護解決方案
最大快取大小
maxmemory : 512G
一是為資料設定超時時間,
二是採用LRU演算法動態將不用的資料刪除。記憶體管理的一種頁面置換演算法,對於在記憶體中但又不用的資料塊(記憶體塊)叫做LRU,作業系統會根據哪些資料屬於LRU而將其移出記憶體而騰出空間來載入另外的資料。在redis中提供了以下配置可供我們選擇
LRU(The Least Recently Used,最近最久未使用演算法)(注重最近)
LRU演算法的思想是:如果一個資料在最近一段時間沒有被訪問到,那麼可以認為在將來它被訪問的可能性也很小。因此,當空間滿時,最久沒有訪問的資料最先被置換(淘汰)。
在這裡插入圖片描述

  1. 新資料插入到連結串列頭部;
  2. 每當快取命中(即快取資料被訪問),則將資料移到連結串列頭部;
  3. 當連結串列滿的時候,將連結串列尾部的資料丟棄。
    a. volatile-lru:設定超時時間的資料中,刪除最不常使用的資料.
    b. allkeys-lru:查詢所有的key中最近最不常使用的資料進行刪除,這是應用最廣泛的策略.
    c. volatile-random:在已經設定了超時的資料中隨機刪除.
    d. allkeys-random:查詢所有的key,之後隨機刪除.
    e. volatile-ttl:查詢全部設定超時時間的資料,之後排序,將馬上將要過期的資料進行刪除操作.
    f. noeviction:如果設定為該屬性,則不會進行刪除操作,如果記憶體溢位則報錯返回.
    LFU演算法是Redis4.0裡面新加的一種淘汰策略。它的全稱是Least Frequently Used,它的核心思想是根據key的最近被訪問的頻率進行淘汰,很少被訪問的優先被淘汰,被訪問的多的則被留下來。
    LFU演算法能更好的表示一個key被訪問的熱度。假如你使用的是LRU演算法,一個key很久沒有被訪問到,只剛剛是偶爾被訪問了一次,那麼它就被認為是熱點資料,不會被淘汰,而有些key將來是很有可能被訪問到的則被淘汰了。如果使用LFU演算法則不會出現這種情況,因為使用一次並不會使一個key成為熱點資料。
    LFU(Least Frequently Used ,最近最少使用演算法)也是一種常見的快取演算法。(注重頻率)
    顧名思義,LFU演算法的思想是:如果一個資料在最近一段時間很少被訪問到,那麼可以認為在將來它被訪問的可能性也很小。因此,當空間滿時,最小頻率訪問的資料最先被淘汰。
    LRU與LFU是不同的:
    LRU是最近最少使用頁面置換演算法(Least Recently Used),也就是首先淘汰最長時間未被使用的頁面!
    LFU是最近最不常用頁面置換演算法(Least Frequently Used),也就是淘汰一定時期內被訪問次數最少的頁!
    g. volatile-lfu:從所有配置了過期時間的鍵中驅逐使用頻率最少的鍵
    h. allkeys-lfu:從所有鍵中驅逐使用頻率最少的鍵
    建議:瞭解了Redis的淘汰策略之後,在平時使用應儘量主動設定/更新key的expire時間,主動刪除不活躍的舊資料,有助於提升查詢效能。

持久化

持久化方案
RDB
是redis的預設持久化機制。 RDB相當於照快照,儲存的是一種狀態。 幾十G資料經過轉二進位制和壓縮的過程轉換偽幾KB快照快照是預設的持久化方式。這種方式是就是將記憶體中資料以快照的方式寫入到二進位制檔案中,預設的檔名為dump.rdb。
快照條件:
1.伺服器正常關閉時:shutdown
2.key滿足一定條件時
save 900 1 //每900秒(15分鐘) 至少1個key發生變化,產生快照
save 300 10 //每300秒(5分鐘) 至少10個key發生變化,產生快照
save 60 10000 //每60秒(1分鐘 ) 至少10000個key發生變化,產生快照
優點:
a. 快照儲存資料極快、還原資料極快
b. 適用於災難備份
缺點:
a. 由於快照方式是在一定間隔時間做一次的,所以如果redis 意外down 掉的話,就會丟失最後一次快照後的所有修改。如果應用要求不能丟失任何修改的話,可以採用aof 持久化方式。
b. 小記憶體機器不適合使用,RDB機制符合要求就會照快照,記憶體小的話會對伺服器造成很大的壓力。

AOF
AOF持久化,預設是關閉的,預設是開啟RDB持久化appendonly yes,可以開啟AOF持久化機制,在生產環境裡面,一般來說AOF都是要開啟的,除非你說隨便丟個幾分鐘的資料也無所謂。開啟AOF持久化機制之後,redis每次接收到一條寫命令,就會寫入日誌檔案中,當然是先寫入os cache的,然後每隔一定時間再fsync一下
而且即使AOF和RDB都開啟了,redis重啟的時候,也是優先通過AOF進行資料恢復的,因為aof資料比較完整
可以配置AOF的fsync策略,有三種策略可以選擇,一種是每次寫入一條資料就執行一次fsync; 一種是每隔一秒執行一次fsync; 一種是不主動執行fsync
AOF 比快照方式有更好的持久化性,是由於在使用aof 持久化方式時,redis 會將每一個收到的寫命令都通過write 函式追加到檔案中(預設是appendonly.aof)。當redis 重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。

有三種方式如下(預設是:每秒 fsync 一次)
a. # appendfsync always //收到寫命令就立即寫入磁碟,最慢,但是保證完全的持久化
b. appendfsync everysec //每秒鐘寫入磁碟一次,在效能和持久化方面做了很好的折中
c. # appendfsync no //完全依賴 os,效能最好,持久化沒保證

AOF產生的問題
aof 的方式也同時帶來了另一個問題。持久化檔案會變的越來越大。例如我們呼叫 incr test命令 100 次,檔案中必須儲存全部的 100 條命令,其實有 99 條都是多餘的。
應該如何解決?
在這裡插入圖片描述
RDB和AOF如何選擇
a. 不要僅僅使用RDB,因為那樣會導致你丟失很多資料
b.也不要僅僅使用AOF,因為那樣有兩個問題,第一,你通過AOF做冷備,沒有RDB做冷備,來的恢復速度更快; 第二,RDB每次簡單粗暴生成資料快照,更加健壯,可以避免AOF這種複雜的備份和恢復機制的bug
c. 綜合使用AOF和RDB兩種持久化機制,用AOF來保證資料不丟失,作為資料恢復的第一選擇; 用RDB來做不同程度的冷備,在AOF檔案都丟失或損壞不可用的時候,還可以使用RDB來進行快速的資料恢復
持久化具體使用方式總結:
RDB持久化方式能夠維持在指定時間間隔能對你的資料進行快照儲存AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到末尾。redis還能對AOF檔案進行後臺重寫,使得AOF檔案體積不至於過大。
• 只做快取:如果你只希望你的資料在伺服器執行的時候存在,可以不開啟任何持久化方式
• 同時開啟RDB和AOF:在這種情況下當redis重啟的時候優先載入AOF檔案來恢復原始資料,因為在通常情況下AOF檔案儲存的資料要比RDB檔案儲存的資料集要完整。RDB的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案。
• 只使用AOF?
建議不要,因為RDB更適合備分資料庫(AOF在不斷變換不好備分)快速重啟,而且不會有AOF可能潛在的Bug,留著做一個萬一的手段。
冷備份
冷備份(cold backup),也被稱為離線備份,是指在關閉資料庫並且資料庫不能更新的狀況下進行的資料庫完整備份。並可對資料進行指定恢復
1、 是非常快速的備份方法(只需拷檔案)
2、 容易歸檔(簡單拷貝即可)
3、 容易恢復到某個時間點上(只需將檔案再拷貝回去)
4、 能與歸檔方法相結合,做資料庫“最佳狀態”的恢復。
5、 低度維護,高度安全。

事務

Redis 事務簡介
Redis 事務可以一次執行多個命令,(按順序地序列化執行,執行中不會被其它命令插入,不許加塞)Redis 事務可以一次執行多個命令(允許在一次單獨的步驟中執行一組命令)。
Redis事務的操作命令
在這裡插入圖片描述
一個事務從開始到執行會經歷三個階段:
開始事務。
命令入隊。
執行事務。

示例1
第一步開啟兩個終端,並在其中一個終端種設定兩個賬戶的初始值a賬戶100元,b賬戶50元。
在這裡插入圖片描述
轉帳功能,A向B帳號轉帳50元
一個事務的例子,它先以 MULTI 開始一個事務,然後將多個命令入隊到事務中,最後由 EXEC 命令觸發事務。
在這裡插入圖片描述
WATCH/UNWATCH
WATCH
WATCH key [key …] 監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。
需求:某一帳戶在一事務內進行操作,在提交事務前,另一個程式對該帳戶進行操作。
UNWATCH
Redis Unwatch 命令用於取消 WATCH 命令對所有 key 的監視。如果在執行WATCH命令之後,EXEC命令或DISCARD命令先被執行的話,那就不需要再執行UNWATCH了。

Redis 錯誤處理
DISCARD
如果我們命令執行之後發現執行錯了之後怎麼辦呢?我們可以放棄對事務的執行。
DISCARD放棄佇列執行
在這裡插入圖片描述

a. 輸入Multi命令開始,輸入的命令都會依次進入命令佇列中,但不會執行
b. 直到輸入Exec後,Redis會將之前的命令佇列中的命令依次執行。
c. 命令佇列的過程中可以通過discard來放棄佇列執行
邏輯錯誤處理
如果執行的某個執行的邏輯有問題但是redis並沒有報出bug,則只有邏輯有錯的命令不會被執行,而其它的命令都會執行,不會回滾。(不會回滾是redis的特點)
在這裡插入圖片描述

報告型錯誤處理
事務的錯誤處理:
佇列中的某個命令出現了報告錯誤,執行時整個的所有佇列都會被取消。
在這裡插入圖片描述

由於之前的錯誤,事務執行失敗
那麼如果是多個客戶端對redis進行操作,我們如何保證單個事務的執行是安全可靠的?首先由於redis是單執行緒執行的所以其實不會引發多執行緒帶來的問題。我在這所想避免的是一個事務在執行完之前不允許其他事務打斷,由於是單執行緒其實打斷也是無所謂的,只是我們可以手動設定不讓這樣的事情發生。下面就是對這種情況做出演示:

事務相關總結
一個事務從開始到執行會經歷以下三個階段:開始事務。命令入隊。執行事務。我們無法回滾如果發現事務中的某一步執行錯了,只能結束掉整個事務。由於redis是單執行緒的所以我們不用擔心多執行緒引發的相關問題,所以redis的事務不涉及MySQL中的隔離性問題。有時事務在執行的時候我們不希望被別的事務干擾可以使用watch方法。

應用場景
一組命令必須同時都執行,或者都不執行。
我們想要保證一組命令在執行

資料一致性

問題描述
由於redis對所儲存的資料無法維護資料之間的關係,也就無法做到聯合查詢或者子查詢。但是在實際的使用中我們有時是需要維護資料之間的關係的。Mysql由無法做到快速的查詢和修改資料。Redis直接將資料儲存到記憶體中,要將資料儲存到磁碟上,Redis可以使用兩種方式實現持久化過程。定時快照(snapshot):每隔一段時間將整個資料庫寫到磁碟上,每次均是寫全部資料,代價非常高。第二種方式基於語句追加(aof):只追蹤變化的資料,但是追加的log可能過大,同時所有的操作均重新執行一遍,回覆速度慢。 耗記憶體,佔用記憶體過高。Redis存在這些缺點,也是從另外一個角度說明了Redis無法完全取代MySQL,他需要和MySQL配合使用。那如果配合使用資料一致性就是一個需要解決的問題。
解決方案
實時同步
對強一致要求比較高的,應採用實時同步方案,即查詢快取查詢不到再從DB查詢,儲存到快取;更新快取時,先更新資料庫,再將快取的設定過期(建議不要去更新快取內容,直接設定快取過期)。
定時同步
設定一個定時任務,每天凌晨4:00的時候同步資料。
非同步佇列
對於併發程度較高的,可採用非同步佇列的方式同步,可採用kafka等訊息中介軟體處理訊息生產和消費。

在這裡插入圖片描述

相關文章