看了看網上大佬關于redis的各種見解,自己也統籌的整理一下。
1.Redis 是 C 語言開發的一個開源的(遵從 BSD 協定)高性能鍵值對(key-value)的記憶體資料庫,可以用作資料庫、緩存、消息中間件等。
2.它是一種 NoSQL(not-only sql,泛指非關系型資料庫)的資料庫。
3.Redis 作為一個記憶體資料庫:
性能優秀,資料在記憶體中,讀寫速度非常快,支援并發 10W QPS。單程序單線程,是線程安全的,采用 IO 多路複用機制。支援資料持久化。可以将記憶體中資料儲存在磁盤中,重新開機時加載。主從複制,哨兵,高可用。可以用作分布式鎖。可以作為消息中間件使用,支援釋出訂閱。
相信大部分開發人員都能回答出來:String、Hash、List、Set、SortedSet。
簡單說一下這5種基本類型:
首先 Redis 内部使用一個 redisObject 對象來表示所有的 key 和 value。
①String 是 Redis 最基本的類型,可以了解成與 Memcached一模一樣的類型,一個 Key 對應一個 Value。Value 不僅是 String,也可以是數字。
String 類型是二進制安全的,意思是 Redis 的 String 類型可以包含任何資料,比如 jpg 圖檔或者序列化的對象。String 類型的值最大能存儲 512M。
②Hash是一個鍵值(key-value)的集合。Redis 的 Hash 是一個 String 的 Key 和 Value 的映射表,Hash 特别适合存儲對象。常用指令:hget,hset,hgetall 等。
③List 清單是簡單的字元串清單,按照插入順序排序。可以添加一個元素到清單的頭部(左邊)或者尾部(右邊) 常用指令:lpush、rpush、lpop、rpop、lrange(擷取清單片段)等。
應用場景:List 應用場景非常多,也是 Redis 最重要的資料結構之一,比如 Twitter 的關注清單,粉絲清單都可以用 List 結構來實作。
資料結構:List 就是連結清單,可以用來當消息隊列用。Redis 提供了 List 的 Push 和 Pop 操作,還提供了操作某一段的 API,可以直接查詢或者删除某一段的元素。
實作方式:Redis List 的是實作是一個雙向連結清單,既可以支援反向查找和周遊,更友善操作,不過帶來了額外的記憶體開銷。
④Set 是 String 類型的無序集合。集合是通過 hashtable 實作的。Set 中的元素是沒有順序的,而且是沒有重複的。常用指令:sdd、spop、smembers、sunion 等。
應用場景:Redis Set 對外提供的功能和 List 一樣是一個清單,特殊之處在于 Set 是自動去重的,而且 Set 提供了判斷某個成員是否在一個 Set 集合中。
⑤Sorted Set 和 Set 一樣是 String 類型元素的集合,且不允許重複的元素。常用指令:zadd、zrange、zrem、zcard 等。
使用場景:Sorted Set 可以通過使用者額外提供一個優先級(score)的參數來為成員排序,并且是插入有序的,即自動排序。
當你需要一個有序的并且不重複的集合清單,那麼可以選擇 SortedSet 結構。
和 Set 相比,Sorted Set關聯了一個 Double 類型權重的參數 Score,使得集合中的元素能夠按照 Score 進行有序排列,Redis 正是通過分數來為集合中的成員進行從小到大的排序。
當然除此之外,redis的資料結構還有Redis Module,像BloomFilter,RedisSearch,Redis-ML。
一般有兩種方式,一種是直接通過 RedisTemplate 來使用,另一種是使用 Spring Cache 內建 Redis(也就是注解的方式)。
因為傳統的關系型資料庫如Mysql已經不能适用所有的場景了,比如秒殺的庫存扣減,APP首頁的通路流量高峰等等,都很容易把資料庫打崩,是以引入了緩存中間件,目前市面上比較常用的緩存中間件有 Redis 和 Memcached 不過中和考慮了他們的優缺點,最後選擇了Redis。
1.存儲方式上:Memcache 會把資料全部存在記憶體之中,斷電後會挂掉,資料不能超過記憶體大小。
Redis 有部分資料存在硬碟上,這樣能保證資料的持久性。
2.資料支援類型上:Memcache 對資料類型的支援簡單,隻支援簡單的 key-value,,而 Redis 支援五種資料類型。
3.使用底層模型不同:它們之間底層實作方式以及與用戶端之間通信的應用協定不一樣。Redis 直接自己建構了 VM 機制,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
4.value 的大小:Redis 可以達到 1GB,而 Memcache 隻有 1MB。
我們拿電商的項目舉個例子,如果首頁所有 Key 的失效時間都是 12 小時,中午 12 點重新整理的,我零點有個大促活動大量使用者湧入,假設每秒 6000 個請求,本來緩存可以抗住每秒 5000 個請求,但是緩存中所有 Key 都失效了。
此時 6000 個/秒的請求全部落在了資料庫上,資料庫必然扛不住。即便重新開機資料庫,但是資料庫立馬又被新流量給擊垮,這就是通俗意思上的redis雪崩。
1.在批量往 Redis 存資料的時候,把每個 Key 的失效時間都加個随機值,這樣可以保證資料不會再同一時間大面積失效。
setRedis(key, value, time+Math.random()*10000)
2.如果 Redis 是叢集部署,将熱點資料均勻分布在不同的 Redis 庫中也能避免全部失效。或者設定熱點資料永不過期,有更新操作就更新緩存。
1.緩存穿透是指緩存和資料庫中都沒有的資料,而使用者(黑客)不斷發起請求。
舉一個小例子:假如我們資料庫的 id 都是從 1 自增的,如果發起 id=-1 的資料或者 id 特别大不存在的資料,這樣的不斷攻擊導緻資料庫壓力很大,嚴重會擊垮資料庫。
2.緩存擊穿跟緩存雪崩有點像,但是有一點不一樣,緩存雪崩是因為大面積的緩存失效,打崩了 DB。
而緩存擊穿是指一個 Key 非常熱點,在不停地扛着大量的請求,大并發集中對這一個點進行通路,當這個 Key 在失效的瞬間,持續的大并發直接落到了資料庫上,就在這個 Key 的點上擊穿了緩存。
1.對于緩存穿透,一般在接口層增加校驗。比如使用者鑒權,參數做校驗,不合法的校驗直接 return,比如 id 做基礎校驗,id<=0 直接攔截。
或者使用應對緩存穿透的利器-----BloomFilter。
2.對于緩存擊穿,設定熱點資料永不過期,或者加上互斥鎖。
Redis 完全基于記憶體,絕大部分請求是純粹的記憶體操作,非常迅速,資料存在記憶體中,類似于 HashMap,HashMap 的優勢就是查找和操作的時間複雜度是 O(1)。資料結構簡單,對資料操作也簡單。采用單線程,避免了不必要的上下文切換和競争條件,不存在多線程導緻的 CPU 切換,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有死鎖問題導緻的性能消耗。使用多路複用 IO 模型,非阻塞 IO。
使用keys指令可以掃出指定模式的key清單。
Redis的單線程的。keys指令會導緻線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢複。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key清單,但是會有一定的重複機率,在用戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
但是并不是說scan指令就是那麼完美的。舉一個例子: 使用 SMEMBERS 指令可以傳回集合鍵目前包含的所有元素, 但是對于 SCAN 這類增量式疊代指令來說, 因為在對鍵進行增量式疊代的過程中, 鍵可能會被修改, 是以增量式疊代指令隻能對被傳回的元素提供有限的保證 。
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)中任意選擇資料淘汰。
n加粗樣式o-enviction(驅逐):禁止驅逐資料。
Redis 為了保證效率,資料緩存在了記憶體中,但是會周期性的把更新的資料寫入磁盤或者把修改操作寫入追加的記錄檔案中,以保證資料的持久化。
Redis 的持久化政策有兩種:
1.RDB:快照形式是直接把記憶體中的資料儲存到一個 dump 的檔案中,定時儲存,儲存政策。
2.AOF:把所有的對 Redis 的伺服器進行修改的指令都存到一個檔案裡,指令的集合。Redis 預設是快照 RDB 的持久化方式。
當 Redis 重新開機的時候,它會優先使用 AOF 檔案來還原資料集,因為 AOF 檔案儲存的資料集通常比 RDB 檔案所儲存的資料集更完整。你甚至可以關閉持久化功能,讓資料隻在伺服器運作時存。
取決于AOF日志sync屬性的配置,如果不要求性能,在每條寫指令時都sync一下磁盤,就不會丢失資料。但是在高性能的要求下每次都sync是不現實的,一般都使用定時sync,比如1s1次,這個時候最多就會丢失1s的資料。
fork和cow。fork是指redis通過建立子程序來進行RDB操作,cow指的是copy on write,子程序建立後,父子程序共享資料段,父程序繼續提供讀寫服務,寫髒的頁面資料會逐漸和子程序分離開來。
1.RDB 的優點:這種檔案非常适合用于備份:比如,你可以在最近的 24 小時内,每小時備份一次,并且在每個月的每一天也備份一個 RDB 檔案。
這樣的話,即使遇上問題,也可以随時将資料集還原到不同的版本。RDB 非常适合災難恢複。
2.RDB 的缺點:如果你需要盡量避免在伺服器故障時丢失資料,那麼RDB不合适你。
AOF 的優點:會讓 Redis 變得非常耐久。可以設定不同的 Fsync 政策,AOF的預設政策是每秒鐘 Fsync 一次,在這種配置下,就算發生故障停機,也最多丢失一秒鐘的資料。
AOF 的缺點:對于相同的資料集來說,AOF 的檔案體積通常要大于 RDB 檔案的體積。根據所使用的 Fsync 政策,AOF 的速度可能會慢于 RDB。
1.如果可以承受數分鐘内的資料丢失,那麼可以使用 RDB 持久。
2.AOF 将 Redis 執行的每一條指令追加到磁盤中,處理巨大的寫入會降低Redis的性能。
3.資料庫備份和災難恢複:定時生成 RDB 快照非常便于進行資料庫備份,并且 RDB 恢複資料集的速度也要比 AOF 恢複的速度快。
當然,Redis 支援同時開啟 RDB 和 AOF,系統重新開機後,Redis 會優先使用 AOF 來恢複資料,這樣丢失的資料會最少。
Redis可以使用主從同步,從從同步。第一次同步時,主節點做一次bgsave,并同時将後續修改操作記錄到記憶體buffer,待完成後将RDB檔案全量同步到複制節點,複制節點接受完成後将RDB鏡像加載到記憶體。加載完成後,再通知主節點将期間修改的操作記錄同步到複制節點進行重放就完成了同步過程。後續的增量資料通過AOF日志同步即可,有點類似資料庫的binlog。
Redis Sentinal 着眼于高可用,在master當機時會自動将slave提升為master,繼續提供服務。
Redis Cluster 着眼于擴充性,在單個redis記憶體不足時,使用Cluster進行分片存儲。