<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 概述 #### 什么是Redis? * Redis 是一個使用 C 語言寫成的,開源的高性能key-value非關系緩存數據庫。它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。Redis的數據都基于緩存的,所以很快,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value DB。Redis也可以實現數據寫入磁盤中,保證了數據的安全不丟失,而且Redis的操作是原子性的。 #### Redis有哪些優缺點? * 優點 * 讀寫性能優異, Redis能讀的速度是110000次/s,寫的速度是81000次/s。 * 支持數據持久化,支持AOF和RDB兩種持久化方式。 * 支持事務,Redis的所有操作都是原子性的,同時Redis還支持對幾個操作合并后的原子性執行。 * 數據結構豐富,除了支持string類型的value外還支持hash、set、zset、list等數據結構。 * 支持主從復制,主機會自動將數據同步到從機,可以進行讀寫分離。 * 缺點 * 數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要局限在較小數據量的高性能操作和運算上。 * Redis 不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的IP才能恢復。 * 主機宕機,宕機前有部分數據未能及時同步到從機,切換IP后還會引入數據不一致的問題,降低了系統的可用性。 * Redis 較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。為避免這一問題,運維人員在系統上線時必須確保有足夠的空間,這對資源造成了很大的浪費。 #### 使用redis有哪些好處? * (1) 速度快,因為數據存在內存中,類似于HashMap,HashMap的優勢就是查找和操作的時間復雜度都很低 * (2)支持豐富數據類型,支持string,list,set,sorted set,hash * (3) 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要么全部執行,要么全部不執行 * (4) 豐富的特性:可用于緩存,消息,按key設置過期時間,過期后將會自動刪除 #### 為什么要用 Redis / 為什么要用緩存 `主要從“高性能”和“高并發”這兩點來看待這個問題。` * 高性能: * 假如用戶第一次訪問數據庫中的某些數據。這個過程會比較慢,因為是從硬盤上讀取的。將該用戶訪問的數據存在數緩存中,這樣下一次再訪問這些數據的時候就可以直接從緩存中獲取了。操作緩存就是直接操作內存,所以速度相當快。如果數據庫中的對應數據改變的之后,同步改變緩存中相應的數據即可! * 高并發: * 直接操作緩存能夠承受的請求是遠遠大于直接訪問數據庫的,所以我們可以考慮把數據庫中的部分數據轉移到緩存中去,這樣用戶的一部分請求會直接到緩存這里而不用經過數據庫。 #### 為什么要用 Redis 而不用 map/guava 做緩存? * 緩存分為本地緩存和分布式緩存。以 Java 為例,使用自帶的 map 或者 guava 實現的是本地緩存,最主要的特點是輕量以及快速,生命周期隨著 jvm 的銷毀而結束,并且在多實例的情況下,每個實例都需要各自保存一份緩存,緩存不具有一致性。 * 使用 redis 或 memcached 之類的稱為分布式緩存,在多實例的情況下,各實例共用一份緩存數據,緩存具有一致性。缺點是需要保持 redis 或 memcached服務的高可用,整個程序架構上較為復雜。 #### Redis為什么這么快 * 1、完全基于內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似于 HashMap,HashMap 的優勢就是查找和操作的時間復雜度都是O(1); * 2、數據結構簡單,對數據操作也簡單,Redis 中的數據結構是專門進行設計的; * 3、采用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗; * 4、使用多路 I/O 復用模型,非阻塞 IO; * 5、使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis 直接自己構建了 VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求; #### Redis有哪些數據類型 * Redis主要有5種數據類型,包括String,List,Set,Zset,Hash,滿足大部分的使用要求 | 數據類型 | 可以存儲的值 | 操作 | 應用場景 | | --- | --- | --- | --- | | String | 字符串、整數或者浮點數 | 對整個字符串或者字符串的其中一部分執行操作 對整數和浮點數執行自增或者自減操作 | 做簡單的鍵值對緩存 | | List | 列表 | 從兩端壓入或者彈出元素 對單個或者多個元素進行修剪, 只保留一個范圍內的元素 | 存儲一些列表型的數據結構,類似粉絲列表、文章的評論列表之類的數據 | | Set | 無序集合 | 添加、獲取、移除單個元素 檢查一個元素是否存在于集合中 計算交集、并集、差集 從集合里面隨機獲取元素 | 交集、并集、差集的操作,比如交集,可以把兩個人的粉絲列表整一個交集 | | Hash | 包含鍵值對的無序散列表 | 添加、獲取、移除單個鍵值對 獲取所有鍵值對 檢查某個鍵是否存在 | 結構化的數據,比如一個對象 | | ZSet | 有序集合 | 添加、獲取、刪除元素 根據分值范圍或者成員來獲取元素 計算一個鍵的排名 | 去重但可以排序,如獲取排名前幾名的用戶 | #### Redis的應用場景 * 計數器 可以對 String 進行自增自減運算,從而實現計數器功能。Redis 這種內存型數據庫的讀寫性能非常高,很適合存儲頻繁讀寫的計數量。 * 緩存 將熱點數據放到內存中,設置內存的最大使用量以及淘汰策略來保證緩存的命中率。 * 會話緩存 可以使用 Redis 來統一存儲多臺應用服務器的會話信息。當應用服務器不再存儲用戶的會話信息,也就不再具有狀態,一個用戶可以請求任意一個應用服務器,從而更容易實現高可用性以及可伸縮性。 * 全頁緩存(FPC) 除基本的會話token之外,Redis還提供很簡便的FPC平臺。以Magento為例,Magento提供一個插件來使用Redis作為全頁緩存后端。此外,對WordPress的用戶來說,Pantheon有一個非常好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。 * 查找表 例如 DNS 記錄就很適合使用 Redis 進行存儲。查找表和緩存類似,也是利用了 Redis 快速的查找特性。但是查找表的內容不能失效,而緩存的內容可以失效,因為緩存不作為可靠的數據來源。 * 消息隊列(發布/訂閱功能) List 是一個雙向鏈表,可以通過 lpush 和 rpop 寫入和讀取消息。不過最好使用 Kafka、RabbitMQ 等消息中間件。 * 分布式鎖實現 在分布式場景下,無法使用單機環境下的鎖來對多個節點上的進程進行同步。可以使用 Redis 自帶的 SETNX 命令實現分布式鎖,除此之外,還可以使用官方提供的 RedLock 分布式鎖實現。 * 其它 Set 可以實現交集、并集等操作,從而實現共同好友等功能。ZSet 可以實現有序性操作,從而實現排行榜等功能。 #### 持久化 * 什么是Redis持久化? 持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。 #### Redis 的持久化機制是什么?各自的優缺點? * Redis 提供兩種持久化機制 RDB(默認) 和 AOF 機制: ##### RDB:是Redis DataBase縮寫快照 * RDB是Redis默認的持久化方式。按照一定的時間將內存的數據以快照的形式保存到硬盤中,對應產生的數據文件為dump.rdb。通過配置文件中的save參數來定義快照的周期。 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/1717449419419e78~tplv-t2oaga2asx-watermark.awebp) * 優點: 1、只有一個文件 dump.rdb,方便持久化。 2、容災性好,一個文件可以保存到安全的磁盤。 3、性能最大化,fork 子進程來完成寫操作,讓主進程繼續處理命令,所以是 IO 最大化。使用單獨子進程來進行持久化,主進程不會進行任何 IO 操作,保證了 redis 的高性能 4.相對于數據集大時,比 AOF 的啟動效率更高。 * 缺點: 1、數據安全性低。RDB 是間隔一段時間進行持久化,如果持久化之間 redis 發生故障,會發生數據丟失。所以這種方式更適合數據要求不嚴謹的時候) 2、AOF(Append-only file)持久化方式: 是指所有的命令行記錄以 redis 命令請 求協議的格式完全持久化存儲)保存為 aof 文件。 ##### AOF:持久化: * AOF持久化(即Append Only File持久化),則是將Redis執行的每次寫命令記錄到單獨的日志文件中,當重啟Redis會重新將持久化的日志中文件恢復數據。 * 當兩種方式同時開啟時,數據恢復Redis會優先選擇AOF恢復 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744941b1f2a80~tplv-t2oaga2asx-watermark.awebp) * 優點: 1、數據安全,aof 持久化可以配置 appendfsync 屬性,有 always,每進行一次 命令操作就記錄到 aof 文件中一次。 2、通過 append 模式寫文件,即使中途服務器宕機,可以通過 redis-check-aof 工具解決數據一致性問題。 3、AOF 機制的 rewrite 模式。AOF 文件沒被 rewrite 之前(文件過大時會對命令 進行合并重寫),可以刪除其中的某些命令(比如誤操作的 flushall)) * 缺點: 1、AOF 文件比 RDB 文件大,且恢復速度慢。 2、數據集大的時候,比 rdb 啟動效率低。 * 倆種持久化的優缺點是什么? * AOF文件比RDB更新頻率高,優先使用AOF還原數據。 * AOF比RDB更安全也更大 * RDB性能比AOF好 * 如果兩個都配了優先加載AOF #### 如何選擇合適的持久化方式 * 一般來說, 如果想達到足以媲美PostgreSQL的數據安全性,你應該同時使用兩種持久化功能。在這種情況下,當 Redis 重啟的時候會優先載入AOF文件來恢復原始的數據,因為在通常情況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。 * 如果你非常關心你的數據, 但仍然可以承受數分鐘以內的數據丟失,那么你可以只使用RDB持久化。 * 有很多用戶都只使用AOF持久化,但并不推薦這種方式,因為定時生成RDB快照(snapshot)非常便于進行數據庫備份, 并且 RDB 恢復數據集的速度也要比AOF恢復的速度要快,除此之外,使用RDB還可以避免AOF程序的bug。 * 如果你只希望你的數據在服務器運行的時候存在,你也可以不使用任何持久化方式。 #### Redis持久化數據和緩存怎么做擴容? * 如果Redis被當做緩存使用,使用一致性哈希實現動態擴容縮容。 * 如果Redis被當做一個持久化存儲使用,必須使用固定的keys-to-nodes映射關系,節點的數量一旦確定不能變化。否則的話(即Redis節點需要動態變化的情況),必須使用可以在運行時進行數據再平衡的一套系統,而當前只有Redis集群可以做到這樣。 #### Redis的過期鍵的刪除策略 `我們都知道,Redis是key-value數據庫,我們可以設置Redis中緩存的key的過期時間。Redis的過期策略就是指當Redis中緩存的key過期了,Redis如何處理。` * 過期策略通常有以下三種: * 定時過期:每個設置過期時間的key都需要創建一個定時器,到過期時間就會立即清除。該策略可以立即清除過期的數據,對內存很友好;但是會占用大量的CPU資源去處理過期的數據,從而影響緩存的響應時間和吞吐量。 * 惰性過期:只有當訪問一個key時,才會判斷該key是否已過期,過期則清除。該策略可以最大化地節省CPU資源,卻對內存非常不友好。極端情況可能出現大量的過期key沒有再次被訪問,從而不會被清除,占用大量內存。 * 定期過期:每隔一定的時間,會掃描一定數量的數據庫的expires字典中一定數量的key,并清除其中已過期的key。該策略是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和內存資源達到最優的平衡效果。 (expires字典會保存所有設置了過期時間的key的過期時間數據,其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis集群中保存的所有鍵。) `Redis中同時使用了惰性過期和定期過期兩種過期策略。` #### Redis key的過期時間和永久有效分別怎么設置? * expire和persist命令。 #### 我們知道通過expire來設置key 的過期時間,那么對過期的數據怎么處理呢? * 除了緩存服務器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇),我們還可以根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種: * 1、定時去清理過期的緩存; * 2、當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到新數據并更新緩存。 `兩者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較復雜!具體用哪種方案,大家可以根據自己的應用場景來權衡。` #### MySQL里有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據 * redis內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。 #### Redis的內存淘汰策略有哪些 `Redis的內存淘汰策略是指在Redis的用于緩存的內存不足時,怎么處理需要新寫入且需要申請額外空間的數據。` * 全局的鍵空間選擇性移除 * noeviction:當內存不足以容納新寫入數據時,新寫入操作會報錯。 * allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。(這個是最常用的) * allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。 * 設置過期時間的鍵空間選擇性移除 * volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。 * volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。 * volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。 * 總結 `Redis的內存淘汰策略的選取并不會影響過期的key的處理。內存淘汰策略用于處理內存不足時的需要申請額外空間的數據;過期策略用于處理過期的緩存數據。` #### Redis主要消耗什么物理資源? * 內存。 #### Redis的內存用完了會發生什么? * 如果達到設置的上限,Redis的寫命令會返回錯誤信息(但是讀命令還可以正常返回。)或者你可以配置內存淘汰機制,當Redis達到內存上限時會沖刷掉舊的內容。 #### Redis如何做內存優化? * 可以好好利用Hash,list,sorted set,set等集合類型數據,因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。盡可能使用散列表(hashes),散列表(是說散列表里面存儲的數少)使用的內存非常小,所以你應該盡可能的將你的數據模型抽象到一個散列表里面。比如你的web系統中有一個用戶對象,不要為這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的所有信息存儲到一張散列表里面 ## 線程模型 ### Redis線程模型 Redis基于Reactor模式開發了網絡事件處理器,這個處理器被稱為文件事件處理器(file event handler)。它的組成結構為4部分:多個套接字、IO多路復用程序、文件事件分派器、事件處理器。因為文件事件分派器隊列的消費是單線程的,所以Redis才叫單線程模型。 * 文件事件處理器使用 I/O 多路復用(multiplexing)程序來同時監聽多個套接字, 并根據套接字目前執行的任務來為套接字關聯不同的事件處理器。 * 當被監聽的套接字準備好執行連接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時, 與操作相對應的文件事件就會產生, 這時文件事件處理器就會調用套接字之前關聯好的事件處理器來處理這些事件。 雖然文件事件處理器以單線程方式運行, 但通過使用 I/O 多路復用程序來監聽多個套接字, 文件事件處理器既實現了高性能的網絡通信模型, 又可以很好地與 redis 服務器中其他同樣以單線程方式運行的模塊進行對接, 這保持了 Redis 內部單線程設計的簡單性。 ## 事務 ### 什么是事務? * 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。 * 事務是一個原子操作:事務中的命令要么全部被執行,要么全部都不執行。 ### Redis事務的概念 * Redis 事務的本質是通過MULTI、EXEC、WATCH等一組命令的集合。事務支持一次執行多個命令,一個事務中所有命令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的命令,其他客戶端提交的命令請求不會插入到事務執行命令序列中。 * 總結說:redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。 ### Redis事務的三個階段 1. 事務開始 MULTI 2. 命令入隊 3. 事務執行 EXEC `事務執行過程中,如果服務端收到有EXEC、DISCARD、WATCH、MULTI之外的請求,將會把請求放入隊列中排隊` ### Redis事務相關命令 Redis事務功能是通過MULTI、EXEC、DISCARD和WATCH 四個原語實現的 Redis會將一個事務中的所有命令序列化,然后按順序執行。 1. **redis 不支持回滾**,“Redis 在事務失敗時不進行回滾,而是繼續執行余下的命令”, 所以 Redis 的內部可以保持簡單且快速。 2. **如果在一個事務中的命令出現錯誤,那么所有的命令都不會執行**; 3. **如果在一個事務中出現運行錯誤,那么正確的命令會被執行**。 * WATCH 命令是一個樂觀鎖,可以為 Redis 事務提供 check-and-set (CAS)行為。 可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之后的事務就不會執行,監控一直持續到EXEC命令。 * MULTI命令用于開啟一個事務,它總是返回OK。 MULTI執行之后,客戶端可以繼續向服務器發送任意多條命令,這些命令不會立即被執行,而是被放到一個隊列中,當EXEC命令被調用時,所有隊列中的命令才會被執行。 * EXEC:執行所有事務塊內的命令。返回事務塊內所有命令的返回值,按命令執行的先后順序排列。 當操作被打斷時,返回空值 nil 。 * 通過調用DISCARD,客戶端可以清空事務隊列,并放棄執行事務, 并且客戶端會從事務狀態中退出。 * UNWATCH命令可以取消watch對所有key的監控。 ### 事務管理(ACID)概述 * 原子性(Atomicity) 原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。 * 一致性(Consistency) 事務前后數據的完整性必須保持一致。 * 隔離性(Isolation) 多個事務并發執行時,一個事務的執行不應影響其他事務的執行 * 持久性(Durability) 持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響 `Redis的事務總是具有ACID中的一致性和隔離性,其他特性是不支持的。當服務器運行在_AOF_持久化模式下,并且appendfsync選項的值為always時,事務也具有耐久性。` ### Redis事務支持隔離性嗎 * Redis 是單進程程序,并且它保證在執行事務時,不會對事務進行中斷,事務可以運行直到執行完所有事務隊列中的命令為止。因此,**Redis 的事務是總是帶有隔離性的**。 ### Redis事務保證原子性嗎,支持回滾嗎 * Redis中,單條命令是原子性執行的,但**事務不保證原子性,且沒有回滾**。事務中任意命令執行失敗,其余的命令仍會被執行。 ### Redis事務其他實現 * 基于Lua腳本,Redis可以保證腳本內的命令一次性、按順序地執行, 其同時也不提供事務運行錯誤的回滾,執行過程中如果部分命令運行錯誤,剩下的命令還是會繼續運行完 * 基于中間標記變量,通過另外的標記變量來標識事務是否執行完成,讀取數據時先讀取該標記變量判斷是否事務執行完成。但這樣會需要額外寫代碼實現,比較繁瑣 ## 集群方案 ### 1、哨兵模式 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744941b28481b~tplv-t2oaga2asx-watermark.awebp) **哨兵的介紹** `sentinel,中文名是哨兵。哨兵是 redis 集群機構中非常重要的一個組件,主要有以下功能:` * 集群監控:負責監控 redis master 和 slave 進程是否正常工作。 * 消息通知:如果某個 redis 實例有故障,那么哨兵負責發送消息作為報警通知給管理員。 * 故障轉移:如果 master node 掛掉了,會自動轉移到 slave node 上。 * 配置中心:如果故障轉移發生了,通知 client 客戶端新的 master 地址。 **哨兵用于實現 redis 集群的高可用**,本身也是分布式的,作為一個哨兵集群去運行,互相協同工作。 * 故障轉移時,判斷一個 master node 是否宕機了,需要大部分的哨兵都同意才行,涉及到了分布式選舉的問題。 * 即使部分哨兵節點掛掉了,哨兵集群還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了。 **哨兵的核心知識** * 哨兵至少需要 3 個實例,來保證自己的健壯性。 * 哨兵 + redis 主從的部署架構,是**不保證數據零丟失**的,只能保證 redis 集群的高可用性。 * 對于哨兵 + redis 主從這種復雜的部署架構,盡量在測試環境和生產環境,都進行充足的測試和演練。 ### 2、官方Redis Cluster 方案(服務端路由查詢) ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744941e2adfa4~tplv-t2oaga2asx-watermark.awebp) * redis 集群模式的工作原理能說一下么?在集群模式下,redis 的 key 是如何尋址的?分布式尋址都有哪些算法?了解一致性 hash 算法嗎? **簡介** * Redis Cluster是一種服務端Sharding技術,3.0版本開始正式提供。Redis Cluster并沒有使用一致性hash,而是采用slot(槽)的概念,一共分成16384個槽。將請求發送到任意節點,接收到請求的節點會將查詢請求發送到正確的節點上執行 **方案說明** 1. 通過哈希的方式,將數據分片,每個節點均分存儲一定哈希槽(哈希值)區間的數據,默認分配了16384 個槽位 2. 每份數據分片會存儲在多個互為主從的多節點上 3. 數據寫入先寫主節點,再同步到從節點(支持配置為阻塞同步) 4. 同一分片多個節點間的數據不保持一致性 5. 讀取數據時,當客戶端操作的key沒有分配在該節點上時,redis會返回轉向指令,指向正確的節點 6. 擴容時時需要需要把舊節點的數據遷移一部分到新節點 * 在 redis cluster 架構下,每個 redis 要放開兩個端口號,比如一個是 6379,另外一個就是 加1w 的端口號,比如 16379。 * 16379 端口號是用來進行節點間通信的,也就是 cluster bus 的東西,cluster bus 的通信,用來進行故障檢測、配置更新、故障轉移授權。cluster bus 用了另外一種二進制的協議,`gossip` 協議,用于節點間進行高效的數據交換,占用更少的網絡帶寬和處理時間。 **節點間的內部通信機制** * 基本通信原理 * 集群元數據的維護有兩種方式:集中式、Gossip 協議。redis cluster 節點間采用 gossip 協議進行通信。 **分布式尋址算法** * hash 算法(大量緩存重建) * 一致性 hash 算法(自動緩存遷移)+ 虛擬節點(自動負載均衡) * redis cluster 的 hash slot 算法 **優點** * 無中心架構,支持動態擴容,對業務透明 * 具備Sentinel的監控和自動Failover(故障轉移)能力 * 客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可 * 高性能,客戶端直連redis服務,免去了proxy代理的損耗 **缺點** * 運維也很復雜,數據遷移需要人工干預 * 只能使用0號數據庫 * 不支持批量操作(pipeline管道操作) * 分布式邏輯和存儲模塊耦合等 ### 3、基于客戶端分配 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744941eba6627~tplv-t2oaga2asx-watermark.awebp) **簡介** * Redis Sharding是Redis Cluster出來之前,業界普遍使用的多Redis實例集群方法。其主要思想是采用哈希算法將Redis數據的key進行散列,通過hash函數,特定的key會映射到特定的Redis節點上。Java redis客戶端驅動jedis,支持Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool **優點** * 優勢在于非常簡單,服務端的Redis實例彼此獨立,相互無關聯,每個Redis實例像單服務器一樣運行,非常容易線性擴展,系統的靈活性很強 **缺點** * 由于sharding處理放到客戶端,規模進一步擴大時給運維帶來挑戰。 * 客戶端sharding不支持動態增刪節點。服務端Redis實例群拓撲結構有變化時,每個客戶端都需要更新調整。連接不能共享,當應用規模增大時,資源浪費制約優化 ### 4、基于代理服務器分片 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744941f4fe2e4~tplv-t2oaga2asx-watermark.awebp) **簡介** * 客戶端發送請求到一個代理組件,代理解析客戶端的數據,并將請求轉發至正確的節點,最后將結果回復給客戶端 **特征** * 透明接入,業務程序不用關心后端Redis實例,切換成本低 * Proxy 的邏輯和存儲的邏輯是隔離的 * 代理層多了一次轉發,性能有所損耗 **業界開源方案** * Twtter開源的Twemproxy * 豌豆莢開源的Codis ### 5、Redis 主從架構 * 單機的 redis,能夠承載的 QPS 大概就在上萬到幾萬不等。對于緩存來說,一般都是用來支撐**讀高并發**的。因此架構做成主從(master-slave)架構,一主多從,主負責寫,并且將數據復制到其它的 slave 節點,從節點負責讀。所有的**讀請求全部走從節點**。這樣也可以很輕松實現水平擴容,**支撐讀高并發**。 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744945c7745d8~tplv-t2oaga2asx-watermark.awebp) `redis replication -> 主從架構 -> 讀寫分離 -> 水平擴容支撐讀高并發` **redis replication 的核心機制** * redis 采用**異步方式**復制數據到 slave 節點,不過 redis2.8 開始,slave node 會周期性地確認自己每次復制的數據量; * 一個 master node 是可以配置多個 slave node 的; * slave node 也可以連接其他的 slave node; * slave node 做復制的時候,不會 block master node 的正常工作; * slave node 在做復制的時候,也不會 block 對自己的查詢操作,它會用舊的數據集來提供服務;但是復制完成的時候,需要刪除舊數據集,加載新數據集,這個時候就會暫停對外服務了; * slave node 主要用來進行橫向擴容,做讀寫分離,擴容的 slave node 可以提高讀的吞吐量。 **注意:** * 如果采用了主從架構,那么建議必須**開啟** master node 的持久化,不建議用 slave node 作為 master node 的數據熱備,因為那樣的話,如果你關掉 master 的持久化,可能在 master 宕機重啟的時候數據是空的,然后可能一經過復制, slave node 的數據也丟了。 * 另外,master 的各種備份方案,也需要做。萬一本地的所有文件丟失了,從備份中挑選一份 rdb 去恢復 master,這樣才能**確保啟動的時候,是有數據的**,即使采用了后續講解的高可用機制,slave node 可以自動接管 master node,但也可能 sentinel 還沒檢測到 master failure,master node 就自動重啟了,還是可能導致上面所有的 slave node 數據被清空。 **redis 主從復制的核心原理** * 當啟動一個 slave node 的時候,它會發送一個 `PSYNC` 命令給 master node。 * 如果這是 slave node 初次連接到 master node,那么會觸發一次 `full resynchronization` 全量復制。此時 master 會啟動一個后臺線程,開始生成一份 `RDB` 快照文件, * 同時還會將從客戶端 client 新收到的所有寫命令緩存在內存中。`RDB` 文件生成完畢后, master 會將這個 `RDB` 發送給 slave,slave 會先**寫入本地磁盤,然后再從本地磁盤加載到內存**中, * 接著 master 會將內存中緩存的寫命令發送到 slave,slave 也會同步這些數據。 * slave node 如果跟 master node 有網絡故障,斷開了連接,會自動重連,連接之后 master node 僅會復制給 slave 部分缺少的數據。 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/171744945c8008f8~tplv-t2oaga2asx-watermark.awebp) **過程原理** 1. 當從庫和主庫建立MS關系后,會向主數據庫發送SYNC命令 2. 主庫接收到SYNC命令后會開始在后臺保存快照(RDB持久化過程),并將期間接收到的寫命令緩存起來 3. 當快照完成后,主Redis會將快照文件和所有緩存的寫命令發送給從Redis 4. 從Redis接收到后,會載入快照文件并且執行收到的緩存的命令 5. 之后,主Redis每當接收到寫命令時就會將命令發送從Redis,從而保證數據的一致 **缺點** * 所有的slave節點數據的復制和同步都由master節點來處理,會照成master節點壓力太大,使用主從從結構來解決 ### Redis集群的主從復制模型是怎樣的? * 為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用,所以集群使用了主從復制模型,每個節點都會有N-1個復制品 ### 生產環境中的 redis 是怎么部署的? * redis cluster,10 臺機器,5 臺機器部署了 redis 主實例,另外 5 臺機器部署了 redis 的從實例,每個主實例掛了一個從實例,5 個節點對外提供讀寫服務,每個節點的讀寫高峰qps可能可以達到每秒 5 萬,5 臺機器最多是 25 萬讀寫請求/s。 * 機器是什么配置?32G 內存+ 8 核 CPU + 1T 磁盤,但是分配給 redis 進程的是10g內存,一般線上生產環境,redis 的內存盡量不要超過 10g,超過 10g 可能會有問題。 * 5 臺機器對外提供讀寫,一共有 50g 內存。 * 因為每個主實例都掛了一個從實例,所以是高可用的,任何一個主實例宕機,都會自動故障遷移,redis 從實例會自動變成主實例繼續提供讀寫服務。 * 你往內存里寫的是什么數據?每條數據的大小是多少?商品數據,每條數據是 10kb。100 條數據是 1mb,10 萬條數據是 1g。常駐內存的是 200 萬條商品數據,占用內存是 20g,僅僅不到總內存的 50%。目前高峰期每秒就是 3500 左右的請求量。 `其實大型的公司,會有基礎架構的 team 負責緩存集群的運維。` ### 說說Redis哈希槽的概念? * Redis集群沒有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽,集群的每個節點負責一部分hash槽。 ### Redis集群會有寫操作丟失嗎?為什么? * Redis并不能保證數據的強一致性,這意味這在實際中集群在特定的條件下可能會丟失寫操作。 ### Redis集群之間是如何復制的? * 異步復制 ### Redis集群最大節點個數是多少? * 16384個 ### Redis集群如何選擇數據庫? * Redis集群目前無法做數據庫選擇,默認在0數據庫。 ## 分區 ### Redis是單線程的,如何提高多核CPU的利用率? * 可以在同一個服務器部署多個Redis的實例,并把他們當作不同的服務器來使用,在某些時候,無論如何一個服務器是不夠的, 所以,如果你想使用多個CPU,你可以考慮一下分片(shard)。 ### 為什么要做Redis分區? * 分區可以讓Redis管理更大的內存,Redis將可以使用所有機器的內存。如果沒有分區,你最多只能使用一臺機器的內存。分區使Redis的計算能力通過簡單地增加計算機得到成倍提升,Redis的網絡帶寬也會隨著計算機和網卡的增加而成倍增長。 ### 你知道有哪些Redis分區實現方案? * 客戶端分區就是在客戶端就已經決定數據會被存儲到哪個redis節點或者從哪個redis節點讀取。大多數客戶端已經實現了客戶端分區。 * 代理分區 意味著客戶端將請求發送給代理,然后代理決定去哪個節點寫數據或者讀數據。代理根據分區規則決定請求哪些Redis實例,然后根據Redis的響應結果返回給客戶端。redis和memcached的一種代理實現就是Twemproxy * 查詢路由(Query routing) 的意思是客戶端隨機地請求任意一個redis實例,然后由Redis將請求轉發給正確的Redis節點。Redis Cluster實現了一種混合形式的查詢路由,但并不是直接將請求從一個redis節點轉發到另一個redis節點,而是在客戶端的幫助下直接redirected到正確的redis節點。 ### Redis分區有什么缺點? * 涉及多個key的操作通常不會被支持。例如你不能對兩個集合求交集,因為他們可能被存儲到不同的Redis實例(實際上這種情況也有辦法,但是不能直接使用交集指令)。 * 同時操作多個key,則不能使用Redis事務. * 分區使用的粒度是key,不能使用一個非常長的排序key存儲一個數據集(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) * 當使用分區的時候,數據處理會非常復雜,例如為了備份你必須從不同的Redis實例和主機同時收集RDB / AOF文件。 * 分區時動態擴容或縮容可能非常復雜。Redis集群在運行時增加或者刪除Redis節點,能做到最大程度對用戶透明地數據再平衡,但其他一些客戶端分區或者代理分區方法則不支持這種特性。然而,有一種預分片的技術也可以較好的解決這個問題。 ## 分布式問題 ### Redis實現分布式鎖 * Redis為單進程單線程模式,采用隊列模式將并發訪問變成串行訪問,且多客戶端對Redis的連接并不存在競爭關系Redis中可以使用setNx命令實現分布式鎖。 * 當且僅當 key 不存在,將 key 的值設為 value。 若給定的 key 已經存在,則 setNx不做任何動作 * SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。 * 返回值:設置成功,返回 1 。設置失敗,返回 0 。 ![在這里插入圖片描述](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/14/1717449461a98262~tplv-t2oaga2asx-watermark.awebp) * 使用setNx完成同步鎖的流程及事項如下: * 使用SETNX命令獲取鎖,若返回0(key已存在,鎖已存在)則獲取失敗,反之獲取成功 * 為了防止獲取鎖后程序出現異常,導致其他線程/進程調用setNx命令總是返回0而進入死鎖狀態,需要為該key設置一個“合理”的過期時間釋放鎖,使用DEL命令將鎖數據刪除 ### 如何解決 Redis 的并發競爭 Key 問題 * 所謂 Redis 的并發競爭 Key 的問題也就是多個系統同時對一個 key 進行操作,但是最后執行的順序和我們期望的順序不同,這樣也就導致了結果的不同! * 推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實現分布式鎖)。(如果不存在 Redis 的并發競爭 Key 問題,不要使用分布式鎖,這樣會影響性能) * 基于zookeeper臨時有序節點可以實現的分布式鎖。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。完成業務流程后,刪除對應的子節點釋放鎖。 `在實踐中,當然是從以可靠性為主。所以首推Zookeeper。` ### 分布式Redis是前期做還是后期規模上來了再做好?為什么? * 既然Redis是如此的輕量(單實例只使用1M內存),為防止以后的擴容,最好的辦法就是一開始就啟動較多實例。即便你只有一臺服務器,你也可以一開始就讓Redis以分布式的方式運行,使用分區,在同一臺服務器上啟動多個實例。 * 一開始就多設置幾個Redis實例,例如32或者64個實例,對大多數用戶來說這操作起來可能比較麻煩,但是從長久來看做這點犧牲是值得的。 * 這樣的話,當你的數據不斷增長,需要更多的Redis服務器時,你需要做的就是僅僅將Redis實例從一臺服務遷移到另外一臺服務器而已(而不用考慮重新分區的問題)。一旦你添加了另一臺服務器,你需要將你一半的Redis實例從第一臺機器遷移到第二臺機器。 ### 什么是 RedLock * Redis 官方站提出了一種權威的基于 Redis 實現分布式鎖的方式名叫 *Redlock*,此種方式比原先的單節點的方法更安全。它可以保證以下特性: 1. 安全特性:互斥訪問,即永遠只有一個 client 能拿到鎖 2. 避免死鎖:最終 client 都可能拿到鎖,不會出現死鎖的情況,即使原本鎖住某資源的 client crash 了或者出現了網絡分區 3. 容錯性:只要大部分 Redis 節點存活就可以正常提供服務 ## 緩存異常 #### 什么是redis穿透? * 就是用戶請求透過redis去請求mysql服務器,導致mysql壓力過載。但一個web服務里,極容易出現瓶頸的就是mysql,所以才讓redis去分擔mysql 的壓力,所以這種問題是萬萬要避免的 * 解決方法: 1. 從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將key-value對寫為key-null,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。這樣可以防止攻擊用戶反復用同一個id暴力攻擊 2. 接口層增加校驗,如用戶鑒權校驗,id做基礎校驗,id<=0的直接攔截; 3. 采用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的 bitmap 中,一個一定不存在的數據會被這個 bitmap 攔截掉,從而避免了對底層存儲系統的查詢壓力 #### 什么是redis雪崩? * 就是redis服務由于負載過大而宕機,導致mysql的負載過大也宕機,最終整個系統癱瘓 * 解決方法: 1. redis集群,將原來一個人干的工作,分發給多個人干 2. 緩存預熱(關閉外網訪問,先開啟mysql,通過預熱腳本將熱點數據寫入緩存中,啟動緩存。開啟外網服務) 3. 數據不要設置相同的生存時間,不然過期時,redis壓力會大 #### 什么是redis穿透? * 高并發下,由于一個key失效,而導致多個線程去mysql查同一業務數據并存到redis(并發下,存了多份數據),而一段時間后,多份數據同時失效。導致壓力驟增 * 解決方法: 1. 分級緩存(緩存兩份數據,第二份數據生存時間長一點作為備份,第一份數據用于被請求命中,如果第二份數據被命中說明第一份數據已經過期,要去mysql請求數據重新緩存兩份數據) 2. 計劃任務(假如數據生存時間為30分鐘,計劃任務就20分鐘執行一次更新緩存數據) ### 緩存預熱 * **緩存預熱**就是系統上線后,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶請求的時候,先查詢數據庫,然后再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據! * **解決方案** 1. 直接寫個緩存刷新頁面,上線時手工操作一下; 2. 數據量不大,可以在項目啟動的時候自動進行加載; 3. 定時刷新緩存; ### 緩存降級 * 當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統可以根據一些關鍵數據進行自動降級,也可以配置開關實現人工降級。 * **緩存降級**的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結算)。 * 在進行降級之前要對系統進行梳理,看看系統是不是可以丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日志級別設置預案: 1. 一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而超時,可以自動降級; 2. 警告:有些服務在一段時間內成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發送告警; 3. 錯誤:比如可用率低于90%,或者數據庫連接池被打爆了,或者訪問量突然猛增到系統能承受的最大閥值,此時可以根據情況自動降級或者人工降級; 4. 嚴重錯誤:比如因為特殊原因數據錯誤了,此時需要緊急人工降級。 * 服務降級的目的,是為了防止Redis服務故障,導致數據庫跟著一起發生雪崩問題。因此,對于不重要的緩存數據,可以采取服務降級策略,例如一個比較常見的做法就是,Redis出現問題,不去數據庫查詢,而是直接返回默認值給用戶。 ### 熱點數據和冷數據 * 熱點數據,緩存才有價值 * 對于冷數據而言,大部分數據可能還沒有再次訪問到就已經被擠出內存,不僅占用內存,而且價值不大。頻繁修改的數據,看情況考慮使用緩存 * 對于熱點數據,比如我們的某IM產品,生日祝福模塊,當天的壽星列表,緩存以后可能讀取數十萬次。再舉個例子,某導航產品,我們將導航信息,緩存以后可能讀取數百萬次。 * 數據更新前至少讀取兩次,緩存才有意義。這個是最基本的策略,如果緩存還沒有起作用就失效了,那就沒有太大價值了。 * 那存不存在,修改頻率很高,但是又不得不考慮緩存的場景呢?有!比如,這個讀取接口對數據庫的壓力很大,但是又是熱點數據,這個時候就需要考慮通過緩存手段,減少數據庫的壓力,比如我們的某助手產品的,點贊數,收藏數,分享數等是非常典型的熱點數據,但是又不斷變化,此時就需要將數據同步保存到Redis緩存,減少數據庫壓力。 ### 緩存熱點key * 緩存中的一個Key(比如一個促銷商品),在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的并發請求過來,這些請求發現緩存過期一般都會從后端DB加載數據并回設到緩存,這個時候大并發的請求可能會瞬間把后端DB壓垮。 **解決方案** * 對緩存查詢加鎖,如果KEY不存在,就加鎖,然后查DB入緩存,然后解鎖;其他進程如果發現有鎖就等待,然后等解鎖后返回數據或者進入DB查詢 ## 常用工具 ### Redis支持的Java客戶端都有哪些?官方推薦用哪個? * Redisson、Jedis、lettuce等等,官方推薦使用Redisson。 ### Redis和Redisson有什么關系? * Redisson是一個高級的分布式協調Redis客服端,能幫助用戶在分布式環境中輕松實現一些Java的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。 ### Jedis與Redisson對比有什么優缺點? * Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持;Redisson實現了分布式和可擴展的Java數據結構,和Jedis相比,功能較為簡單,不支持字符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。 ## 其他問題 ### Redis與Memcached的區別 * 兩者都是非關系型內存鍵值數據庫,現在公司一般都是用 Redis 來實現緩存,而且 Redis 自身也越來越強大了!Redis 與 Memcached 主要有以下不同: > | 對比參數 | Redis | Memcached | > | --- | --- | --- | > | 類型 | 1\. 支持內存 2. 非關系型數據庫 | 1\. 支持內存 2. 鍵值對形式 3. 緩存形式 | > | 數據存儲類型 | 1\. String 2. List 3. Set 4. Hash 5. Sort Set 【俗稱ZSet】 | 1\. 文本型 2. 二進制類型 | > | 查詢【操作】類型 | 1\. 批量操作 2. 事務支持 3. 每個類型不同的CRUD | 1.常用的CRUD 2. 少量的其他命令 | > | 附加功能 | 1\. 發布/訂閱模式 2. 主從分區 3. 序列化支持 4. 腳本支持【Lua腳本】 | 1\. 多線程服務支持 | > | 網絡IO模型 | 1\. 單線程的多路 IO 復用模型 | 1\. 多線程,非阻塞IO模式 | > | 事件庫 | 自封轉簡易事件庫AeEvent | 貴族血統的LibEvent事件庫 | > | 持久化支持 | 1\. RDB 2. AOF | 不支持 | > | 集群模式 | 原生支持 cluster 模式,可以實現主從復制,讀寫分離 | 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入數據 | > | 內存管理機制 | 在 Redis 中,并不是所有數據都一直存儲在內存中,可以將一些很久沒用的 value 交換到磁盤 | Memcached 的數據則會一直在內存中,Memcached 將內存分割成特定長度的塊來存儲數據,以完全解決內存碎片的問題。但是這種方式會使得內存的利用率不高,例如塊的大小為 128 bytes,只存儲 100 bytes 的數據,那么剩下的 28 bytes 就浪費掉了。 | > | 適用場景 | 復雜數據結構,有持久化,高可用需求,value存儲內容較大 | 純key-value,數據量非常大,并發量非常大的業務 | 1. memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 2. redis的速度比memcached快很多 3. redis可以持久化其數據 ### 如何保證緩存與數據庫雙寫時的數據一致性? * 你只要用緩存,就可能會涉及到緩存與數據庫雙存儲雙寫,你只要是雙寫,就一定會有數據一致性的問題,那么你如何解決一致性問題? * 一般來說,就是如果你的系統不是嚴格要求緩存+數據庫必須一致性的話,緩存可以稍微的跟數據庫偶爾有不一致的情況,最好不要做這個方案,讀請求和寫請求串行化,串到一個內存隊列里去,這樣就可以保證一定不會出現不一致的情況 * 串行化之后,就會導致系統的吞吐量會大幅度的降低,用比正常情況下多幾倍的機器去支撐線上的一個請求。 * 還有一種方式就是可能會暫時產生不一致的情況,但是發生的幾率特別小,就是**先更新數據庫,然后再刪除緩存。** | 問題場景 | 描述 | 解決 | | --- | --- | --- | | 先寫緩存,再寫數據庫,緩存寫成功,數據庫寫失敗 | 緩存寫成功,但寫數據庫失敗或者響應延遲,則下次讀取(并發讀)緩存時,就出現臟讀 | 這個寫緩存的方式,本身就是錯誤的,需要改為先寫數據庫,把舊緩存置為失效;讀取數據的時候,如果緩存不存在,則讀取數據庫再寫緩存 | | 先寫數據庫,再寫緩存,數據庫寫成功,緩存寫失敗 | 寫數據庫成功,但寫緩存失敗,則下次讀取(并發讀)緩存時,則讀不到數據 | 緩存使用時,假如讀緩存失敗,先讀數據庫,再回寫緩存的方式實現 | | 需要緩存異步刷新 | 指數據庫操作和寫緩存不在一個操作步驟中,比如在分布式場景下,無法做到同時寫緩存或需要異步刷新(補救措施)時候 | 確定哪些數據適合此類場景,根據經驗值確定合理的數據不一致時間,用戶數據刷新的時間間隔 | ### Redis常見性能問題和解決方案? 1. Master最好不要做任何持久化工作,包括內存快照和AOF日志文件,特別是不要啟用內存快照做持久化。 2. 如果數據比較關鍵,某個Slave開啟AOF備份數據,策略為每秒同步一次。 3. 為了主從復制的速度和連接的穩定性,Slave和Master最好在同一個局域網內。 4. 盡量避免在壓力較大的主庫上增加從庫 5. Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會占大量的CPU和內存資源,導致服務load過高,出現短暫服務暫停現象。 6. 為了Master的穩定性,主從復制不要用圖狀結構,用單向鏈表結構更穩定,即主從關系為:Master<–Slave1<–Slave2<–Slave3…,這樣的結構也方便解決單點故障問題,實現Slave對Master的替換,也即,如果Master掛了,可以立馬啟用Slave1做Master,其他不變。 ### Redis官方為什么不提供Windows版本? * 因為目前Linux版本已經相當穩定,而且用戶量很大,無需開發windows版本,反而會帶來兼容性等問題。 ### 一個字符串類型的值能存儲最大容量是多少? * 512M ### Redis如何做大量數據插入? * Redis2.6開始redis-cli支持一種新的被稱之為pipe mode的新模式用于執行大量數據插入工作。 ### 假如Redis里面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,如果將它們全部找出來? * 使用keys指令可以掃出指定模式的key列表。 * 對方接著追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什么問題? 這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重復概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。 ### 使用Redis做過異步隊列嗎,是如何實現的 * 使用list類型保存數據信息,rpush生產消息,lpop消費消息,當lpop沒有消息時,可以sleep一段時間,然后再檢查有沒有信息,如果不想sleep的話,可以使用blpop, 在沒有信息的時候,會一直阻塞,直到信息的到來。redis可以通過pub/sub主題訂閱模式實現一個生產者,多個消費者,當然也存在一定的缺點,當消費者下線時,生產的消息會丟失。 ### Redis如何實現延時隊列 * 使用sortedset,使用時間戳做score, 消息內容作為key,調用zadd來生產消息,消費者使用zrangbyscore獲取n秒之前的數據做輪詢處理。 ### Redis回收進程如何工作的? 1. 一個客戶端運行了新的命令,添加了新的數據。 2. Redis檢查內存使用情況,如果大于maxmemory的限制, 則根據設定好的策略進行回收。 3. 一個新的命令被執行,等等。 4. 所以我們不斷地穿越內存限制的邊界,通過不斷達到邊界然后不斷地回收回到邊界以下。 `如果一個命令的結果導致大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。` ### Redis回收使用的是什么算法? * LRU算法
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看