<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          整理好了,Redis面試題

          共 11836字,需瀏覽 24分鐘

           ·

          2021-08-18 10:35

          1、談下你對 Redis 的了解?

          Redis(全稱:Remote Dictionary Server 遠程字典服務)是一個開源的使用 ANSI C 語言編寫、支持網(wǎng)絡、可基于內存亦可持久化的日志型、Key-Value 數(shù)據(jù)庫,并提供多種語言的 API。

          2、Redis 一般都有哪些使用場景?

          Redis 適合的場景

          1. 緩存:減輕 MySQL 的查詢壓力,提升系統(tǒng)性能;

          2. 排行榜:利用 Redis 的 SortSet(有序集合)實現(xiàn);

          3. 計算器/限速器:利用 Redis 中原子性的自增操作,我們可以統(tǒng)計類似用戶點贊數(shù)、用戶訪問數(shù)等。這類操作如果用 MySQL,頻繁的讀寫會帶來相當大的壓力;限速器比較典型的使用場景是限制某個用戶訪問某個 API 的頻率,常用的有搶購時,防止用戶瘋狂點擊帶來不必要的壓力;

          4. 好友關系:利用集合的一些命令,比如求交集、并集、差集等。可以方便解決一些共同好友、共同愛好之類的功能;

          5. 消息隊列:除了 Redis 自身的發(fā)布/訂閱模式,我們也可以利用 List 來實現(xiàn)一個隊列機制,比如:到貨通知、郵件發(fā)送之類的需求,不需要高可靠,但是會帶來非常大的 DB 壓力,完全可以用 List 來完成異步解耦;

          6. Session 共享:Session 是保存在服務器的文件中,如果是集群服務,同一個用戶過來可能落在不同機器上,這就會導致用戶頻繁登陸;采用 Redis 保存 Session 后,無論用戶落在那臺機器上都能夠獲取到對應的 Session 信息。

          Redis 不適合的場景

          數(shù)據(jù)量太大、數(shù)據(jù)訪問頻率非常低的業(yè)務都不適合使用 Redis,數(shù)據(jù)太大會增加成本,訪問頻率太低,保存在內存中純屬浪費資源。

          3、Redis 有哪些常見的功能?

          1. 數(shù)據(jù)緩存功能

          2. 分布式鎖的功能

          3. 支持數(shù)據(jù)持久化

          4. 支持事務

          5. 支持消息隊列

          4、Redis 支持的數(shù)據(jù)類型有哪些?

          • 1. string 字符串

          字符串類型是 Redis 最基礎的數(shù)據(jù)結構,首先鍵是字符串類型,而且其他幾種結構都是在字符串類型基礎上構建的。字符串類型實際上可以是字符串:簡單的字符串、XML、JSON;數(shù)字:整數(shù)、浮點數(shù);二進制:圖片、音頻、視頻。

          使用場景:緩存、計數(shù)器、共享 Session、限速。

          • 2. Hash(哈希)

          在 Redis中哈希類型是指鍵本身是一種鍵值對結構,如 value={{field1,value1},……{fieldN,valueN}}

          使用場景:哈希結構相對于字符串序列化緩存信息更加直觀,并且在更新操作上更加便捷。所以常常用于用戶信息等管理,但是哈希類型和關系型數(shù)據(jù)庫有所不同,哈希類型是稀疏的,而關系型數(shù)據(jù)庫是完全結構化的,關系型數(shù)據(jù)庫可以做復雜的關系查詢,而 Redis 去模擬關系型復雜查詢開發(fā)困難且維護成本高。

          • 3. List(列表)

          列表類型是用來儲存多個有序的字符串,列表中的每個字符串成為元素,一個列表最多可以儲存 2 ^ 32 - 1 個元素,在 Redis 中,可以隊列表兩端插入和彈出,還可以獲取指定范圍的元素列表、獲取指定索引下的元素等,列表是一種比較靈活的數(shù)據(jù)結構,它可以充當棧和隊列的角色。

          使用場景:Redis 的 lpush + brpop 命令組合即可實現(xiàn)阻塞隊列,生產(chǎn)者客戶端是用 lpush 從列表左側插入元素,多個消費者客戶端使用 brpop 命令阻塞式的“搶”列表尾部的元素,多個客戶端保證了消費的負載均衡和高可用性。


          • 4. Set(集合)

          集合類型也是用來保存多個字符串的元素,但和列表不同的是集合中不允許有重復的元素,并且集合中的元素是無序的,不能通過索引下標獲取元素,Redis 除了支持集合內的增刪改查,同時還支持多個集合取交集、并集、差集。合理的使用好集合類型,能在實際開發(fā)中解決很多實際問題。

          使用場景:如:一個用戶對娛樂、體育比較感興趣,另一個可能對新聞感興趣,這些興趣就是標簽,有了這些數(shù)據(jù)就可以得到同一標簽的人,以及用戶的共同愛好的標簽,這些數(shù)據(jù)對于用戶體驗以及曾強用戶粘度比較重要。

          • 5. zset(sorted set:有序集合)

          有序集合和集合有著必然的聯(lián)系,它保留了集合不能有重復成員的特性,但不同得是,有序集合中的元素是可以排序的,但是它和列表的使用索引下標作為排序依據(jù)不同的是:它給每個元素設置一個分數(shù),作為排序的依據(jù)。

          使用場景:排行榜是有序集合經(jīng)典的使用場景。例如:視頻網(wǎng)站需要對用戶上傳的文件做排行榜,榜單維護可能是多方面:按照時間、按照播放量、按照獲得的贊數(shù)等。

          5、Redis 為什么這么快?

          1. 完全基于內存,絕大部分請求是純粹的內存操作,非常快速;

          2. 數(shù)據(jù)結構簡單,對數(shù)據(jù)操作也簡單;

          3. 采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現(xiàn)死鎖而導致的性能消耗;

          4. 使用多路 I/O 復用模型,非阻塞 IO。

          6、什么是緩存穿透?怎么解決?

          緩存穿透是指查詢一個一定不存在的數(shù)據(jù),由于緩存是不命中時需要從數(shù)據(jù)庫查詢,查不到數(shù)據(jù)則不寫入緩存,這將導致這個不存在的數(shù)據(jù)每次請求都要到數(shù)據(jù)庫去查詢,造成緩存穿透。

          解決辦法:

          1、緩存空對象:如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。

          緩存空對象帶來的問題:

          1. 空值做了緩存,意味著緩存中存了更多的鍵,需要更多的內存空間,比較有效的方法是針對這類數(shù)據(jù)設置一個較短的過期時間,讓其自動剔除。

          2. 緩存和存儲的數(shù)據(jù)會有一段時間窗口的不一致,可能會對業(yè)務有一定影響。例如:過期時間設置為 5分鐘,如果此時存儲添加了這個數(shù)據(jù),那此段時間就會出現(xiàn)緩存和存儲數(shù)據(jù)的不一致,此時可以利用消息系統(tǒng)或者其他方式清除掉緩存層中的空對象。

          2、布隆過濾器:將所有可能存在的數(shù)據(jù)哈希到一個足夠大的 bitmap 中,一個一定不存在的數(shù)據(jù)會被這個 bitmap 攔截掉,從而避免了對底層存儲系統(tǒng)的查詢壓力。

          7、什么是緩存雪崩?該如何解決?

          如果緩存集中在一段時間內失效,發(fā)生大量的緩存穿透,所有的查詢都落在數(shù)據(jù)庫上,造成了緩存雪崩。

          解決辦法:

          1. 加鎖排隊:在緩存失效后,通過加鎖或者隊列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個 key 只允許一個線程查詢數(shù)據(jù)和寫緩存,其他線程等待;

          2. 數(shù)據(jù)預熱:可以通過緩存 reload 機制,預先去更新緩存,再即將發(fā)生大并發(fā)訪問前手動觸發(fā)加載緩存不同的 key,設置不同的過期時間,讓緩存失效的時間點盡量均勻;

          3. 做二級緩存,或者雙緩存策略:Cache1 為原始緩存,Cache2 為拷貝緩存,Cache1 失效時,可以訪問 Cache2,Cache1 緩存失效時間設置為短期,Cache2 設置為長期。

          4. 在緩存的時候給過期時間加上一個隨機值,這樣就會大幅度的減少緩存在同一時間過期。

          8、 怎么保證緩存和數(shù)據(jù)庫數(shù)據(jù)的一致性?

          1. 從理論上說,只要我們設置了合理的鍵的過期時間,我們就能保證緩存和數(shù)據(jù)庫的數(shù)據(jù)最終是一致的。因為只要緩存數(shù)據(jù)過期了,就會被刪除。隨后讀的時候,因為緩存里沒有,就可以查數(shù)據(jù)庫的數(shù)據(jù),然后將數(shù)據(jù)庫查出來的數(shù)據(jù)寫入到緩存中。除了設置過期時間,我們還需要做更多的措施來盡量避免數(shù)據(jù)庫與緩存處于不一致的情況發(fā)生。

          2. 新增、更改、刪除數(shù)據(jù)庫操作時同步更新 Redis,可以使用事物機制來保證數(shù)據(jù)的一致性。

          9、Redis 持久化有幾種方式?

          持久化就是把內存的數(shù)據(jù)寫到磁盤中去,防止服務宕機了內存數(shù)據(jù)丟失。Redis 提供了兩種持久化方式:RDB(默認) 和 AOF。

          RDB

          RDB 是 Redis DataBase 的縮寫。按照一定的時間周期策略把內存的數(shù)據(jù)以快照的形式保存到硬盤的二進制文件。即 Snapshot 快照存儲,對應產(chǎn)生的數(shù)據(jù)文件為 dump.rdb,通過配置文件中的 save 參數(shù)來定義快照的周期。核心函數(shù):rdbSave(生成 RDB 文件)和 rdbLoad(從文件加載內存)兩個函數(shù)。

          AOF

          AOF 是 Append-only file 的縮寫。Redis會將每一個收到的寫命令都通過 Write 函數(shù)追加到文件最后,類似于 MySQL 的 binlog。當 Redis 重啟是會通過重新執(zhí)行文件中保存的寫命令來在內存中重建整個數(shù)據(jù)庫的內容。每當執(zhí)行服務器(定時)任務或者函數(shù)時,flushAppendOnlyFile 函數(shù)都會被調用, 這個函數(shù)執(zhí)行以下兩個工作:

          • WRITE:根據(jù)條件,將 aof_buf 中的緩存寫入到 AOF 文件;

          • SAVE:根據(jù)條件,調用 fsync 或 fdatasync 函數(shù),將 AOF 文件保存到磁盤中。

          RDB 和 AOF 的區(qū)別:

          1. AOF 文件比 RDB 更新頻率高,優(yōu)先使用 AOF 還原數(shù)據(jù);

          2. AOF比 RDB 更安全也更大;

          3. RDB 性能比 AOF 好;

          4. 如果兩個都配了優(yōu)先加載 AOF。

          10、Redis 怎么實現(xiàn)分布式鎖?

          Redis 為單線程模式,采用隊列模式將并發(fā)訪問變成串行訪問,且多客戶端對 Redis 的連接并不存在競爭關系。Redis 中可以使用 SETNX 命令實現(xiàn)分布式鎖。一般使用 setnx(set if not exists) 指令,只允許被一個程序占有,使用完調用 del 釋放鎖。

          11、Redis 內存淘汰策略有哪些?

          1. volatile-lru:從已設置過期時間的數(shù)據(jù)集(server. db[i]. expires)中挑選最近最少使用的數(shù)據(jù)淘汰;

          2. volatile-ttl:從已設置過期時間的數(shù)據(jù)集(server. db[i]. expires)中挑選將要過期的數(shù)據(jù)淘汰。

          3. volatile-random:從已設置過期時間的數(shù)據(jù)集(server. db[i]. expires)中任意選擇數(shù)據(jù)淘汰。

          4. allkeys-lru:從數(shù)據(jù)集(server. db[i]. dict)中挑選最近最少使用的數(shù)據(jù)淘汰。

          5. allkeys-random:從數(shù)據(jù)集(server. db[i]. dict)中任意選擇數(shù)據(jù)淘汰。

          6. no-enviction(驅逐):禁止驅逐數(shù)據(jù)。

          12、Redis 常見性能問題和解決方案?

          1. Master 最好不要做任何持久化工作,如 RDB 內存快照和 AOF 日志文件。如果數(shù)據(jù)比較重要,某個 Slave 開啟 AOF 備份數(shù)據(jù),策略設置為每秒同步一次;

          2. 為了主從復制的速度和連接的穩(wěn)定性, Master 和 Slave 最好在同一個局域網(wǎng)內;

          3. 主從復制不要用圖狀結構,用單向鏈表結構更為穩(wěn)定,即:Master <- Slave1 <- Slave2 <- Slave3…

          13、Redis的過期鍵的刪除策略

          我們都知道,Redis是key-value數(shù)據(jù)庫,我們可以設置Redis中緩存的key的過期時間。Redis的過期策略就是指當Redis中緩存的key過期了,Redis如何處理。

          過期策略通常有以下三種:

          • 定時過期:每個設置過期時間的key都需要創(chuàng)建一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的數(shù)據(jù),對內存很友好;但是會占用大量的CPU資源去處理過期的數(shù)據(jù),從而影響緩存的響應時間和吞吐量。

          • 惰性過期:只有當訪問一個key時,才會判斷該key是否已過期,過期則清除。該策略可以最大化地節(jié)省CPU資源,卻對內存非常不友好。極端情況可能出現(xiàn)大量的過期key沒有再次被訪問,從而不會被清除,占用大量內存。

          • 定期過期:每隔一定的時間,會掃描一定數(shù)量的數(shù)據(jù)庫的expires字典中一定數(shù)量的key,并清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和內存資源達到最優(yōu)的平衡效果。
            (expires字典會保存所有設置了過期時間的key的過期時間數(shù)據(jù),其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis集群中保存的所有鍵。)

          Redis中同時使用了惰性過期和定期過期兩種過期策略。

          14、我們知道通過expire來設置key 的過期時間,那么對過期的數(shù)據(jù)怎么處理呢?

          除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇),我們還可以根據(jù)具體的業(yè)務需求進行自定義的緩存淘汰,常見的策略有兩種:

          1. 定時去清理過期的緩存;

          2. 當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。

          兩者各有優(yōu)劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,大家可以根據(jù)自己的應用場景來權衡。

          15、Hash 沖突怎么辦?

          Redis 通過鏈式哈希解決沖突:也就是同一個 桶里面的元素使用鏈表保存。但是當鏈表過長就會導致查找性能變差可能,所以 Redis 為了追求快,使用了兩個全局哈希表。用于 rehash 操作,增加現(xiàn)有的哈希桶數(shù)量,減少哈希沖突。

          開始默認使用 「hash 表 1 」保存鍵值對數(shù)據(jù),「hash 表 2」 此刻沒有分配空間。當數(shù)據(jù)越來越多觸發(fā) rehash 操作,則執(zhí)行以下操作:

          1. 給 「hash 表 2 」分配更大的空間;

          2. 將 「hash 表 1 」的數(shù)據(jù)重新映射拷貝到 「hash 表 2」 中;

          3. 釋放 「hash 表 1」 的空間。

          值得注意的是,將 hash 表 1 的數(shù)據(jù)重新映射到 hash 表 2 的過程中并不是一次性的,這樣會造成 Redis 阻塞,無法提供服務。

          而是采用了漸進式 rehash,每次處理客戶端請求的時候,先從「 hash 表 1」 中第一個索引開始,將這個位置的 所有數(shù)據(jù)拷貝到 「hash 表 2」 中,就這樣將 rehash 分散到多次請求過程中,避免耗時阻塞。

          16、什么是 RDB 內存快照?

          在 Redis 執(zhí)行「寫」指令過程中,內存數(shù)據(jù)會一直變化。所謂的內存快照,指的就是 Redis 內存中的數(shù)據(jù)在某一刻的狀態(tài)數(shù)據(jù)。

          好比時間定格在某一刻,當我們拍照的,通過照片就能把某一刻的瞬間畫面完全記錄下來。

          Redis 跟這個類似,就是把某一刻的數(shù)據(jù)以文件的形式拍下來,寫到磁盤上。這個快照文件叫做 RDB 文件,RDB 就是 Redis DataBase 的縮寫。

          在做數(shù)據(jù)恢復時,直接將 RDB 文件讀入內存完成恢復。

          17、在生成 RDB 期間,Redis 可以同時處理寫請求么?

          可以的,Redis 使用操作系統(tǒng)的多進程寫時復制技術 COW(Copy On Write) 來實現(xiàn)快照持久化,保證數(shù)據(jù)一致性。

          Redis 在持久化時會調用 glibc 的函數(shù)fork產(chǎn)生一個子進程,快照持久化完全交給子進程來處理,父進程繼續(xù)處理客戶端請求。

          當主線程執(zhí)行寫指令修改數(shù)據(jù)的時候,這個數(shù)據(jù)就會復制一份副本, bgsave 子進程讀取這個副本數(shù)據(jù)寫到 RDB 文件。

          這既保證了快照的完整性,也允許主線程同時對數(shù)據(jù)進行修改,避免了對正常業(yè)務的影響。

          18、如何實現(xiàn)數(shù)據(jù)盡可能少丟失又能兼顧性能呢?

          重啟 Redis 時,我們很少使用 rdb 來恢復內存狀態(tài),因為會丟失大量數(shù)據(jù)。我們通常使用 AOF 日志重放,但是重放 AOF 日志性能相對 rdb 來說要慢很多,這樣在 Redis 實例很大的情況下,啟動需要花費很長的時間。

          Redis 4.0 為了解決這個問題,帶來了一個新的持久化選項——混合持久化。將 rdb 文件的內容和增量的 AOF 日志文件存在一起。這里的 AOF 日志不再是全量的日志,而是自持久化開始到持久化結束的這段時間發(fā)生的增量 AOF 日志,通常這部分 AOF 日志很小。

          于是在 Redis 重啟的時候,可以先加載 rdb 的內容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重啟效率因此大幅得到提升。

          19、你知道 哨兵集群原理么?

          哨兵是 Redis 的一種運行模式,它專注于對 Redis 實例(主節(jié)點、從節(jié)點)運行狀態(tài)的監(jiān)控,并能夠在主節(jié)點發(fā)生故障時通過一系列的機制實現(xiàn)選主及主從切換,實現(xiàn)故障轉移,確保整個 Redis 系統(tǒng)的可用性

          他的架構圖如下:

          Redis 哨兵具備的能力有如下幾個:

          • 監(jiān)控:持續(xù)監(jiān)控 master 、slave 是否處于預期工作狀態(tài)。

          • 自動切換主庫:當 Master 運行故障,哨兵啟動自動故障恢復流程:從 slave 中選擇一臺作為新 master。

          • 通知:讓 slave 執(zhí)行 replicaof ,與新的 master 同步;并且通知客戶端與新 master 建立連接。

          20、什么是 Cluster 集群?

          Redis 集群是一種分布式數(shù)據(jù)庫方案,集群通過分片(sharding)來進行數(shù)據(jù)管理(「分治思想」的一種實踐),并提供復制和故障轉移功能。

          將數(shù)據(jù)劃分為 16384 的 slots,每個節(jié)點負責一部分槽位。槽位的信息存儲于每個節(jié)點中。

          它是去中心化的,如圖所示,該集群由三個 Redis 節(jié)點組成,每個節(jié)點負責整個集群的一部分數(shù)據(jù),每個節(jié)點負責的數(shù)據(jù)多少可能不一樣。

          三個節(jié)點相互連接組成一個對等的集群,它們之間通過 Gossip協(xié)議相互交互集群信息,最后每個節(jié)點都保存著其他節(jié)點的 slots 分配情況。

          使用 Redis Cluster 集群,主要解決了大數(shù)據(jù)量存儲導致的各種慢問題

          21、哈希槽又是如何映射到 Redis 實例上呢?

          1. 根據(jù)鍵值對的 key,使用 CRC16 算法,計算出一個 16 bit 的值;

          2. 將 16 bit 的值對 16384 執(zhí)行取模,得到 0 ~ 16383 的數(shù)表示 key 對應的哈希槽。

          3. 根據(jù)該槽信息定位到對應的實例。

          鍵值對數(shù)據(jù)、哈希槽、Redis 實例之間的映射關系如下:

          22、Cluster 如何實現(xiàn)故障轉移?

          Redis 集群節(jié)點采用 Gossip 協(xié)議來廣播自己的狀態(tài)以及自己對整個集群認知的改變。比如一個節(jié)點發(fā)現(xiàn)某個節(jié)點失聯(lián)了 (PFail),它會將這條信息向整個集群廣播,其它節(jié)點也就可以收到這點失聯(lián)信息。

          如果一個節(jié)點收到了某個節(jié)點失聯(lián)的數(shù)量 (PFail Count) 已經(jīng)達到了集群的大多數(shù),就可以標記該節(jié)點為確定下線狀態(tài) (Fail),然后向整個集群廣播,強迫其它節(jié)點也接收該節(jié)點已經(jīng)下線的事實,并立即對該失聯(lián)節(jié)點進行主從切換。

          23、Redis如何做內存優(yōu)化?

          可以好好利用Hash,list,sorted set,set等集合類型數(shù)據(jù),因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。盡可能使用散列表(hashes),散列表(是說散列表里面存儲的數(shù)少)使用的內存非常小,所以你應該盡可能的將你的數(shù)據(jù)模型抽象到一個散列表里面。比如你的web系統(tǒng)中有一個用戶對象,不要為這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的所有信息存儲到一張散列表里面

          24、Redis線程模型

          Redis基于Reactor模式開發(fā)了網(wǎng)絡事件處理器,這個處理器被稱為文件事件處理器(file event handler)。它的組成結構為4部分:多個套接字、IO多路復用程序、文件事件分派器、事件處理器。因為文件事件分派器隊列的消費是單線程的,所以Redis才叫單線程模型。

          • 文件事件處理器使用 I/O 多路復用(multiplexing)程序來同時監(jiān)聽多個套接字, 并根據(jù)套接字目前執(zhí)行的任務來為套接字關聯(lián)不同的事件處理器。

          • 當被監(jiān)聽的套接字準備好執(zhí)行連接應答(accept)、讀?。╮ead)、寫入(write)、關閉(close)等操作時, 與操作相對應的文件事件就會產(chǎn)生, 這時文件事件處理器就會調用套接字之前關聯(lián)好的事件處理器來處理這些事件。

          雖然文件事件處理器以單線程方式運行, 但通過使用 I/O 多路復用程序來監(jiān)聽多個套接字, 文件事件處理器既實現(xiàn)了高性能的網(wǎng)絡通信模型, 又可以很好地與 redis 服務器中其他同樣以單線程方式運行的模塊進行對接, 這保持了 Redis 內部單線程設計的簡單性。

          25、Redis事務及其相關面試題

          什么是事務?

          事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執(zhí)行。事務在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。

          事務是一個原子操作:事務中的命令要么全部被執(zhí)行,要么全部都不執(zhí)行。

          Redis事務的概念

          Redis 事務的本質是通過MULTI、EXEC、WATCH等一組命令的集合。事務支持一次執(zhí)行多個命令,一個事務中所有命令都會被序列化。在事務執(zhí)行過程,會按照順序串行化執(zhí)行隊列中的命令,其他客戶端提交的命令請求不會插入到事務執(zhí)行命令序列中。

          總結說:redis事務就是一次性、順序性、排他性的執(zhí)行一個隊列中的一系列命令。

          搜索公眾號 Java面試題精選,回復“面試資料”,送你一份Java面試寶典.pdf

          Redis事務的三個階段

          1. 事務開始 MULTI

          2. 命令入隊

          3. 事務執(zhí)行 EXEC

          事務執(zhí)行過程中,如果服務端收到有EXEC、DISCARD、WATCH、MULTI之外的請求,將會把請求放入隊列中排

          事務管理(ACID)概述

          • 原子性(Atomicity)

          原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發(fā)生,要么都不發(fā)生。

          • 一致性(Consistency)

          事務前后數(shù)據(jù)的完整性必須保持一致。

          • 隔離性(Isolation)

          多個事務并發(fā)執(zhí)行時,一個事務的執(zhí)行不應影響其他事務的執(zhí)行

          • 持久性(Durability)

          持久性是指一個事務一旦被提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變就是永久性的,接下來即使數(shù)據(jù)庫發(fā)生故障也不應該對其有任何影響

          Redis的事務總是具有ACID中的一致性和隔離性,其他特性是不支持的。當服務器運行在AOF持久化模式下,并且appendfsync選項的值為always時,事務也具有耐久性。

          Redis事務支持隔離性嗎

          Redis 是單進程程序,并且它保證在執(zhí)行事務時,不會對事務進行中斷,事務可以運行直到執(zhí)行完所有事務隊列中的命令為止。因此,Redis 的事務是總是帶有隔離性的。

          Redis事務保證原子性嗎,支持回滾嗎

          Redis中,單條命令是原子性執(zhí)行的,但事務不保證原子性,且沒有回滾。事務中任意命令執(zhí)行失敗,其余的命令仍會被執(zhí)行。

          Redis事務其他實現(xiàn)

          • 基于Lua腳本,Redis可以保證腳本內的命令一次性、按順序地執(zhí)行,
            其同時也不提供事務運行錯誤的回滾,執(zhí)行過程中如果部分命令運行錯誤,剩下的命令還是會繼續(xù)運行完

          • 基于中間標記變量,通過另外的標記變量來標識事務是否執(zhí)行完成,讀取數(shù)據(jù)時先讀取該標記變量判斷是否事務執(zhí)行完成。但這樣會需要額外寫代碼實現(xiàn),比較繁瑣

          26、Redis是單線程的,如何提高多核CPU的利用率?

          可以在同一個服務器部署多個Redis的實例,并把他們當作不同的服務器來使用,在某些時候,無論如何一個服務器是不夠的, 所以,如果你想使用多個CPU,你可以考慮一下分片(shard)。

          27、為什么要做Redis分區(qū)?

          分區(qū)可以讓Redis管理更大的內存,Redis將可以使用所有機器的內存。如果沒有分區(qū),你最多只能使用一臺機器的內存。分區(qū)使Redis的計算能力通過簡單地增加計算機得到成倍提升,Redis的網(wǎng)絡帶寬也會隨著計算機和網(wǎng)卡的增加而成倍增長。

          28、你知道有哪些Redis分區(qū)實現(xiàn)方案?

          • 客戶端分區(qū)就是在客戶端就已經(jīng)決定數(shù)據(jù)會被存儲到哪個redis節(jié)點或者從哪個redis節(jié)點讀取。大多數(shù)客戶端已經(jīng)實現(xiàn)了客戶端分區(qū)。

          • 代理分區(qū) 意味著客戶端將請求發(fā)送給代理,然后代理決定去哪個節(jié)點寫數(shù)據(jù)或者讀數(shù)據(jù)。代理根據(jù)分區(qū)規(guī)則決定請求哪些Redis實例,然后根據(jù)Redis的響應結果返回給客戶端。redis和memcached的一種代理實現(xiàn)就是Twemproxy

          • 查詢路由(Query routing) 的意思是客戶端隨機地請求任意一個redis實例,然后由Redis將請求轉發(fā)給正確的Redis節(jié)點。Redis Cluster實現(xiàn)了一種混合形式的查詢路由,但并不是直接將請求從一個redis節(jié)點轉發(fā)到另一個redis節(jié)點,而是在客戶端的幫助下直接redirected到正確的redis節(jié)點。

          29、Redis分區(qū)有什么缺點?

          • 涉及多個key的操作通常不會被支持。例如你不能對兩個集合求交集,因為他們可能被存儲到不同的Redis實例(實際上這種情況也有辦法,但是不能直接使用交集指令)。

          • 同時操作多個key,則不能使用Redis事務.

          • 分區(qū)使用的粒度是key,不能使用一個非常長的排序key存儲一個數(shù)據(jù)集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)

          • 當使用分區(qū)的時候,數(shù)據(jù)處理會非常復雜,例如為了備份你必須從不同的Redis實例和主機同時收集RDB / AOF文件。

          • 分區(qū)時動態(tài)擴容或縮容可能非常復雜。Redis集群在運行時增加或者刪除Redis節(jié)點,能做到最大程度對用戶透明地數(shù)據(jù)再平衡,但其他一些客戶端分區(qū)或者代理分區(qū)方法則不支持這種特性。然而,有一種預分片的技術也可以較好的解決這個問題。

          30、Redis實現(xiàn)分布式鎖

          Redis為單進程單線程模式,采用隊列模式將并發(fā)訪問變成串行訪問,且多客戶端對Redis的連接并不存在競爭關系Redis中可以使用SETNX命令實現(xiàn)分布式鎖。

          當且僅當 key 不存在,將 key 的值設為 value。若給定的 key 已經(jīng)存在,則 SETNX 不做任何動作

          SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。

          返回值:設置成功,返回 1 。設置失敗,返回 0 。

          使用SETNX完成同步鎖的流程及事項如下:

          使用SETNX命令獲取鎖,若返回0(key已存在,鎖已存在)則獲取失敗,反之獲取成功

          為了防止獲取鎖后程序出現(xiàn)異常,導致其他線程/進程調用SETNX命令總是返回0而進入死鎖狀態(tài),需要為該key設置一個“合理”的過期時間

          釋放鎖,使用DEL命令將鎖數(shù)據(jù)刪除

          31、如何解決 Redis 的并發(fā)競爭 Key 問題

          所謂 Redis 的并發(fā)競爭 Key 的問題也就是多個系統(tǒng)同時對一個 key 進行操作,但是最后執(zhí)行的順序和我們期望的順序不同,這樣也就導致了結果的不同!

          推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現(xiàn)分布式鎖)。(如果不存在 Redis 的并發(fā)競爭 Key 問題,不要使用分布式鎖,這樣會影響性能)

          基于zookeeper臨時有序節(jié)點可以實現(xiàn)的分布式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節(jié)點的目錄下,生成一個唯一的瞬時有序節(jié)點。判斷是否獲取鎖的方式很簡單,只需要判斷有序節(jié)點中序號最小的一個。當釋放鎖的時候,只需將這個瞬時節(jié)點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產(chǎn)生的死鎖問題。完成業(yè)務流程后,刪除對應的子節(jié)點釋放鎖。

          在實踐中,當然是從以可靠性為主。所以首推Zookeeper。

          參考:https://www.jianshu.com/p/8bddd381de06

          32、分布式Redis是前期做還是后期規(guī)模上來了再做好?為什么?

          既然Redis是如此的輕量(單實例只使用1M內存),為防止以后的擴容,最好的辦法就是一開始就啟動較多實例。即便你只有一臺服務器,你也可以一開始就讓Redis以分布式的方式運行,使用分區(qū),在同一臺服務器上啟動多個實例。

          一開始就多設置幾個Redis實例,例如32或者64個實例,對大多數(shù)用戶來說這操作起來可能比較麻煩,但是從長久來看做這點犧牲是值得的。

          這樣的話,當你的數(shù)據(jù)不斷增長,需要更多的Redis服務器時,你需要做的就是僅僅將Redis實例從一臺服務遷移到另外一臺服務器而已(而不用考慮重新分區(qū)的問題)。一旦你添加了另一臺服務器,你需要將你一半的Redis實例從第一臺機器遷移到第二臺機器。

          33、什么是 RedLock

          Redis 官方站提出了一種權威的基于 Redis 實現(xiàn)分布式鎖的方式名叫 Redlock,此種方式比原先的單節(jié)點的方法更安全。它可以保證以下特性:

          1. 安全特性:互斥訪問,即永遠只有一個 client 能拿到鎖

          2. 避免死鎖:最終 client 都可能拿到鎖,不會出現(xiàn)死鎖的情況,即使原本鎖住某資源的 client crash 了或者出現(xiàn)了網(wǎng)絡分區(qū)

          3. 容錯性:只要大部分 Redis 節(jié)點存活就可以正常提供服務

          后續(xù)還會繼續(xù)更新,盡量補全一些,大家也可以來我的網(wǎng)站閱讀,每次更新都會在網(wǎng)站實時更新,并且網(wǎng)站帶有目錄的功能。

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  狠狠亲狠狠操 | 午夜亚洲AⅤ无码高潮片苍井空 | 中文无码字幕视频 | 91传媒在线观看网站 | 91三级片 |