vue.js+vuetify學習開發排坑:一個古怪的程式碼 v-slot:activator="{ on, attrs }"
1.Redis是什麼
Redis是C語言開發的一個開源的(遵從BSD協議)高效能鍵值對(key-value)的記憶體資料庫,可以用作資料庫、快取、訊息中介軟體等。它是一種NoSQL(not-only sql,泛指非關係型資料庫)的資料庫。Redis作為一個記憶體資料庫。
1、效能優秀,資料在記憶體中,讀寫速度非常快,支援併發10W QPS;
2、單程序單執行緒,是執行緒安全的,採用IO多路複用機制;
3、豐富的資料型別,支援字串(strings)、雜湊(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等;
4、支援資料持久化。可以將記憶體中資料儲存在磁碟中,重啟時載入;
5、主從複製,哨兵,高可用;
6、可以用作分散式鎖;
7、可以作為訊息中介軟體使用,支援釋出訂閱
2.五種資料型別
首先redis內部使用一個redisObject物件來表示所有的key和value,redisObject最主要的資訊如上圖所示:type表示一個value物件具體是何種資料型別,encoding是不同資料型別在redis內部的儲存方式。
比如:type=string表示value儲存的是一個普通字串,那麼encoding可以是raw或者int。
1、string是redis最基本的型別,可以理解成與memcached一模一樣的型別,一個key對應一個value。value不僅是string,也可以是數字。string型別是二進位制安全的,意思是redis的string型別可以包含任何資料,比如jpg圖片或者序列化的物件。string型別的值最大能儲存512M。
2、Hash是一個鍵值(key-value)的集合。redis的hash是一個string的key和value的對映表,Hash特別適合儲存物件。常用命令:hget,hset,hgetall等。
3、list列表是簡單的字串列表,按照插入順序排序。可以新增一個元素到列表的頭部(左邊)或者尾部(右邊) 常用命令:lpush、rpush、lpop、rpop、lrange(獲取列表片段)等。應用場景:list應用場景非常多,也是Redis最重要的資料結構之一,比如關注列表,粉絲列表都可以用list結構來實現。資料結構:list就是連結串列,可以用來當訊息佇列用。redis提供了List的push和pop操作,還提供了操作某一段的api,可以直接查詢或者刪除某一段的元素。實現方式:redis list的是實現是一個雙向連結串列,既可以支援反向查詢和遍歷,更方便操作,不過帶來了額外的記憶體開銷。
4、set是string型別的無序集合。集合是通過hashtable實現的。set中的元素是沒有順序的,而且是沒有重複的。常用命令:sdd、spop、smembers、sunion等。應用場景:redis set對外提供的功能和list一樣是一個列表,特殊之處在於set是自動去重的,而且set提供了判斷某個成員是否在一個set集合中。
5、zset和set一樣是string型別元素的集合,且不允許重複的元素。常用命令:zadd、zrange、zrem、zcard等。使用場景:sorted set可以通過使用者額外提供一個優先順序(score)的引數來為成員排序,並且是插入有序的,即自動排序。當你需要一個有序的並且不重複的集合列表,那麼可以選擇sorted set結構。和set相比,sorted set關聯了一個double型別權重的引數score,使得集合中的元素能夠按照score進行有序排列,redis正是通過分數來為集合中的成員進行從小到大的排序。實現方式:Redis sorted set的內部使用HashMap和跳躍表(skipList)來保證資料的儲存和有序,HashMap裡放的是成員到score的對映,而跳躍表裡存放的是所有的成員,排序依據是HashMap裡存的score,使用跳躍表的結構可以獲得比較高的查詢效率,並且在實現上比較簡單。
3.資料型別應用場景總結
型別 | 簡介 | 特性 | 場景 | |
---|---|---|---|---|
string(字串) | 二進位制安全 | 可以包含任何資料,比如jpg圖片或者序列化物件 | ||
Hash(字典) | 鍵值對集合,即程式語言中的map型別 | 適合儲存物件,並且可以像資料庫中的update一個屬性一樣只修改某一項屬性值 | 儲存、讀取、修改使用者屬性 | |
List(列表) | 連結串列(雙向連結串列) | 增刪快,提供了操作某一元素的api | 最新訊息排行;訊息佇列 | |
set(集合) | hash表實現,元素不重複 | 新增、刪除、查詢的複雜度都是O(1),提供了求交集、並集、差集的操作 | 共同好友;利用唯一性,統計訪問網站的所有Ip | |
sorted set(有序集合zset) | 將set中的元素增加一個權重引數score,元素按score有序排列 | 資料插入集合時,已經進行了天然排序 | 排行榜;帶權重的訊息佇列 |
結合spring boot使用的。一般有兩種方式,一種是直接通過RedisTemplate來使用,另一種是使用spring cache整合Redis
4.快取問題
快取和資料庫資料一致性問題
分散式環境下非常容易出現快取和資料庫間資料一致性問題,針對這一點,如果專案對快取的要求是強一致性的,那麼就不要使用快取。我們只能採取合適的策略來降低快取和資料庫間資料不一致的概率,而無法保證兩者間的強一致性。
合適的策略包括合適的快取更新策略,更新資料庫後及時更新快取、快取失敗時增加重試機制。
Redis雪崩
一般快取都是定時任務去重新整理,或者查不到之後去更新快取的,定時任務重新整理就有一個問題。舉個栗子:如果首頁所有Key的失效時間都是12小時,中午12點重新整理的,我零點有個大促活動大量使用者湧入,假設每秒6000個請求,本來快取可以抗住每秒5000個請求,但是快取中所有Key都失效了。此時6000個/秒的請求全部落在了資料庫上,資料庫必然扛不住,真實情況可能DBA都沒反應過來直接掛了,此時,如果沒什麼特別的方案來處理,DBA很著急,重啟資料庫,但是資料庫立馬又被新流量給打死了。這就是我理解的快取雪崩。
解決方案
在批量往Redis存資料的時候,把每個Key的失效時間都加個隨機值就好了,這樣可以保證資料不會再同一時間大面積失效。
setRedis(key, value, time+Math.random()*10000);
如果Redis是叢集部署,將熱點資料均勻分佈在不同的Redis庫中也能避免全部失效。或者設定熱點資料永不過期,有更新操作就更新快取就好了(比如運維更新了首頁商品,那你刷下快取就好了,不要設定過期時間)。
快取穿透和擊穿和雪崩的區別
快取穿透
快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,舉個栗子:我們資料庫的id都是從1自增的,如果發起id=-1的資料或者id特別大不存在的資料,這樣的不斷攻擊導致資料庫壓力很大,嚴重會擊垮資料庫。
解決方案
- 在介面層增加校驗,比如使用者鑑權,引數做校驗,不合法的校驗直接return,比如id做基礎校驗,id小於1直接攔截。
- 高階用法**布隆過濾器(Bloom Filter)**這個也能很好的預防快取穿透的發生,他的原理也很簡單,就是利用高效的資料結構和演算法快速判斷出你這個Key是否在資料庫中存在,不存在你return就好了,存在你就去查DB重新整理KV再return。
快取擊穿
跟快取雪崩有點像,但是又有一點不一樣,快取雪崩是因為大面積的快取失效,打崩了DB,而快取擊穿不同的是快取擊穿是指一個Key非常熱點,在不停地扛著大量的請求,大併發集中對這一個點進行訪問,當這個Key在失效的瞬間,持續的大併發直接落到了資料庫上,就在這個Key的點上擊穿了快取。
解決方案
設定熱點資料永不過期,或者加上互斥鎖就搞定了。Demo:
public static String getData(String key) throws InterruptedException { //從Redis查詢資料 String result = getDataByKV(key); //引數校驗 if (StringUtils.isBlank(result)) { try { //獲得鎖 if (reenLock.tryLock()) { //去資料庫查詢 result = getDataByDB(key); //校驗 if (StringUtils.isNotBlank(result)) { //插進快取 setDataToKV(key, result); } } else { //睡一會再拿 Thread.sleep(100L); result = getData(key); } } finally { //釋放鎖 reenLock.unlock(); } } return result; }
5.Redis為什麼這麼快
Redis是單程序單執行緒的模型,因為Redis完全是基於記憶體的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器記憶體的大小或者網路頻寬。 第一:Redis完全基於記憶體,絕大部分請求是純粹的記憶體操作,非常迅速,資料存在記憶體中,類似於HashMap,HashMap的優勢就是查詢和操作的時間複雜度是O(1)。第二:資料結構簡單,對資料操作也簡單。第三:採用單執行緒,避免了不必要的上下文切換和競爭條件,不存在多執行緒導致的CPU切換,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有死鎖問題導致的效能消耗。第四:使用多路複用IO模型,非阻塞IO。
6.Redis淘汰策略
策略 | 描述 |
---|---|
volatile-lru | 從已設定過期時間的KV集中優先對最近最少使用(less recently used)的資料淘汰 |
volitile-ttl | 從已設定過期時間的KV集中優先對剩餘時間短(time to live)的資料淘汰 |
volitile-random | 從已設定過期時間的KV集中隨機選擇資料淘汰 |
allkeys-lru | 從所有KV集中優先對最近最少使用(less recently used)的資料淘汰 |
allKeys-random | 從所有KV集中隨機選擇資料淘汰 |
noeviction | 不淘汰策略,若超過最大記憶體,返回錯誤資訊 |
補充一下:Redis4.0加入了LFU(least frequency use)淘汰策略,包括volatile-lfu和allkeys-lfu,通過統計訪問頻率,將訪問頻率最少,即最不經常使用的KV淘汰。