如何保證Redis和數據庫雙寫一致性的問題?


Redis在國內各大公司都很熱門,比如新浪、阿里、騰訊、百度、美團、小米等。Redis也是大廠面試最愛問的,尤其是Redis客戶端、Redis高級功能、Redis持久化和開發運維常用問題探討、Redis復制的原理和優化策略、Redis分布式解決方案等。

關於Redis的這8問,你能答上來幾個?

1、為什么使用Redis

項目中使用Redis,主要考慮性能和並發。如果僅僅是分布式鎖這些,完全可以用中間件ZooKeeper等代替。

性能:

如下圖所示,在大並發的情況下,所有的請求直接訪問數據庫,數據庫會出現連接異常。這個時候,就需要使用Redis做一個緩沖操作,讓請求先訪問到Redis,而不是直接訪問數據庫。

根據交互效果的不同,響應時間沒有固定標准。在理想狀態下,我們的頁面跳轉需要在瞬間解決,對於頁內操作則需要在剎那間解決。

並發:

如下圖所示,在大並發的情況下,所有的請求直接訪問數據庫,數據庫會出現連接異常。這個時候,就需要使用Redis做一個緩沖操作,讓請求先訪問到Redis,而不是直接訪問數據庫。

2、使用Redis有什么缺點?

緩存和數據庫雙寫一致性問題
緩存雪崩問題
緩存擊穿問題
緩存的並發競爭問題

3、單線程的Redis為什么這么快?

你知道Redis是單線程工作模型嗎?

純內存操作
單線程操作,避免了頻繁的上下文切換
采用了非阻塞I/O多路復用機制

4、Redis的數據類型及使用場景

(這5種類型你用到過幾個?)

String:一般做一些復雜的計數功能的緩存;

Hash:單點登錄;

List:做簡單的消息隊列的功能;

Set:做全局去重的功能;

SortedSet:做排行榜應用,取TOPN操作;延時任務;做范圍查找。

5、Redis過期策略和內存淘汰機制?

正解:Redis采用的是定期刪除+惰性刪除策略。

為什么不用定時刪除策略?
定期刪除+惰性刪除是如何工作的呢?
采用定期刪除+惰性刪除就沒其他問題了么?

6、Redis和數據庫雙寫一致性問題

(最終一致性和強一致性)

如果對數據有強一致性要求,不能放緩存。

7、如何應對緩存穿透和緩存雪崩問題

緩存穿透:即黑客故意去請求緩存中不存在的數據,導致所有的請求都懟到數據庫上,從而數據庫連接異常。

緩存雪崩:即緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而導致數據庫連接異常。

中小型的公司一般遇不到這些問題,但是大並發的項目,流量有幾百萬左右,這兩個問題一定要深刻考慮。

8、如何解決Redis並發競爭Key問題?

這個問題大致就是,同時有多個子系統去set一個key。不太推薦使用redis的事務機制。

(1)如果對這個key操作,不要求順序

這種情況下,准備一個分布式鎖,大家去搶鎖,搶到鎖就做set操作即可。

(2)如果對這個key操作,要求順序

假設有一個key1,系統A需要將key1設置為valueA,系統B需要將key1設置為valueB,系統C需要將key1設置為valueC.

期望按照key1的value值按照 valueA-->valueB-->valueC的順序變化。這種時候我們在數據寫入數據庫的時候,需要保存一個時間戳。假設時間戳如下

系統A key 1 {valueA 3:00}
系統B key 1 {valueB 3:05}
系統C key 1 {valueC 3:10}

那么,假設這會系統B先搶到鎖,將key1設置為{valueB 3:05}。接下來系統A搶到鎖,發現自己的valueA的時間戳早於緩存中的時間戳,那就不做set操作了。以此類推。

其他方法,比如利用隊列,將set方法變成串行訪問也可以。總之,靈活變通。

煙哥彩蛋

在面試中如果碰到下列問題,如何應用上本篇的知識呢?先明確一點,我推薦的是Redis Cluster。
OK,開始舉例說明

問題1:懂Redis事務么?
正常版:Redis事務是一些列redis命令的集合,blabla…
高調版: 我們在生產上采用的是Redis Cluster集群架構,不同的key是有可能分配在不同的Redis節點上的,在這種情況下Redis的事務機制是不生效的。其次,Redis事務不支持回滾操作,簡直是雞肋!所以基本不用!

問題2:Redis的多數據庫機制,了解多少?
正常版:Redis支持多個數據庫,並且每個數據庫的數據是隔離的不能共享,單機下的redis可以支持16個數據庫(db0 ~ db15)
高調版: 在Redis Cluster集群架構下只有一個數據庫空間,即db0。因此,我們沒有使用Redis的多數據庫功能!

問題3:Redis集群機制中,你覺得有什么不足的地方嗎?
正常版: 不知道
高調版: 假設我有一個key,對應的value是Hash類型的。如果Hash對象非常大,是不支持映射到不同節點的!只能映射到集群中的一個節點上!還有就是做批量操作比較麻煩!

問題4:懂Redis的批量操作么?
正常版: 懂一點。比如mset、mget操作等,blabla
高調版: 我們在生產上采用的是Redis Cluster集群架構,不同的key會划分到不同的slot中,因此直接使用mset或者mget等操作是行不通的。

問題5:那在Redis集群模式下,如何進行批量操作?
正常版:不知道
高調版:這個問題其實可以寫一篇文章了,改天寫。這里說一種有一個很簡單的答法,足夠面試用。即:
如果執行的key數量比較少,就不用mget了,就用串行get操作。如果真的需要執行的key很多,就使用Hashtag保證這些key映射到同一台Redis節點上。簡單來說語法如下

對於key為{foo}.student1、{foo}.student2,{foo}student3,這類key一定是在同一個redis節點上。因為key中“{}”之間的字符串就是當前key的hash tags, 只有key中{ }中的部分才被用來做hash,因此計算出來的redis節點一定是同一個!

ps:如果你用的是Proxy分片集群架構,例如Codis這種,會將mget/mset的多個key拆分成多個命令發往不同得Redis實例,這里不多說。我推薦答的還是Redis Cluster。

問題6:你們有對Redis做讀寫分離么?
正常版:沒有做,至於原因額。。。額。。。額。。沒辦法了,硬着頭皮扯~
高調版:不做讀寫分離。我們用的是Redis Cluster的架構,是屬於分片集群的架構。而Redis本身在內存上操作,不會涉及IO吞吐,即使讀寫分離也不會提升太多性能,Redis在生產上的主要問題是考慮容量,單機最多10-20G,key太多降低Redis性能.因此采用分片集群結構,已經能保證了我們的性能。其次,用上了讀寫分離后,還要考慮主從一致性,主從延遲等問題,徒增業務復雜度。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM