Redis全面解析零:redis從入門到精通

前言

Redis 也是中高級後端工程師技術面試中,面試官最喜歡問的問題之一。特別是那些優秀的、競爭激烈的大型互聯網公司,通常要求面試者不僅僅掌握 Redis 基礎使用,更要求深層理解 Redis 內部實現的細節原理。毫不誇張地說,能把 Redis 的知識點全部吃透,你的半隻腳就已經踏進心儀大公司的技術研發部。

定義

Redis 本質上是一個 Key-Value 類型的內存非關係數據庫, 整個數據庫加載在內存當中進行操作, 定期通過異步操作把數據庫數據 flush 到硬盤上進行保存。

  • Redis 的性能非常出色, 每秒可以處理超過 10 萬次讀寫操作, 是已知性能最快的 Key-Value DB。
  • Redis 最大的魅力是支持保存多種數據結構
  • 單個value 的最大限制是 1GB, 不像 memcached 只能保存 1MB 的數據
  • Redis 也可以對存入的Key-Value 設置 expire 時間
  • Redis 的主要缺點是數據庫容量受到物理內存的限制, 不能用作海量數據的高性能讀寫

Redis和Memcache區別

  • 存儲方式:memcache 把數據全部存在內存之中,斷電後會掛掉,而redis支持持久化。
  • Redis在存儲小數據量時比Memcached性能更高。而在100k以上的數據時,Memcached性能要高於Redis
  • 數據支持類型:redis在數據支持上要比memecache多的多。
  • Memcached本身並不支持分佈式,因此只能在客戶端通過像一致性哈希這樣的分佈式算法來實現Memcached的分佈式存儲。Redis更偏向於在服務器端構建分佈式存儲

Redis版本新增的一些新特性記錄

  • 部分複製(Redis 2.8.18):用來解決主節點在快照同步時大量IO影響效率的問題。
  • Redis在3.0版正式引入了集羣這個特性
  • Redis在4.0版正式引入了混合持久化:RDB加AOF混合持久化的方式。
  • Redis 5.0引入的一種新數據類型:Stream數據結構,用來持久化消息隊列

Redis 數據類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

①string 類型是 Redis 最基本的數據類型,string 類型的值最大能存儲 512MB。Redis 常用 SET 和 GET 命令。

②Redis hash 是一個鍵值(key=>value)對集合。Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用於存儲對象。Redis 中每個 hash 可以存儲 232 - 1 鍵值對(40多億)。命令示例:HMSET runoob field1 "Hello" field2 "World"     HGET runoob field1

③Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。命令示例:  lpush runoob redis       lrange runoob 0 10

④Redis 的 Set 是 string 類型的無序集合。集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1)。命令示例:sadd runoob redis       smembers runoob

⑤Redis zset 和 set 一樣也是string類型元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來爲集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。命令示例:  zadd runoob 0 redis      ZRANGEBYSCORE runoob 0 1000

Redis 事務

一個事務從開始到執行會經歷以下三個階段:先以 MULTI 開始一個事務, 然後將多個命令入隊到事務中, 最後由 EXEC 命令觸發事務, 一併執行事務中的所有命令

①開始事務:MULTI命令的執行標誌着事務的開始,MULTI命令可以將執行該命令的客戶端從非事務狀態切換至事務狀態。

127.0.0.1:6379> MULTI
OK

② 命令入隊:事務隊列是一個以先進先出(FIFO)的方式保存入隊的命令,較先入隊的命令會被放到數組的前面,而較後入隊的命令則會被放到數組的後面

127.0.0.1:6379>> MULTI
OK

127.0.0.1:6379>> set name Redis;
QUEUED

127.0.0.1:6379>> get name;
QUEUED

127.0.0.1:6379>> set author "Peter Seibei";
QUEUED

127.0.0.1:6379>> get author;
QUEUED

③ 執行事務:

當一個處於事務狀態的客戶端向服務器發送EXEC命令時,這個EXEC命令將立即被服務器執行。服務器會遍歷這個客戶端的事務隊列,執行隊列中保存的所有的命令,最後將執行命令所得的結果返回給客戶端。對於上例子:

127.0.0.1:6379> EXEC
1) OK
2) "Redis"
3) OK
4) "Peter Seibei"

 注:redis事務特性

事務在執行過程中不會被中斷,當事務隊列中的所有命令都被執行完畢之後,事務
纔會結束。

②Redis事務不支持回滾機制,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做。

③在事務執行過程,其他客戶端提交的命令請求不會插入到事務執行命令序列中。

不支持回滾的理由:

1、redis認爲,失敗都是由命令使用不當造成

2、redis這樣做,是爲了保持內部實現簡單快速

3、redis還認爲,回滾並不能解決所有問題

redis緩存雪崩和穿透 

緩存雪崩:可能是因爲數據未加載到緩存中,或者緩存同一時間大面積的失效,從而導致所有請求都去查數據庫,導致數據庫CPU和內存負載過高,甚至宕機。解決思路:

  • 加鎖計數(即限制併發的數量,可以用semphore)或者起一定數量的隊列來避免緩存失效時大量請求併發到數據庫。但這種方式會降低吞吐量。
  • 分析用戶行爲,然後失效時間均勻分佈。或者在失效時間的基礎上再加1~5分鐘的隨機數。
  • 如果是某臺緩存服務器宕機,則考慮做主備。

緩存穿透:指用戶查詢數據,在數據庫沒有,自然在緩存中也不會有。這樣就導致用戶查詢的時候,在緩存中找不到,每次都要去數據庫中查詢。解決思路:

  • 如果查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫。設置一個過期時間或者當有值的時候將緩存中的值替換掉即可。
  • 可以給key設置一些格式規則,然後查詢之前先過濾掉不符合規則的Key。

緩存併發:如果網站併發訪問高,一個緩存如果失效,可能出現多個進程同時查詢DB,同時設置緩存的情況,如果併發確實很大,這也可能造成DB壓力過大,還有緩存頻繁更新的問題。解決思路:

  • 對緩存查詢加鎖,如果KEY不存在,就加鎖,然後查DB入緩存,然後解鎖;其他進程如果發現有鎖就等待,然後等解鎖後返回數據或者進入DB查詢。

redis如何保障數據熱點-數據淘汰策略

場景:

數據庫中有1000w的數據,而redis中只有50w數據,如何保證redis中10w數據都是熱點數據?

方案1:

 限定 Redis 佔用的內存,Redis 會根據自身數據淘汰策略,留下熱數據到內存。所以,計算一下 50W 數據大約佔用的內存,然後設置一下 Redis 內存限制即可,並將淘汰策略爲volatile-lru或者allkeys-lru。  

redis 內存數據集大小上升到一定大小的時候,會施行數據淘汰策略。redis 提供 6種數據淘汰策略:

  • volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
  • volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
  • volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
  • allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
  • allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
  • no-enviction(驅逐):禁止驅逐數據

方案2:

只是把Redis當緩存來用.提供一種簡單實現緩存失效的思路: LRU(最近少用的淘汰)即redis的緩存每命中一次,就給命中的緩存增加一定ttl(過期時間)(根據具體情況來設定, 比如10分鐘).一段時間後, 熱數據的ttl都會較大, 不會自動失效, 而冷數據基本上過了設定的ttl就馬上失效了.

redis緩存與數據庫一致性解決方案

一致性解決方式

  • 緩存雙淘汰,傳統的玩法在進行寫操作的時候,先淘汰cache再寫主庫。在主從同步時間窗口之內可能有髒數據入cache,此時如果再發起一個異步的淘汰,即使不一致時間窗內臟數據入了cache,也會再次淘汰掉。
  • 使用中間件,業務層不直接訪問數據庫,而是通過中間件訪問數據庫,這個中間件會記錄哪一些key上發生了寫請求,在數據主從同步時間窗口之內,如果key上又出了讀請求,就將這個請求也路由到主庫上去,使用這個方法來保證數據的一致性。
  • 使用隊列,創建幾個隊列如20個,根據key值去做hash值,然後對隊列量進行取模決定放到哪個隊列中。先把它放進隊列裏,當有數據更新請求時,先看下緩存有沒有數據,如果沒有再去隊列中查看是否有相同的key在做更新,如果有也把查詢的請求放到隊列中,然後同步等待緩存更新成功。當更新完時從隊列裏去除。

常見問題:

查看Redis使用情況及狀態信息用什麼命令?

info

Jedis與Redisson對比有什麼優缺點?

Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持;Redisson是一個高級的分佈式協調Redis客服端,Redisson實現了分佈式和可擴展的Java數據結構,和Jedis相比,功能較爲簡單,不支持字符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。

 

文章參考:

https://www.toutiao.com/a6747926805744730627/

 

 

 

 

 

 

 

只是把Redis當緩存來用.提供一種簡單實現緩存失效的思路: LRU(最近少用的淘汰)即redis的緩存每命中一次,就給命中的緩存增加一定ttl(過期時間)(根據具體情況來設定, 比如10分鐘).

一段時間後, 熱數據的ttl都會較大, 不會自動失效, 而冷數據基本上過了設定的ttl就馬上失效了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章