指引:html
1、面試題:redis中zset的score值同樣,那它是按什麼排序的:按字典值排序
java
在score相同的狀況下,redis使用字典排序,而所謂的字典排序其實就是「ABCDEFG」這樣的排序,在首字母相同的狀況下,redis會再比較後面的字母,仍是按照字典排序。
node
二、假如Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,若是將它們所有找出來?mysql
使用keys指令能夠掃出指定模式的key列表。可是redis的單線程的,keys指令會致使線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。面試
這個時候可以使用scan指令,scan指令能夠無阻塞的提取出指定模式的key列表,可是會有必定的重複機率,在客戶端作一次去重就能夠了,可是總體所花費的時間會比直接用keys指令長。redis
Redis有5個基本數據結構,string、list、hash、set和zset。
算法
Redis列表是簡單的字符串列表,按照插入順序排序。可添加一個元素到列表頭部或尾部
List爲一個雙向的鏈表,便可用做棧,也能夠用做隊列。List同時支持頭和尾的操做
sql
Redis 列表命令
Redis Lpush 命令將一個或多個值插入到列表頭部。
Redis Rpop 命令用於移除並返回列表的最後一個元素。
Redis Lrange 返回列表中指定區間內的元素,區間以偏移量 START 和 END 指定。
應用:
一、消息隊列
二、文章列表或者數據分頁展現的應用
三、例如新聞列表頁面最新的新聞列表
zset應用:排行榜zset:字典與跳躍表數據庫
其中,字典(也稱爲hashtable或散列表)api
Strings類型:一個String類型的value最大能夠存儲512M
Lists類型:list的元素個數最多爲2^32-1個,也就是4294967295個。
Sets類型:元素個數最多爲2^32-1個,也就是4294967295個。
Hashes類型:鍵值對個數最多爲2^32-1個,也就是4294967295個。
Sorted sets類型:跟Sets類型類似。
一、緩存穿透,是指查詢一個必定不存在的數據,因爲緩存是不命中時被動寫( 被動寫,指的是從 DB 查詢到數據,則更新到緩存中 )的,而且處於容錯考慮,若是從 DB 查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到 DB 去查詢,失去了緩存的意義。 在流量大時,可能 DB 就掛掉了,要是有人利用不存在的 key 頻繁攻擊咱們的應用,這就是漏洞。
解決方法:
方案一,緩存空對象:當從 DB 查詢數據爲空,咱們仍然將這個空結果進行緩存,具體的值須要使用特殊的標識,能和真正緩存的數據區分開。另外,須要設置較短的過時時間,通常建議不要超過 5 分鐘。
方案二,BloomFilter 布隆過濾器:在緩存服務的基礎上,構建 BloomFilter 數據結構,在 BloomFilter 中存儲對應的 KEY 是否存在,若是存在,說明該 KEY 對應的值爲空。
- 簡介:布隆過濾器其實是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器能夠用於檢索一個元素是否在一個集合中。它的優勢是空間效率和查詢時間都遠遠超過通常的算法,缺點是有必定的誤識別率和刪除困難。
- 原理:當一個元素被加入集合時,經過K個散列函數將這個元素映射成一個位數組中的K個點,把它們置爲1。檢索時,咱們只要看看這些點是否是都是1就(大約)知道集合中有沒有它了:若是這些點有任何一個0,則被檢元素必定不在;若是都是1,則被檢元素極可能在。
- 思想步驟:
1. 位數組:初始狀態時,BloomFilter是一個長度爲m的位數組,每一位都置爲0。
2. 添加元素(k個獨立的hash函數)
添加元素時,對x使用k個哈希函數獲得k個哈希值,對m取餘,對應的bit位設置爲1。
3. 判斷元素是否存在
判斷y是否屬於這個集合,對y使用k個哈希函數獲得k個哈希值,對m取餘,全部對應的位置都是1,則認爲y屬於該集合(哈希衝突,可能存在誤判),不然就認爲y不屬於該集合。原文連接:https://blog.csdn.net/qq_18495465/article/details/78500472
二、緩存雪崩,是指緩存因爲某些緣由沒法提供服務( 例如,緩存掛掉了 ),全部請求所有達到 DB 中,致使 DB 負荷大增,最終掛掉的狀況。
解決方法:
1)緩存高可用
2)本地緩存
3)請求 DB 限流
4)服務降級
5)提早演練
一、純內存操做。 Redis 爲了達到最快的讀寫速度,將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。因此 Redis 具備快速和數據持久化的特徵。 若是不將數據放在內存中,磁盤 I/O 速度爲嚴重影響 Redis 的性能。
二、核心是基於非阻塞的 IO 多路複用機制。
三、單線程反而避免了多線程的頻繁上下文切換問題。 Redis 利用隊列技術,將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷
四、Redis 全程使用 hash 結構,讀取速度快,還有一些特殊的數據結構,對數據存儲進行了優化,如壓縮表,對短數據進行壓縮存儲,再如,跳錶,使用有序的數據結構加快讀取的速度。
學習:IO多路複用的三種機制Select,Poll,Epoll 從新學習
redis 採用網絡IO多路複用技術來保證在多鏈接的時候, 系統的高吞吐量。
多路-指的是多個socket鏈接,複用-指的是複用一個線程。多路複用主要有三種技術:select,poll,epoll。epoll是最新的也是目前最好的多路複用技術。
這裏「多路」指的是多個網絡鏈接,「複用」指的是複用同一個線程。採用多路I/O複用技術可讓單個線程高效的處理多個鏈接請求(儘可能減小網絡IO的時間消耗),且Redis在內存中操做數據的速度很是快(內存內的操做不會成爲這裏的性能瓶頸),主要以上兩點造就了Redis具備很高的吞吐量。
1.在寫庫先後都進行redis.del(key)操做,而且設定合理的超時時間。
2.具體的步驟就是:
1)先刪除緩存
2)再寫數據庫
3)休眠500毫秒:須要評估本身的項目的讀數據業務邏輯的耗時
4)再次刪除緩存
3.設置緩存過時時間
從理論上來講,給緩存設置過時時間,是保證最終一致性的解決方案。全部的寫操做以數據庫爲準,只要到達緩存過時時間,則後面的讀請求天然會從數據庫中讀取新值而後回填緩存。
4.該方案的弊端
結合雙刪策略+緩存超時設置,這樣最差的狀況就是在超時時間內數據存在不一致,並且又增長了寫請求的耗時。
1.技術總體思路:
MySQL binlog增量訂閱消費+消息隊列+增量數據更新到redis
1)讀Redis:熱數據基本都在Redis
2)寫MySQL:增刪改都是操做MySQL
3)更新Redis數據:MySQ的數據操做binlog,來更新到Redis
2.Redis更新
1)數據操做主要分爲兩大塊:
這裏說的是增量,指的是mysql的update、insert、delate變動數據。
2)讀取binlog後分析 ,利用消息隊列,推送更新各臺的redis緩存數據。
這樣一旦MySQL中產生了新的寫入、更新、刪除等操做,就能夠把binlog相關的消息推送至Redis,Redis再根據binlog中的記錄,對Redis進行更新。
其實這種機制,很相似MySQL的主從備份機制,由於MySQL的主備也是經過binlog來實現的數據一致性。
這裏能夠結合使用canal(阿里的一款開源框架),經過該框架能夠對MySQL的binlog進行訂閱,而canal正是模仿了mysql的slave數據庫的備份請求,使得Redis的數據更新達到了相同的效果。
固然,這裏的消息推送工具你也能夠採用別的第三方:kafka、rabbitMQ等來實現推送更新Redis。
以上就是Redis和MySQL數據一致性詳解
摘自:零壹技術棧
在 Redis 中,實現 高可用 的技術主要包括 持久化、複製、哨兵 和 集羣,下面簡單說明它們的做用,以及解決了什麼樣的問題:
主:寫,從:讀
Redis 主從複製可將主節點數據同步給從節點,從節點此時有兩個做用:
主從複製同時存在如下幾個問題:
- 一旦主節點宕機,從節點晉升成主節點,同時須要修改應用方的主節點地址,還須要命令全部 從節點去複製新的主節點,整個過程須要人工干預。
- 主節點的寫能力受到單機的限制。
- 主節點的存儲能力受到單機的限制。
- 原生複製 的弊端在早期的版本中也會比較突出,好比:Redis 複製中斷 後,從節點 會發起 psync。此時若是 同步不成功,則會進行 全量同步,主庫 執行 全量備份 的同時,可能會形成毫秒或秒級的卡頓。
哨兵模式就是不時地監控redis是否按照預期良好地運行(至少是保證主節點是存在的),若一臺主機出現問題時,哨兵會自動將該主機下的某一個從機設置爲新的主機,並讓其餘從機和新主機創建主從關係。
哨兵模式也存在單點故障問題,若是哨兵機器掛了,那麼就沒法進行監控了,解決辦法是哨兵也創建集羣,Redis哨兵模式是支持集羣的。
Sentinel 的主要功能包括 主節點存活檢測、主從運行狀況檢測、自動故障轉移 、主從切換。Redis 的 Sentinel 最小配置是 一主一從。
Redis 的 Sentinel 系統能夠用來管理多個 Redis 服務器,該系統能夠執行如下四個任務:
Sentinel 會不斷的檢查 主服務器 和 從服務器 是否正常運行。
當被監控的某個 Redis 服務器出現問題,Sentinel 經過 API 腳本 向 管理員 或者其餘的 應用程序 發送通知。
當主節點不能正常工做時,Sentinel 會開始一次自動的故障轉移操做,它會將與失效主節點是主從關係的其中一個從節點升級爲新的主節點,而且將其餘從節點指向新的主節點
在 Redis Sentinel 模式下,客戶端應用 在初始化時鏈接的是 Sentinel 節點集合,從中獲取主節點的信息。
redis集羣核心原理:gossip通訊、jedis Smart定位、主備切換
可能會懵逼,又是 Redis 主從複製,又是 Redis 分區,又是 Redis 集羣。傻傻分不清啊!
客戶端就已經決定數據會被存儲到哪一個 redis 節點或者從哪一個 redis 節點 讀取數據。其主要思想是採用 哈希算法 將 Redis 數據的 key 進行散列,經過 hash 函數,特定的 key會 映射 到特定的 Redis 節點上。
優勢:不使用第三方中間件,分區邏輯可控,配置簡單,節點之間無關聯,容易線性擴展,靈活性強。
缺點:客戶端沒法動態增刪服務節點,客戶端須要自行維護分發邏輯,客戶端之間無鏈接共享,會形成鏈接浪費。
代理分區,意味着客戶端將請求發送給代理,而後代理決定去哪一個節點寫數據或者讀數據。代理根據分區規則決定請求哪些 Redis 實例,而後根據 Redis 的響應結果返回給客戶端。
優勢:簡化客戶端的分佈式邏輯,客戶端透明接入,切換成本低,代理的轉發和存儲分離
缺點:多了一層代理層,加劇了 架構部署複雜度和性能損耗。
代理分區主流實現的有方案有 Twemproxy 和 Codis。
01. Twemproxy
Twemproxy 也叫 nutcraker,是 twitter 開源的一個 redis 和 memcache 的 中間代理服務器 程序。Twemproxy 做爲 代理,可接受來自多個程序的訪問,按照 路由規則,轉發給後臺的各個 Redis 服務器,再原路返回。Twemproxy 存在單點故障問題,須要結合 Lvs 和 Keepalived 作 高可用方案。
02. Codis
Codis 是一個 分佈式 Redis 解決方案,對於上層應用來講,鏈接 Codis-Proxy 和直接鏈接 原生的 Redis-Server 沒有的區別。Codis 底層會 處理請求的轉發,不停機的進行 數據遷移 等工做。Codis 採用了無狀態的 代理層,對於 客戶端 來講,一切都是透明的。
客戶端隨機地 請求任意一個 Redis 實例,而後由 Redis 將請求 轉發 給 正確 的 Redis 節點。Redis Cluster 實現了一種 混合形式 的 查詢路由,但並非 直接 將請求從一個 Redis 節點 轉發 到另外一個 Redis 節點,而是在 客戶端 的幫助下直接 重定向( redirected)到正確的 Redis 節點。
開源方案 Redis-cluster
Hash slot。集羣內的每一個redis實例監聽兩個tcp端口,6379(默認)用於服務客戶端查詢,16379(默認服務端口 + 10000)用於集羣內部通訊。
- key的空間被分到16384個hash slot裏;
- 計算key屬於哪一個slot,CRC16(key) & 16384。
- 用hash tag能夠手動指定key對應的slot,同一個hash tag下的key,都會在一個hash slot中,好比set mykey1:{100}和set mykey2:{100};
- 節點間狀態同步:gossip協議,最終一致性。節點間通訊使用輕量的二進制協議,減小帶寬佔用。
- 16379 端口號是用來進行節點間通訊的,也就是 cluster bus 的東西,cluster bus 的通訊,用來進行故障檢測、配置更新、故障轉移受權。cluster bus 用了另一種二進制的協議,
gossip
協議,用於節點間進行高效的數據交換,佔用更少的網絡帶寬和處理時間。
Redis-Cluster藉助客戶端實現了混合形式的路由查詢
查詢路由並不是直接從一個redis節點到另一個redis,而是藉助客戶端轉發到正確的節點。根據客戶端的實現方式,能夠分爲如下兩種:包括Jedis在內的許多redis client,已經實現了對Redis Cluster的支持。
Redis cluster採用這種架構的考慮:
具體路由過程
- 減小redis實現的複雜度
- 下降客戶端等待的時間。Smart client能夠在客戶端緩存 slot 與 redis節點的映射關係,當接收到 MOVED 響應時,會修改緩存中的映射關係。請求時會直接發送到正確的節點上,減小一次交互。
Redis Cluster 的客戶端相比單機Redis 須要具有路由語義的識別能力,且具有必定的路由緩存能力。當Client 訪問的key 不在當前Redis 節點的 slots 中,Redis 會返回給Client 一個moved命令。並告知其正確的路由信息,以下所示:
當Client 接收到moved 後,再次請求新的Redis時,此時Cluster 的結構又可能發生了變化(slot 遷移)。此時有可能再次返回moved 。Client 會根據 moved響應,更新其內部的路由緩存信息,以便後續的操做直接找到正確的節點,減小交互次數。
基於重定向的客戶端,很消耗網絡io,由於大部分狀況下,可能都會出現一次請求重定向,才能找到正確的節點; 因此大部分的客戶端好比java redis客戶端,都是jedis,都是smart的,
本地維護一份hashslot -> node的映射表在緩存裏,大部分狀況下直接走本地緩存就能夠找到hashslot -> node,不須要經過節點進行moved重定向;
redis-cluster羣集高可用架構:參考
若是一個節點認爲另一個節點宕機,name就是pfail,主觀宕機;
若是多個節點都認爲另一個節點宕機了,那麼就是fail,客觀宕機,跟哨兵的原理幾乎同樣,sdown,odown;
在cluster-node-timeout內,某個節點一直沒有返回pong,那麼就被認爲pfail;
若是一個節點認爲某個節點pfail了,那麼會在gossip ping消息中,ping給其餘節點,若是超過半數的節點都認爲pfail了,那麼就會變成fail;
對宕機的master node,從其全部的slave node中,選擇一個切換成master node;
檢查每一個slave node與master node斷開鏈接的時間,若是超過了cluster-node-timeout * cluster-slave-validity-factor,那麼就沒有資格切換成master;
哨兵:對全部從節點進行排序,slave priority,offset,run id;
每一個從節點,都根據本身對master複製數據的offset,來設置一個選舉時間,offset越大(複製數據越多)的從節點,選舉時間越靠前,優先進行選舉;
全部的master node開始slave選舉投票,給要進行選舉的slave進行投票,若是大部分master node(N/2 + 1)都投票給了某個從節點,那麼選舉經過,那個從節點能夠切換成master;
從節點執行主備切換,從節點切換爲主節點;
整個流程跟哨兵相比,很是相似,因此說,redis cluster功能強大,直接集成了replication和sentinal的功能;
redis集羣核心原理: 轉載自 https://blog.csdn.net/qq_33814629/article/details/79904158
來了一個 key,首先計算 hash 值,而後對節點數取模。使用公式:hash(key)% N
計算出 哈希值,用來決定數據 映射 到哪個節點上。 而後打在不一樣的 master 節點上。
一旦某一個 master 節點宕機,全部請求過來,都會基於最新的剩餘 master 節點數去取模,嘗試去取數據。這會致使大部分的請求過來,所有沒法拿到有效的緩存,致使大量的流量涌入數據庫。
一致性 hash 算法將整個 hash 值空間組織成一個虛擬的圓環,整個空間按順時針方向組織,下一步將各個 master 節點(使用服務器的 ip 或主機名)進行 hash。這樣就能肯定每一個節點在其哈希環上的位置。
來了一個 key,首先計算 hash 值,並肯定此數據在環上的位置,今後位置沿環順時針「行走」,遇到的第一個 master 節點就是 key 所在位置。
在一致性哈希算法中,若是一個節點掛了,受影響的數據僅僅是此節點到環空間前一個節點(沿着逆時針方向行走遇到的第一個節點)之間的數據,其它不受影響。增長一個節點也同理。
燃鵝,一致性哈希算法在節點太少時,容易由於節點分佈不均勻而形成緩存熱點的問題。爲了解決這種熱點問題,一致性 hash 算法引入了虛擬節點機制,即對每個節點計算多個 hash,每一個計算結果位置都放置一個虛擬節點。這樣就實現了數據的均勻分佈,負載均衡。
redis cluster 有固定的 16384
個 hash slot,對每一個 key
計算 CRC16
值,而後對 16384
取模,能夠獲取 key 對應的 hash slot。
redis cluster 中每一個 master 都會持有部分 slot,好比有 3 個 master,那麼可能每一個 master 持有 5000 多個 hash slot。hash slot 讓 node 的增長和移除很簡單,增長一個 master,就將其餘 master 的 hash slot 移動部分過去,減小一個 master,就將它的 hash slot 移動到其餘 master 上去。移動 hash slot 的成本是很是低的。客戶端的 api,能夠對指定的數據,讓他們走同一個 hash slot,經過 hash tag
來實現。
任何一臺機器宕機,另外兩個節點,不影響的。由於 key 找的是 hash slot,不是機器。
Redis 提供 RDB 和 AOF 兩種數據的持久化存儲方案,解決內存數據庫最擔憂的萬一 Redis 掛掉,數據會消失。
Redis 提供了兩種方式來將數據持久化到硬盤。
如何選擇
Redis 支持同時開啓開啓兩種持久化方式,咱們能夠綜合使用 AOF 和 RDB 兩種持久化機制,用 AOF 來保證數據不丟失,做爲數據恢復的第一選擇; 用 RDB 來作不一樣程度的冷備,在 AOF 文件都丟失或損壞不可用的時候,還可使用 RDB 來進行快速的數據恢復。
默認 Redis 是會以快照 「RDB」 的形式將數據持久化到磁盤的,一個二進 制文件,dump.rdb
工做原理簡單介紹一下:當 Redis 須要作持久化時,Redis 會 fork 一個子進程,子進程將數據寫到磁盤上一個臨時 RDB 文件中。當子進程完成寫臨時文件後,將原來的 RDB 替換掉,這樣的好處就是能夠 copy-on-write。
Redis默認狀況下,是快照 RDB 的持久化方式,將內存中的數據以快照的方式寫入二進制文件中,默認的文件名是 dump.rdb 。固然咱們也能夠手動執行 save 或者 bgsave(異步)作快照。
使用 AOF 作持久化,每個寫命令都經過write函數追加到 appendonly.aof 中,配置方式:啓動 AOF 持久化的方式
Redis.conf配置
appendfsync yes
appendfsync always #每次有數據修改發生時都會寫入AOF文件。
appendfsync everysec #每秒鐘同步一次,該策略爲AOF的缺省策略。複製代碼
若是你很是關心你的數據,但仍然能夠承受數分鐘之內的數據丟失, 那麼你能夠只使用 RDB 持久。 AOF 將 Redis 執行的每一條命令追加到磁盤中,處理巨大的寫入會下降 Redis 的性能,不知道你是否能夠接受。 數據庫備份和災難恢復:定時生成 RDB 快照(snapshot)很是便於進行數據庫備份, 而且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快。
Redis 支持同時開啓 RDB 和 AOF,系統重啓後,Redis 會優先使用 AOF 來恢復數據,這樣丟失的數據會最少。
參考:https://juejin.im/post/5bb02c42e51d450e92524b6f
參考:在面試pdd的時候有問到相關的問題:
1. 全部的過時指令最終都變成了PEXPIREAT指令
2. redis保存一份過時字典,鍵是一個指針,指向某個鍵對象,值是過時時間,一個毫秒精度的時間戳。過時字典與鍵空間中的鍵指向的是一個地址,不存在空間浪費。
redis採用的是惰性刪除跟按期刪除。
參考:
連接:https://juejin.im/post/5bb02c42e51d450e92524b6f
http://youzhixueyuan.com/reasons-for-redis-fast.html
http://youzhixueyuan.com/redis-cache-and-mysql-data-consistency.html
http://svip.iocoder.cn/Redis/Interview/#Redis-