1. 程式人生 > 資料庫 >在MySQL中實現Rank高階排名函式

在MySQL中實現Rank高階排名函式

文章目錄

Java面試總結匯總,整理了包括Java基礎知識,集合容器,併發程式設計,JVM,常用開源框架Spring,MyBatis,資料庫,中介軟體等,包含了作為一個Java工程師在面試中需要用到或者可能用到的絕大部分知識。歡迎大家閱讀,本人見識有限,寫的部落格難免有錯誤或者疏忽的地方,還望各位大佬指點,在此表示感激不盡。文章持續更新中…

序號內容連結地址
1Java基礎知識面試題(2020最新版)
2Java集合容器面試題(2020最新版)
3Java異常面試題(2020最新版)
4併發程式設計面試題(2020最新版)
5JVM面試題(2020最新版)
6Spring面試題(2020最新版)
7Spring MVC面試題(2020最新版)
8Spring Boot面試題(2020最新版)
9Spring Cloud面試題(2020最新版)
10MyBatis面試題(2020最新版)
11Redis面試題(2020最新版)
12MySQL資料庫面試題(2020最新版)
13訊息中介軟體MQ與RabbitMQ面試題(2020最新版)
14Dubbo面試題(2020最新版)
15Linux面試題(2020最新版)
16Tomcat面試題(2020最新版)
17ZooKeeper面試題(2020最新版)
18Netty面試題(2020最新版)
19架構設計&分散式&資料結構與演算法面試題(2020最新版)

概述

什麼是Redis

Redis(Remote Dictionary Server) 是一個使用 C 語言編寫的,開源的(BSD許可)高效能非關係型(NoSQL)的鍵值對資料庫。

Redis 可以儲存鍵和五種不同型別的值之間的對映。鍵的型別只能為字串,值支援五種資料型別:字串、列表、集合、散列表、有序集合。

與傳統資料庫不同的是 Redis 的資料是存在記憶體中的,所以讀寫速度非常快,因此 redis 被廣泛應用於快取方向,每秒可以處理超過 10萬次讀寫操作,是已知效能最快的Key-Value DB。另外,Redis 也經常用來做分散式鎖。除此之外,Redis 支援事務 、持久化、LUA指令碼、LRU驅動事件、多種叢集方案。

Redis有哪些優缺點

優點

  • 讀寫效能優異, Redis能讀的速度是110000次/s,寫的速度是81000次/s。
  • 支援資料持久化,支援AOF和RDB兩種持久化方式。
  • 支援事務,Redis的所有操作都是原子性的,同時Redis還支援對幾個操作合併後的原子性執行。
  • 資料結構豐富,除了支援string型別的value外還支援hash、set、zset、list等資料結構。
  • 支援主從複製,主機會自動將資料同步到從機,可以進行讀寫分離。

缺點

  • 資料庫容量受到實體記憶體的限制,不能用作海量資料的高效能讀寫,因此Redis適合的場景主要侷限在較小資料量的高效能操作和運算上。
  • Redis 不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的IP才能恢復。
  • 主機宕機,宕機前有部分資料未能及時同步到從機,切換IP後還會引入資料不一致的問題,降低了系統的可用性。
  • Redis 較難支援線上擴容,在叢集容量達到上限時線上擴容會變得很複雜。為避免這一問題,運維人員在系統上線時必須確保有足夠的空間,這對資源造成了很大的浪費。

為什麼要用 Redis /為什麼要用快取

主要從“高效能”和“高併發”這兩點來看待這個問題。

高效能:

假如使用者第一次訪問資料庫中的某些資料。這個過程會比較慢,因為是從硬碟上讀取的。將該使用者訪問的資料存在數快取中,這樣下一次再訪問這些資料的時候就可以直接從快取中獲取了。操作快取就是直接操作記憶體,所以速度相當快。如果資料庫中的對應資料改變的之後,同步改變快取中相應的資料即可!

img

高併發:

直接操作快取能夠承受的請求是遠遠大於直接訪問資料庫的,所以我們可以考慮把資料庫中的部分資料轉移到快取中去,這樣使用者的一部分請求會直接到快取這裡而不用經過資料庫。

img

為什麼要用 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相比其他快取,有一個非常大的優勢,就是支援多種資料型別。

資料型別說明string字串,最簡單的k-v儲存hashhash格式,value為field和value,適合ID-Detail這樣的場景。list簡單的list,順序列表,支援首位或者末尾插入資料set無序list,查詢速度快,適合交集、並集、差集處理sorted set有序的set

其實,通過上面的資料型別的特性,基本就能想到合適的應用場景了。

string——適合最簡單的k-v儲存,類似於memcached的儲存結構,簡訊驗證碼,配置資訊等,就用這種型別來儲存。

hash——一般key為ID或者唯一標示,value對應的就是詳情了。如商品詳情,個人資訊詳情,新聞詳情等。

list——因為list是有序的,比較適合儲存一些有序且資料相對固定的資料。如省市區表、字典表等。因為list是有序的,適合根據寫入的時間來排序,如:最新的***,訊息佇列等。

set——可以簡單的理解為ID-List的模式,如微博中一個人有哪些好友,set最牛的地方在於,可以對兩個set提供交集、並集、差集操作。例如:查詢兩個人共同的好友等。

Sorted Set——是set的增強版本,增加了一個score引數,自動會根據score的值進行排序。比較適合類似於top 10等不根據插入的時間來排序的資料。

如上所述,雖然Redis不像關係資料庫那麼複雜的資料結構,但是,也能適合很多場景,比一般的快取資料結構要多。瞭解每種資料結構適合的業務場景,不僅有利於提升開發效率,也能有效利用Redis的效能。

持久化

什麼是Redis持久化?

持久化就是把記憶體的資料寫到磁碟中去,防止服務宕機了記憶體資料丟失。

Redis 的持久化機制是什麼?各自的優缺點?

Redis 提供兩種持久化機制 RDB(預設) 和 AOF 機制:

RDB:是Redis DataBase縮寫快照

RDB是Redis預設的持久化方式。按照一定的時間將記憶體的資料以快照的形式儲存到硬碟中,對應產生的資料檔案為dump.rdb。通過配置檔案中的save引數來定義快照的週期。

img

優點:

  • 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恢復。

img

優點:

  • 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可以保證指令碼內的命令一次性、按順序地執行,
    其同時也不提供事務執行錯誤的回滾,執行過程中如果部分命令執行錯誤,剩下的命令還是會繼續執行完
  • 基於中間標記變數,通過另外的標記變數來標識事務是否執行完成,讀取資料時先讀取該標記變數判斷是否事務執行完成。但這樣會需要額外寫程式碼實現,比較繁瑣

叢集方案

哨兵模式

哨兵的介紹

sentinel,中文名是哨兵。哨兵是 redis 叢集機構中非常重要的一個元件,主要有以下功能:

  • 叢集監控:負責監控 redis master 和 slave 程序是否正常工作。
  • 訊息通知:如果某個 redis 例項有故障,那麼哨兵負責傳送訊息作為報警通知給管理員。
  • 故障轉移:如果 master node 掛掉了,會自動轉移到 slave node 上。
  • 配置中心:如果故障轉移發生了,通知 client 客戶端新的 master 地址。

哨兵用於實現 redis 叢集的高可用,本身也是分散式的,作為一個哨兵叢集去執行,互相協同工作。

  • 故障轉移時,判斷一個 master node 是否宕機了,需要大部分的哨兵都同意才行,涉及到了分散式選舉的問題。
  • 即使部分哨兵節點掛掉了,哨兵叢集還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了。

哨兵的核心知識

  • 哨兵至少需要 3 個例項,來保證自己的健壯性。
  • 哨兵 + redis 主從的部署架構,是不保證資料零丟失的,只能保證 redis 叢集的高可用性。
  • 對於哨兵 + redis 主從這種複雜的部署架構,儘量在測試環境和生產環境,都進行充足的測試和演練。

官方Redis Cluster 方案(服務端路由查詢)

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管道操作)
  • 分散式邏輯和儲存模組耦合等

基於客戶端分配

簡介

Redis Sharding是Redis Cluster出來之前,業界普遍使用的多Redis例項叢集方法。其主要思想是採用雜湊演算法將Redis資料的key進行雜湊,通過hash函式,特定的key會對映到特定的Redis節點上。Java redis客戶端驅動jedis,支援Redis Sharding功能,即ShardedJedis以及結合快取池的ShardedJedisPool

優點

優勢在於非常簡單,服務端的Redis例項彼此獨立,相互無關聯,每個Redis例項像單伺服器一樣執行,非常容易線性擴充套件,系統的靈活性很強

缺點

  • 由於sharding處理放到客戶端,規模進一步擴大時給運維帶來挑戰。
  • 客戶端sharding不支援動態增刪節點。服務端Redis例項群拓撲結構有變化時,每個客戶端都需要更新調整。連線不能共享,當應用規模增大時,資源浪費制約優化

基於代理伺服器分片

簡介

客戶端傳送請求到一個代理元件,代理解析客戶端的資料,並將請求轉發至正確的節點,最後將結果回覆給客戶端

特徵

  • 透明接入,業務程式不用關心後端Redis例項,切換成本低
  • Proxy 的邏輯和儲存的邏輯是隔離的
  • 代理層多了一次轉發,效能有所損耗

業界開源方案

  • Twtter開源的Twemproxy
  • 豌豆莢開源的Codis

Redis 主從架構

單機的 redis,能夠承載的 QPS 大概就在上萬到幾萬不等。對於快取來說,一般都是用來支撐讀高併發的。因此架構做成主從(master-slave)架構,一主多從,主負責寫,並且將資料複製到其它的 slave 節點,從節點負責讀。所有的讀請求全部走從節點。這樣也可以很輕鬆實現水平擴容,支撐讀高併發

redis-master-slave

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 部分缺少的資料。

redis-master-slave-replication

過程原理

  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 。

img

使用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 節點存活就可以正常提供服務

快取異常

快取雪崩

快取雪崩是指快取同一時間大面積的失效,所以,後面的請求都會落到資料庫上,造成資料庫短時間內承受大量請求而崩掉。

解決方案

  1. 快取資料的過期時間設定隨機,防止同一時間大量資料過期現象發生。
  2. 一般併發量不是特別多的時候,使用最多的解決方案是加鎖排隊。
  3. 給每一個快取資料增加相應的快取標記,記錄快取的是否失效,如果快取標記失效,則更新資料快取。

快取穿透

快取穿透是指快取和資料庫中都沒有的資料,導致所有的請求都落到資料庫上,造成資料庫短時間內承受大量請求而崩掉。

解決方案

  1. 介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id<=0的直接攔截;
  2. 從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key-value對寫為key-null,快取有效時間可以設定短點,如30秒(設定太長會導致正常情況也沒法使用)。這樣可以防止攻擊使用者反覆用同一個id暴力攻擊
  3. 採用布隆過濾器,將所有可能存在的資料雜湊到一個足夠大的 bitmap 中,一個一定不存在的資料會被這個 bitmap 攔截掉,從而避免了對底層儲存系統的查詢壓力

附加

對於空間的利用到達了一種極致,那就是Bitmap和布隆過濾器(Bloom Filter)。
Bitmap: 典型的就是雜湊表
缺點是,Bitmap對於每個元素只能記錄1bit資訊,如果還想完成額外的功能,恐怕只能靠犧牲更多的空間、時間來完成了。

布隆過濾器(推薦)

就是引入了k(k>1)k(k>1)個相互獨立的雜湊函式,保證在給定的空間、誤判率下,完成元素判重的過程。
它的優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。
Bloom-Filter演算法的核心思想就是利用多個不同的Hash函式來解決“衝突”。
Hash存在一個衝突(碰撞)的問題,用同一個Hash得到的兩個URL的值有可能相同。為了減少衝突,我們可以多引入幾個Hash,如果通過其中的一個Hash值我們得出某元素不在集合中,那麼該元素肯定不在集合中。只有在所有的Hash函式告訴我們該元素在集合中時,才能確定該元素存在於集合中。這便是Bloom-Filter的基本思想。
Bloom-Filter一般用於在大資料量的集合中判定某元素是否存在。

快取擊穿

快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於併發使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力。和快取雪崩不同的是,快取擊穿指併發查同一條資料,快取雪崩是不同資料都過期了,很多資料都查不到從而查資料庫。

解決方案

  1. 設定熱點資料永遠不過期。
  2. 加互斥鎖,互斥鎖

快取預熱

快取預熱就是系統上線後,將相關的快取資料直接載入到快取系統。這樣就可以避免在使用者請求的時候,先查詢資料庫,然後再將資料快取的問題!使用者直接查詢事先被預熱的快取資料!

解決方案

  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 主要有以下不同:

對比引數RedisMemcached
型別1. 支援記憶體 2. 非關係型資料庫1. 支援記憶體 2. 鍵值對形式 3. 快取形式
資料儲存型別1. String 2. List 3. Set 4. Hash 5. Sort Set 【俗稱ZSet】1. 文字型 2. 二進位制型別
查詢【操作】型別1. 批量操作 2. 事務支援 3. 每個型別不同的CRUD1.常用的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演算法